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 offzarf connect
to port-forward to any required UI services
Create a working directory:
mkdir -p zarf-podinfo-demo && cd zarf-podinfo-demo
Create a zarf.yaml
describing the package:
kind: ZarfPackageConfigmetadata: name: podinfo-demo description: Offline demo of podinfo packaged by Zarf version: 1.0.0components: - 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:
replicaCount: 1ui: message: "Hello from Zarf — no internet required!"
Additionally we will create a separate service to enable zarf connect
port-forwarding access
apiVersion: v1kind: Servicemetadata: 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):
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:
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
.
Phase 2 (Once per cluster): Initialize Zarf
Section titled “Phase 2 (Once per cluster): Initialize Zarf”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.
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.
Phase 3 (Disconnected): Deploy the package
Section titled “Phase 3 (Disconnected): Deploy the package”Turn off Wi‑Fi to prove the point. Then deploy:
Prove that the cluster is empty:
kubectl get pods -A
zarf package deploy ./zarf-package-podinfo-demo-amd64-1.0.0.tar.zst --confirm
Watch the pods come up:
kubectl get pods -n demo -w
When podinfo
is Running
, port‑forward and open your browser:
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:
kubectl port-forward -n demo svc/podinfo 9898:9898
Visit http://localhost:9898
— you should see the UI message from values.yaml
.
- Show the package: a single
.tar.zst
file on your desktop. - Toggle airplane mode: visibly disable networking.
zarf package deploy
: audience can see images loading from the in‑cluster registry.- Port‑forward & refresh: open the app UI; call out the custom message.
- 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
zarf package list
Remove the package from the cluster
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? Runzarf 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