By Rob

August 28th, 2023


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.

Want to learn more right away?

Check out the Zarf docs.


Before diving into the creation process, let’s understand what Zarf is.Zarf is a deployment tool designed for use in “air-gapped” or offline environments.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.



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


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)


Install Docker on your local machine here

Your app

You could use your own application, but to make things simple, we’ll be using the podinfo application

Yaml file

You will also need a zarf.yaml file at the root of the directory. This acts as the blueprint for your package and also dictates what goes into your package and how it should be configured


This is the command line interface that allows you to interact with your k8s cluster


Firstly, lets begin by creating our local k8s cluster with k3d. Although Zarf does have a component that lets you setup k3s automatically, I prefer to have k3d installed primarly, just to make things a little easier to understand. Go ahead and install k3d with the following command (which is found on

wget -q -O — []( | bash

Once you have k3d installed, lets create our cluster on our local machine. Optionally, if you would like to setup k3d on a remote machine and access it from your local 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

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


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.


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 an 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


Lets create a new zarf.yaml in the root of the podinfo directory. We can 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
        gitPath: charts/podinfo
        namespace: podinfo
        version: 6.3.5
      - ""


We define our Zarf package with the ZarfPackageConfig:

kind: ZarfPackageConfig
  name: podinfo
  description: "Deploys podinfo from git repo"
  architecture: amd64

We then create the component, which is the podinfo app and specify the github repository where it is hosted, as well as the location of the podinfo image. Zarf is designed to make deploying applications in an Airgapped environment super easy. A Zarf package will package up everything required for podinfo to work.


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 podinfo directory, we can create our zarf package with the following command:

zarf package create --confirm

Which 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.


Assuming all has been successfully completed, lets 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... well what are you waiting for? Follow the command prompt and press Y key to deploy.

Keep an extra terminal open and watch the magic happen by executing this command:

watch kubectl get pods -A

The final product in k9s:


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.

Until next time!


What is is a simple website for other software engineers alike. Eventually I hope to post much more professionally developed content.

Why subscribe?

Subscribing means you never miss out on my fun and boring journeys.

© 2023