← Back to posts

Getting Started: k3d + Zarf for Local Air-Gap Development

February 8, 2026

quickstart.png

Getting Started: k3d + Zarf for Local Air-Gap Development

Building a local Kubernetes environment that mimics a secure, air-gapped production site is a common challenge for DevSecOps and SREs. Combining k3d (k3s in Docker) with Zarf allows you to test "airplane mode" deployments on your laptop with minimal overhead and high fidelity.

This guide walks you through spinning up a k3d cluster and "initializing" it with Zarf to establish the local registry and agent services.


๐Ÿ—๏ธ 1. Prerequisites

Before starting, ensure you have the following installed on your machine.

  • Docker: The engine that runs your nodes.
  • k3d CLI: To manage the k3s nodes as containers.
  • Zarf CLI: To manage the air-gap packages and cluster initialization.

Installation (Linux/macOS)

Install Docker

# Install Docker (Ubuntu/Debian)
sudo apt update && sudo apt install -y docker.io

# Create docker group and add your user
sudo groupadd docker
sudo usermod -aG docker $USER

# IMPORTANT: Apply the group changes to your current session
newgrp docker 

# Verify you can run docker without sudo
docker ps

Install the Tooling (k3d, kubectl, zarf)

# Install k3d
curl -s https://raw.githubusercontent.com/k3d-io/k3d/main/install.sh | bash

# Install kubectl
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl

# Install Zarf
ZARF_VERSION=$(curl -sIX HEAD https://github.com/zarf-dev/zarf/releases/latest | grep -i ^location: | grep -Eo 'v[0-9]+.[0-9]+.[0-9]+')

curl -sL "https://github.com/zarf-dev/zarf/releases/download/${ZARF_VERSION}/zarf_${ZARF_VERSION}_Linux_amd64" -o zarf
chmod +x zarf
sudo mv zarf /usr/local/bin/zarf

๐Ÿš€ 2. Spin Up the k3d Cluster

Zarf needs a Kubernetes cluster to live in. While Zarf can install k3s directly on Linux, using k3d is the preferred method for local development because it's easy to destroy and recreate.

Run the following command to create a cluster configured for local ingress:

k3d cluster create zarf-dev \
  --agents 1 \
  -p "8080:80@loadbalancer" \
  -p "8443:443@loadbalancer" \
  --k3s-arg "--disable=traefik@server:0"
  • --agents 1: Adds a worker node.
  • -p ...@loadbalancer: Maps host ports 8080/8443 to the cluster.
  • --disable=traefik: Optional. Useful if you plan to let Zarf or Istio manage your ingress later.

Verify connectivity:

kubectl cluster-info


๐Ÿ“ฆ 3. Initialize the Cluster with Zarf

"Initializing" is the most critical step. This deploys the Zarf Agent (a mutating webhook) and a Local Registry into your cluster. This allows Zarf to intercept image pulls and redirect them to the internal registry it manages.

Step 3a: Run the Init Command

Execute the following in your terminal:

zarf init

Step 3b: Configuration Choices

You will see several prompts. For a standard local dev environment:

  1. Download init package? -> y (Zarf will grab the tar.zst for your architecture).
  2. Deploy this Zarf package? -> y.
  3. Deploy the k3s component? -> n.
  4. Deploy the git-server component? -> y (highly recommended for testing GitOps/Flux workflows).

๐Ÿ” 4. Validating the Setup

Once initialization finishes, Zarf will display credentials for the internal registry and Gitea.

To see what is running inside your cluster, use Zarf's built-in dashboard:

kubectl get pods -A
NAMESPACE     NAME                                      READY   STATUS    RESTARTS   AGE
kube-system   coredns-ccb96694c-vb49s                   1/1     Running   0          6m18s
kube-system   local-path-provisioner-5cf85fd84d-dbss8   1/1     Running   0          6m18s
kube-system   metrics-server-5985cbc9d7-k89xt           1/1     Running   0          6m18s
zarf          agent-hook-54674969b5-lgxqf               1/1     Running   0          65s
zarf          agent-hook-54674969b5-qfrt4               1/1     Running   0          65s
zarf          zarf-docker-registry-76f7df8d9b-4grxw     1/1     Running   0          24s
zarf          zarf-docker-registry-76f7df8d9b-5zhv5     1/1     Running   0          73s
zarf          zarf-gitea-5576d96c46-j2qhk               1/1     Running   0          59s

Look for the zarf namespace. You should see:

  • zarf-agent: Watches for new pods and updates image paths.
  • zarf-docker-registry: The internal storage for your container images.
  • zarf-gitea: Your local Git repository for air-gapped code.

๐ŸŽฎ 5. Test Drive: Deploying a Package

To test the "air-gap" flow, deploy one of the built-in examples. This package contains all images and manifests in a single compressed file.

# Create the package (this pulls images from the web into a tarball)
zarf package create https://github.com/zarf-dev/zarf/tree/main/examples/dos-games --confirm

# Deploy the package (this pushes images from the tarball to your k3d registry)
zarf package deploy zarf-package-dos-games-*.tar.zst --confirm

Once deployed, connect to the application:

zarf connect doom


๐Ÿงน 6. Clean Up

To remove everything and reclaim your Docker resources:

# Remove Zarf components from the cluster
zarf destroy --confirm

# Delete the k3d cluster
k3d cluster delete zarf-dev

0

Comments

Sign in to comment and like posts

Sign in with Google