github.com/Racer159/jackal@v0.32.7-0.20240401174413-0bd2339e4f2e/docs/5-jackal-tutorials/0-creating-a-jackal-package.md (about)

     1  # Creating a Jackal Package
     2  
     3  ## Introduction
     4  
     5  In this tutorial, we will demonstrate the process to create a Jackal package for an application from defining a `jackal.yaml`, finding resources with `jackal dev` commands and finally building the package with `jackal package create`.
     6  
     7  When creating a Jackal package, you must have a network connection so that Jackal can fetch all of the dependencies and resources necessary to build the package. If your package is using images from a private registry or is referencing repositories in a private repository, you will need to have your credentials configured on your machine for Jackal to be able to fetch the resources.
     8  
     9  ## System Requirements
    10  
    11  - You'll need an internet connection so Jackal can pull in anything required to build the package in this tutorial.
    12  
    13  ## Prerequisites
    14  
    15  Before beginning this tutorial you will need the following:
    16  
    17  - Jackal binary installed on your $PATH: ([Installing Jackal](../1-getting-started/index.md#installing-jackal))
    18  - A text editor or development environment such as [VS Code](../3-create-a-jackal-package/8-vscode.md)
    19  
    20  ## Putting Together a Jackal Package
    21  
    22  In order to create a Jackal package you first need to have an idea of what application(s) you want to package.  In this example we will be using the [WordPress chart from Bitnami](https://artifacthub.io/packages/helm/bitnami/wordpress) but the steps and tools used below are very similar for other applications.
    23  
    24  ### Creating the Package Definition
    25  
    26  A `jackal.yaml` file follows the [Jackal Package Schema](../3-create-a-jackal-package/4-jackal-schema.md) and allows us to specify package metadata and a set of components for us to deploy. We start a package definition with the `kind` of package we are making and `metadata` that describes the package.  You can start our WordPress package by creating a new `jackal.yaml` with the following content:
    27  
    28  ```yaml
    29  kind: JackalPackageConfig # JackalPackageConfig is the package kind for most normal jackal packages
    30  metadata:
    31    name: wordpress       # specifies the name of our package and should be unique and unchanging through updates
    32    version: 16.0.4       # (optional) a version we can track as we release updates or publish to a registry
    33    description: |        # (optional) a human-readable description of the package that you are creating
    34      "A Jackal Package that deploys the WordPress blogging and content management platform"
    35  ```
    36  
    37  :::tip
    38  
    39  If you are using an Integrated Development Environment (such as [VS Code](../3-create-a-jackal-package/8-vscode.md)) to create and edit the `jackal.yaml` file, you can install or reference the [`jackal.schema.json`](https://github.com/Racer159/jackal/blob/main/jackal.schema.json) file to get error checking and autocomplete.
    40  Additionally, you can run `jackal dev lint <directory>` to validate against the [`jackal.schema.json`](https://github.com/Racer159/jackal/blob/main/jackal.schema.json)
    41  
    42  :::
    43  
    44  ### Adding the WordPress Component
    45  
    46  Components are the unit of Jackal Packages that define an application stack.  These are defined under the `components` key and allow many different resource types to be brought into a package.  You can learn more about components on the [Understanding Jackal Components](../3-create-a-jackal-package/2-jackal-components.md) page. To add our WordPress component, add the following to the bottom of our `jackal.yaml`:
    47  
    48  ```yaml
    49  components:
    50    - name: wordpress  # specifies the name of our component and should be unique and unchanging through updates
    51      description: |   # (optional) a human-readable description of the component you are defining
    52        "Deploys the Bitnami-packaged WordPress chart into the cluster"
    53      required: true   # (optional) sets the component as 'required' so that it is always deployed
    54      charts:
    55        - name: wordpress
    56          url: oci://registry-1.docker.io/bitnamicharts/wordpress
    57          version: 16.0.4
    58          namespace: wordpress
    59          valuesFiles:
    60            - wordpress-values.yaml
    61  ```
    62  
    63  In addition to this component definition, we also need to create the `valuesFiles` we have specified.  In this case we need to create a file named `wordpress-values.yaml` in the same directory as our `jackal.yaml` with the following contents:
    64  
    65  ```yaml
    66  # We are hard-coding these for now but will make them dynamic in Setting up Variables.
    67  wordpressUsername: jackal
    68  wordpressPassword: ""
    69  wordpressEmail: hello@defenseunicorns.com
    70  wordpressFirstName: Jackal
    71  wordpressLastName: The Axolotl
    72  wordpressBlogName: The Jackal Blog
    73  
    74  # This value turns on the metrics exporter and thus will require another image.
    75  metrics:
    76    enabled: true
    77  
    78  # Sets the WordPress service as a ClusterIP service to not conflict with potential
    79  # pre-existing LoadBalancer services.
    80  service:
    81    type: ClusterIP
    82  ```
    83  
    84  :::note
    85  
    86  We create any `values.yaml` file(s) at this stage because the `jackal dev find-images` command we will use next will template out this chart to look only for the images we need.
    87  
    88  :::
    89  
    90  :::caution
    91  
    92  Note that we are explicitly defining the `wordpress` namespace for this deployment, this is strongly recommended to separate out the applications you deploy and to avoid issues with the Jackal Agent not being able to mutate your resources as it intentionally ignores resources in the `default` or `kube-system` namespaces.  See [what happens to resources that exist before Jackal init](../8-faq.md#what-happens-to-resources-that-exist-in-the-cluster-before-jackal-init) for more information.
    93  
    94  :::
    95  
    96  ### Finding the Images
    97  
    98  Once you have the above defined we can now work on setting the images that we will need to bring with us into the air gap.  For this, Jackal has a helper command you can run with `jackal dev find-images`.  Running this command in the directory of your jackal.yaml will result in the following output:
    99  
   100  <iframe src="/docs/tutorials/prepare_find_images.html" height="220px" width="100%"></iframe>
   101  
   102  From here you can copy the `images` key and array of images into the `wordpress` component we defined in our `jackal.yaml`
   103  
   104  :::note
   105  
   106  Due to the way some applications are deployed, Jackal might not be able to find all of the images in this way (particularly with operators).  For this you can look at the upstream charts or manifests and find them manually.
   107  
   108  :::
   109  
   110  :::tip
   111  
   112  Jackal has more `dev` commands you can learn about on the [dev CLI docs page](../3-create-a-jackal-package/10-dev.md).
   113  
   114  :::
   115  
   116  ### Setting up Variables
   117  
   118  We now have a deployable package definition, but it is currently not very configurable and might not fit every environment we want to deploy it to.  If we deployed it as-is we would always have a Jackal Blog and a `jackal` user with an autogenerated password.
   119  
   120  To resolve this, we can add configuration options with [Jackal Deploy-Time Variables](../../examples/variables/README.md#deploy-time-variables-and-constants).  For this package we will add a `variables` section to our `jackal.yaml` above `components` that will allow us to setup the user and the blog.
   121  
   122  ```yaml
   123  variables:
   124      # The unique name of the variable corresponding to the ###JACKAL_VAR_### template
   125    - name: WORDPRESS_USERNAME
   126      # A human-readable description of the variable shown during prompting
   127      description: The username that is used to login to the WordPress admin account
   128      # A default value to take if --confirm is used or the user chooses the default prompt
   129      default: jackal
   130      # Whether to prompt for this value interactively if it is not --set on the CLI
   131      prompt: true
   132    - name: WORDPRESS_PASSWORD
   133      description: The password that is used to login to the WordPress admin account
   134      prompt: true
   135      # Whether to treat this value as sensitive to keep it out of Jackal logs
   136      sensitive: true
   137    - name: WORDPRESS_EMAIL
   138      description: The email that is used for the WordPress admin account
   139      default: hello@defenseunicorns.com
   140      prompt: true
   141    - name: WORDPRESS_FIRST_NAME
   142      description: The first name that is used for the WordPress admin account
   143      default: Jackal
   144      prompt: true
   145    - name: WORDPRESS_LAST_NAME
   146      description: The last name that is used for the WordPress admin account
   147      default: The Axolotl
   148      prompt: true
   149    - name: WORDPRESS_BLOG_NAME
   150      description: The blog name that is used for the WordPress admin account
   151      default: The Jackal Blog
   152      prompt: true
   153  ```
   154  
   155  To use these variables in our chart we must add their corresponding templates to our `wordpress-values.yaml` file.  Jackal can template chart values, manifests, included text files and more.
   156  
   157  ```yaml
   158  wordpressUsername: ###JACKAL_VAR_WORDPRESS_USERNAME###
   159  wordpressPassword: ###JACKAL_VAR_WORDPRESS_PASSWORD###
   160  wordpressEmail: ###JACKAL_VAR_WORDPRESS_EMAIL###
   161  wordpressFirstName: ###JACKAL_VAR_WORDPRESS_FIRST_NAME###
   162  wordpressLastName: ###JACKAL_VAR_WORDPRESS_LAST_NAME###
   163  wordpressBlogName: ###JACKAL_VAR_WORDPRESS_BLOG_NAME###
   164  ```
   165  
   166  :::caution
   167  
   168  When dealing with `sensitive` values in Jackal it is strongly recommended to not include them directly inside of a Jackal Package and to only define them at deploy-time.  You should also be aware of where you are using these values as they may be printed in `actions` you create or `files` that you place on disk.
   169  
   170  :::
   171  
   172  ### Setting up a Jackal Connect Service
   173  
   174  As-is, our package could be configured to interface with an ingress provider to provide access to our blog, but this may not be desired for every service, particularly those that provide a backend for other frontend services.  To help with debugging, Jackal allows you to specify Jackal Connect Services that will be displayed after package deployment to quickly connect into our deployed application.
   175  
   176  For this package we will define two services, one for the blog and the other for the admin panel.  These are normal Kubernetes services with special labels and annotations that Jackal watches out for, and to defined them create a `connect-services.yaml` with the following contents:
   177  
   178  ```yaml
   179  apiVersion: v1
   180  kind: Service
   181  metadata:
   182    name: wordpress-connect-blog
   183    labels:
   184      # Enables "jackal connect wordpress-blog"
   185      jackal.dev/connect-name: wordpress-blog
   186    annotations:
   187      jackal.dev/connect-description: "The public facing WordPress blog site"
   188  spec:
   189    selector:
   190      app.kubernetes.io/instance: wordpress
   191      app.kubernetes.io/name: wordpress
   192    ports:
   193      - name: http
   194        port: 8080
   195        protocol: TCP
   196        targetPort: 8080
   197  ---
   198  apiVersion: v1
   199  kind: Service
   200  metadata:
   201    name: wordpress-connect-admin
   202    labels:
   203      # Enables "jackal connect wordpress-admin"
   204      jackal.dev/connect-name: wordpress-admin
   205    annotations:
   206      jackal.dev/connect-description: "The login page for the WordPress admin panel"
   207      # Sets a URL-suffix to automatically navigate to in the browser
   208      jackal.dev/connect-url: "/wp-admin"
   209  spec:
   210    selector:
   211      app.kubernetes.io/instance: wordpress
   212      app.kubernetes.io/name: wordpress
   213    ports:
   214      - name: http
   215        port: 8080
   216        protocol: TCP
   217        targetPort: 8080
   218  ```
   219  
   220  To add this to our `jackal.yaml` we can simply specify it under our `wordpress` component using the `manifests` key:
   221  
   222  ```yaml
   223      manifests:
   224        - name: connect-services
   225          namespace: wordpress
   226          files:
   227            - connect-services.yaml
   228  ```
   229  
   230  ### Creating the Package
   231  
   232  Once you have followed the above you should now have a `jackal.yaml` file that matches the one found on the [WordPress example page](../../examples/wordpress/README.md).
   233  
   234  Creating this package is as simple as running the `jackal package create` command with the directory containing our `jackal.yaml`.  Jackal will show us the `jackal.yaml` one last time asking if we would like to build the package, and upon confirmation Jackal will pull down all of the resources and bundle them into a package tarball.
   235  
   236  ```bash
   237  jackal package create .
   238  ```
   239  
   240  When you execute the `jackal package create` command, Jackal will prompt you to confirm that you want to create the package by displaying the package definition and asking you to respond with either `y` or `n`.
   241  
   242  <iframe src="/docs/tutorials/package_create_wordpress.html" height="500px" width="100%"></iframe>
   243  
   244  :::tip
   245  
   246  You can skip this confirmation by adding the `--confirm` flag when running the command. This will look like: `jackal package create . --confirm`
   247  
   248  :::
   249  
   250  This will create a jackal package in the current directory with a package name that looks something like `jackal-package-wordpress-amd64-16.0.4.tar.zst`, although it might be slightly different depending on your system architecture.
   251  
   252  :::tip
   253  
   254  You can learn more about what is going on behind the scenes of this process on the [package create lifecycle page](../3-create-a-jackal-package/5-package-create-lifecycle.md), and can view other useful command flags like `--max-package-size`, `--differential` and `--registry-override` on the [package create command flags page](../2-the-jackal-cli/100-cli-commands/jackal_package_create.md).
   255  
   256  :::
   257  
   258  Congratulations! You've built the WordPress package. Now, you can learn how to [inspect the SBOMs](../4-deploy-a-jackal-package/4-view-sboms.md) or head straight to [deploying it](./2-deploying-jackal-packages.md)!
   259  
   260  ## Troubleshooting
   261  
   262  ### Unable to read jackal.yaml file
   263  
   264  <iframe src="/docs/tutorials/package_create_error.html" height="120px" width="100%"></iframe>
   265  
   266  :::info Remediation
   267  
   268  If you receive this error, you may not be in the correct directory. Double-check where you are in your system and try again once you're in the correct directory with the jackal.yaml file that you're trying to build.
   269  
   270  :::