Skip to main content

Creating a Zarf Package


In this tutorial, we will demonstrate the process to create a Zarf package for an application from defining a zarf.yaml, finding resources with zarf prepare commands and finally building the package with zarf package create.

When creating a Zarf package, you must have a network connection so that Zarf 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 Zarf to be able to fetch the resources.

System Requirements

  • You'll need an internet connection so Zarf can pull in anything required to build the package in this tutorial.


Before beginning this tutorial you will need the following:

  • Zarf binary installed on your $PATH: (Installing Zarf)
  • A text editor or development environment such as VS Code

Putting Together a Zarf Package

In order to create a Zarf 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 but the steps and tools used below are very similar for other applications.

Creating the Package Definition

A zarf.yaml file follows the Zarf Package Schema 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 zarf.yaml with the following content:

kind: ZarfPackageConfig # ZarfPackageConfig is the package kind for most normal zarf packages
name: wordpress # specifies the name of our package and should be unique and unchanging through updates
version: 16.0.4 # (optional) a version we can track as we release updates or publish to a registry
description: | # (optional) a human-readable description of the package that you are creating
"A Zarf Package that deploys the WordPress blogging and content management platform"

If you are using an Integrated Development Environment (such as VS Code) to create and edit the zarf.yaml file, you can install or reference the zarf.schema.json file to get error checking and autocomplete. Additionally, you can run zarf prepare lint <directory> to validate aginst the zarf.schema.json

Adding the WordPress Component

Components are the unit of Zarf 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 Zarf Components page. To add our WordPress component, add the following to the bottom of our zarf.yaml:

- name: wordpress # specifies the name of our component and should be unique and unchanging through updates
description: | # (optional) a human-readable description of the component you are defining
"Deploys the Bitnami-packaged WordPress chart into the cluster"
required: true # (optional) sets the component as 'required' so that it is always deployed
- name: wordpress
url: oci://
version: 16.0.4
namespace: wordpress
- wordpress-values.yaml

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 zarf.yaml with the following contents:

# We are hard-coding these for now but will make them dynamic in Setting up Variables.
wordpressUsername: zarf
wordpressPassword: ""
wordpressFirstName: Zarf
wordpressLastName: The Axolotl
wordpressBlogName: The Zarf Blog

# This value turns on the metrics exporter and thus will require another image.
enabled: true

# Sets the WordPress service as a ClusterIP service to not conflict with potential
# pre-existing LoadBalancer services.
type: ClusterIP

We create any values.yaml file(s) at this stage because the zarf prepare find-images command we will use next will template out this chart to look only for the images we need.


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 Zarf 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 Zarf init for more information.

Finding the Images

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, Zarf has a helper command you can run with zarf prepare find-images. Running this command in the directory of your zarf.yaml will result in the following output:

From here you can copy the images key and array of images into the wordpress component we defined in our zarf.yaml


Due to the way some applications are deployed, Zarf 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.


Zarf has more prepare commands you can learn about on the prepare CLI docs page.

Setting up Variables

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 Zarf Blog and a zarf user with an autogenerated password.

To resolve this, we can add configuration options with Zarf Deploy-Time Variables. For this package we will add a variables section to our zarf.yaml above components that will allow us to setup the user and the blog.

# The unique name of the variable corresponding to the ###ZARF_VAR_### template
# A human-readable description of the variable shown during prompting
description: The username that is used to login to the WordPress admin account
# A default value to take if --confirm is used or the user chooses the default prompt
default: zarf
# Whether to prompt for this value interactively if it is not --set on the CLI
prompt: true
description: The password that is used to login to the WordPress admin account
prompt: true
# Whether to treat this value as sensitive to keep it out of Zarf logs
sensitive: true
description: The email that is used for the WordPress admin account
prompt: true
description: The first name that is used for the WordPress admin account
default: Zarf
prompt: true
description: The last name that is used for the WordPress admin account
default: The Axolotl
prompt: true
description: The blog name that is used for the WordPress admin account
default: The Zarf Blog
prompt: true

To use these variables in our chart we must add their corresponding templates to our wordpress-values.yaml file. Zarf can template chart values, manifests, included text files and more.

wordpressUsername: ###ZARF_VAR_WORDPRESS_USERNAME###
wordpressPassword: ###ZARF_VAR_WORDPRESS_PASSWORD###
wordpressEmail: ###ZARF_VAR_WORDPRESS_EMAIL###
wordpressFirstName: ###ZARF_VAR_WORDPRESS_FIRST_NAME###
wordpressLastName: ###ZARF_VAR_WORDPRESS_LAST_NAME###
wordpressBlogName: ###ZARF_VAR_WORDPRESS_BLOG_NAME###

When dealing with sensitive values in Zarf it is strongly recommended to not include them directly inside of a Zarf 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.

Setting up a Zarf Connect Service

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, Zarf allows you to specify Zarf Connect Services that will be displayed after package deployment to quickly connect into our deployed application.

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 Zarf watches out for, and to defined them create a connect-services.yaml with the following contents:

apiVersion: v1
kind: Service
name: wordpress-connect-blog
# Enables "zarf connect wordpress-blog" wordpress-blog
annotations: "The public facing WordPress blog site"
selector: wordpress wordpress
- name: http
port: 8080
protocol: TCP
targetPort: 8080
apiVersion: v1
kind: Service
name: wordpress-connect-admin
# Enables "zarf connect wordpress-admin" wordpress-admin
annotations: "The login page for the WordPress admin panel"
# Sets a URL-suffix to automatically navigate to in the browser "/wp-admin"
selector: wordpress wordpress
- name: http
port: 8080
protocol: TCP
targetPort: 8080

To add this to our zarf.yaml we can simply specify it under our wordpress component using the manifests key:

- name: connect-services
namespace: wordpress
- connect-services.yaml

Creating the Package

Once you have followed the above you should now have a zarf.yaml file that matches the one found on the WordPress example page.

Creating this package is as simple as running the zarf package create command with the directory containing our zarf.yaml. Zarf will show us the zarf.yaml one last time asking if we would like to build the package, and upon confirmation Zarf will pull down all of the resources and bundle them into a package tarball.

zarf package create .

When you execute the zarf package create command, Zarf 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.


You can skip this confirmation by adding the --confirm flag when running the command. This will look like: zarf package create . --confirm

This will create a zarf package in the current directory with a package name that looks something like zarf-package-wordpress-amd64-16.0.4.tar.zst, although it might be slightly different depending on your system architecture.


You can learn more about what is going on behind the scenes of this process on the package create lifecycle page, and can view other useful command flags like --max-package-size, --differential and --registry-override on the package create command flags page.

Congratulations! You've built the WordPress package. Now, you can learn how to inspect the SBOMs or head straight to deploying it!


Unable to read zarf.yaml file


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 zarf.yaml file that you're trying to build.