Skip to content

Offline Live Demos with Zarf

Event Wi‑Fi is unpredictable. DNS breaks, captive portals intervene, and even a tiny image pull can stall a talk. That’s why some events recommend avoiding live demos entirely.

Zarf takes the opposite stance: live demos should be reliable. Zarf packages everything your demo needs — Helm charts, container images, manifests, and supporting assets — into a single, portable file. You build the package ahead of time on a connected machine, then deploy it on stage with networking disabled. No public registries. No Helm repos. No “hold on, it’s pulling an image.”

What you’ll learn

  • Construct a fully self‑contained Zarf package
  • Prove a demo runs with zero external connectivity
  • Reuse the same package for workshops, trainings, and airgapped environments

  • A Kubernetes cluster you control (kind, k3d, k3s, minikube, or any conformant cluster)
  • Zarf installed on your build machine and on the demo machine

⚠️ One‑time cluster prep: Zarf uses an internal registry and optional git service managed in‑cluster. Run zarf init once per cluster before deploying packages (details below).


We’ll package the popular sample app podinfo. The result is a single file like zarf-package-podinfo-demo-<version>-amd64.tar.zst.

Before you take the stage, you’ll:

  • Ensure the cluster is running
  • (If not already done) zarf init

Once you take the stage:

  • zarf package deploy the file — with Wi‑Fi off
  • zarf connect to port-forward to any required UI services

Create a working directory:

Terminal window
mkdir -p zarf-podinfo-demo && cd zarf-podinfo-demo

Create a zarf.yaml describing the package:

zarf.yaml
kind: ZarfPackageConfig
metadata:
name: podinfo-demo
description: Offline demo of podinfo packaged by Zarf
version: 1.0.0
components:
- name: podinfo
description: Deploy podinfo via Helm, completely offline
required: true
charts:
- name: podinfo
version: 6.9.1
namespace: demo
releaseName: podinfo
url: oci://ghcr.io/stefanprodan/charts/podinfo
valuesFiles:
- values.yaml
# Explicitly list images so they are pulled into the package
images:
- ghcr.io/stefanprodan/podinfo:6.9.1
manifests:
- name: connect-service
namespace: demo
files:
- connect-service.yaml

Create a minimal values.yaml to customize the demo:

values.yaml
replicaCount: 1
ui:
message: "Hello from Zarf — no internet required!"

Additionally we will create a separate service to enable zarf connect port-forwarding access

connect-service.yaml
apiVersion: v1
kind: Service
metadata:
name: podinfo-connect
labels:
# Enables "zarf connect podinfo-demo"
zarf.dev/connect-name: podinfo-demo
annotations:
zarf.dev/connect-description: "The podinfo UI service"
spec:
selector:
app.kubernetes.io/name: podinfo
ports:
- name: http
port: 9898
protocol: TCP
targetPort: 9898

💡 The chart and image versions don’t have to match numerically, but must exist. Pin them to an exact version you’ve tested to ensure reproducibility.

Identify the architecture you plan to deploy to on-stage. If you are building the package on a connected system that happens to be an amd64 architecture but plan to use arm64 you can pass -a/--architecture with the architecture you want the package to run on.

Now create the package (this step downloads artifacts and embeds them):

Terminal window
zarf package create .

You should now have a file similar to:

zarf-package-podinfo-demo-amd64-1.0.0.tar.zst

Optionally verify what’s inside:

Terminal window
zarf package inspect definition zarf-package-podinfo-demo-amd64-1.0.0.tar.zst

Copy the package file to your demo laptop (USB, etc.) or optionally publish it to a public registry such as ghcr.io.


On the demo machine with the target cluster running, initialize Zarf. This installs the Zarf system components (including the internal registry) into the cluster so deployments can load packaged images without the public internet.

Terminal window
zarf tools download-init && zarf init --confirm

✅ Do this only once per cluster. For fresh ephemeral clusters (kind/k3d/minikube), run it after the cluster is created.


Turn off Wi‑Fi to prove the point. Then deploy:

Prove that the cluster is empty:

Terminal window
kubectl get pods -A
Terminal window
zarf package deploy ./zarf-package-podinfo-demo-amd64-1.0.0.tar.zst --confirm

Watch the pods come up:

Terminal window
kubectl get pods -n demo -w

When podinfo is Running, port‑forward and open your browser:

Terminal window
zarf connect podinfo-demo --local-port 9898

Note: --local-port specifies the local port to bind to. If you forgo this flag a random port will be assigned.

This is the same as:

Terminal window
kubectl port-forward -n demo svc/podinfo 9898:9898

Visit http://localhost:9898 — you should see the UI message from values.yaml.


  1. Show the package: a single .tar.zst file on your desktop.
  2. Toggle airplane mode: visibly disable networking.
  3. zarf package deploy: audience can see images loading from the in‑cluster registry.
  4. Port‑forward & refresh: open the app UI; call out the custom message.
  5. Q&A: highlight that Helm and image pulls were satisfied locally; no external registries or repos were contacted.

When you’re done:

Locate the package

Terminal window
zarf package list

Remove the package from the cluster

Terminal window
zarf package remove podinfo-demo --confirm

If your talk uses a throwaway cluster, you can also delete the cluster entirely and skip zarf package remove.


  • Image not found during create: double‑check images: tags exist and are reachable from the build machine.
    • Ensure the image packaged (including the repository) is the exact reference used in the manifests/helm charts.
  • Chart fetch fails during create: verify the OCI URL and chart version. Zarf vendors the chart into the package; it will not contact the chart repo at deploy time.
  • No pods after deploy: did you run zarf init on this cluster? Run zarf init --confirm once, then redeploy.

  • Workshops: Publish the package to a registry such as ghcr.io and/or a local network registry for offline retrieval.
  • Multiple apps: add more components to the same zarf.yaml (each with charts/images) to build a single multi‑app demo package.

  • zarf package create succeeds on a connected build machine
  • zarf package inspect lists the expected images and the podinfo chart
  • Package file copied to demo machine
  • Demo cluster created and zarf init --confirm has been run once
  • Optional: test deploy with Wi‑Fi off ahead of the talk

Reach out to the Zarf community on the Kubernetes/OpenSSF Slack at #zarf