A Comprehensive Guide to Creating a Zarf Package

Zarf packages are growing in popularity as they offer an efficient and secure method of deploying applications on air-gapped environments. But creating one can seem like a daunting task for those new to the concept. So, let’s break it down and walk through the process of creating a Zarf package step-by-step.

For more information, take some time and read through the Zarf docs to better familiarize yourself with Zarf.

Grasping Zarf

Before diving into the creation process, let’s understand what Zarf is. When we install applications into Kubernetes, we use a number of different “YAML” files to deploy different components and applications. After that, we have Helm, which made this process even simpler. Zarf takes that several steps further by packaging all of a specific Helm chart’s dependencies into a simple archive, which can be deployed to any cluster, even “air-gapped”. It allows you to package software, configuration files, deployment scripts, and all other necessary components into one package. This Zarf package can then be moved onto your air-gapped system for deployment.


  • Zarf CLI: This is the command-line tool for creating and managing Zarf packages. It can be built from scratch or installed with Homebrew (macOS/Linux). Read more here: Zarf CLI Documentation
  • K3D: K3D allows us to run a very simple and yet powerful Kubernetes cluster on your local machine (although you could also run K3D on an EC2 instance or any supported machine).
  • Docker: Install Docker on your local machine here: Docker Installation Documentation
  • Your App: You could use your own application, but to make things simpler, we’ll be using the podinfo application. Remember, Zarf is all about packaging helm charts, so make sure your application is indeed a helm chart.
  • YAML file: You will also need a Zarf.yaml file at the root of your application directory. This acts as the blueprint for your package and also dictates what goes into your package and how it should be configured.
  • Kubectl: This is the command line interface that allows you to interact with your k8s cluster.


Firstly, let’s begin by creating our local k8s cluster with K3D. Although Zarf does have a component that lets you set up k3s automatically, I prefer to have K3D installed primarily, just to make things a little easier to understand. Go ahead and install K3D with the following command (found on K3D Documentation):

wget -q -O - https://raw.githubusercontent.com/k3d-io/k3d/main/install.sh | bash

Once you have K3D installed, let’s create our cluster on our local machine. Optionally, if you would like to set up K3D on a remote machine and access it from your local machine, you can set SERVER_IP="" prior to running your K3D cluster create command:

mkdir -p ${IMAGE_CACHE}

After setting the IMAGE_CACHE, you can begin by creating your local k8s cluster with the following command:

k3d cluster create 
--k3s-arg "--tls-san=$SERVER_IP@server:0" 
--volume /etc/machine-id:/etc/machine-id 
--volume ${IMAGE_CACHE}:/var/lib/rancher/k3s/agent/containerd/io.containerd.content.v1.content 
--k3s-arg "--disable=traefik@server:0" 
--port 80:80@loadbalancer 
--port 443:443@loadbalancer 
--api-port 6443

Step-by-Step Setup Using Zarf

If you haven’t done so, you’ll need to clone podinfo. Let’s navigate to our podinfo directory that we cloned from GitHub, and then we can begin working on the Zarf package.

Zarf Init

We must initiate Zarf onto the Kubernetes (k8s) cluster that we have created. You can decline to use K3S, Gitea, and Logging components by pressing the N key when prompted. Since we already have K3D, we do not need the k3s component (Zarf will spin up a k3d cluster for you if this option is selected).


Podinfo is a simple test application written in Go that can be used in a k8s environment. It gives us info about a Kubernetes pod that is running. By the end of the tutorial, you’ll be able to check the following items within an air-gapped environment:

/ : Displays a simple homepage
/version : Displays the version of podinfo that's running
/env : Shows all environment variables
/headers : Shows HTTP request headers
/metrics : Provides Prometheus-compatible metrics
/healthz : Can be used for Kubernetes liveness probes
/readyz : Can be used for Kubernetes readiness probes

Zarf Package

Let’s create a new zarf.yaml in the root of the podinfo directory (You can clone podinfo from here). We can then set it up and define it as displayed in the example below:

kind: ZarfPackageConfig
  name: podinfo
  description: "Deploys podinfo from git repo"
  architecture: amd64
  - name: podinfo
    required: true
      - name: podinfo
        url: https://github.com/stefanprodan/podinfo.git
        gitPath: charts/podinfo
        namespace: podinfo
        version: 6.3.5
      - "ghcr.io/stefanprodan/podinfo:6.3.5"

If you actually look at the repository link, https://github.com/stefanprodan/podinfo.git, you will see a bunch of different files and configurations, but most importantly is the charts/podinfo which is where the helm chart is located. This is where the magic happens with Zarf. As discussed earlier, Zarf will package everything into an archive which can then be deployed into your Kubernetes cluster.

Creating a Zarf Package

If you are running on macOS with the M1 chip, you can specify arm64 as the architecture, otherwise amd64 will work just fine on Linux or Ubuntu. Now that you have defined your zarf.yaml in the root of the podinfo directory, we can create our Zarf package with the following command:

zarf package create --confirm

This will create and produce your Zarf package with the name zarf-package-podinfo-amd64.tar.zst. We can now get started deploying our Zarf package.

Deploying a Zarf Package

Assuming all has been successfully completed, let’s deploy our podinfo Zarf package. Run the following command:

zarf package deploy zarf-package-podinfo-amd64.tar.zst

You’ll be prompted if you would like to deploy the package. Follow the command prompt and press the Y key to deploy. Keep an extra terminal open and watch the magic happen by executing this command:

watch kubectl get pods -A


Finally, to view the podinfo frontend, we can forward the port with zarf connect podinfo or kubectl port-forward svc/podinfo -n podinfo 9898:http and navigate to http://localhost:9898/ to see what podinfo is doing.

So there you have it, you can see the power of Zarf and how easy it can be to deploy your applications into an air-gapped environment with minimal configuration time. For further reading, check out the Zarf docs to get a more in-depth understanding of Zarf and Zarf packages.

Got more questions? Discuss in the comments!