k3d for Local Dev & Ephemeral CI Clusters

Spin up throwaway k3s clusters in Docker for CI, import local images, and mirror registries to keep pipelines fast.

k3d runs k3s nodes as Docker containers, which makes it the natural fit for CI: create a real cluster in seconds, run your tests against actual Kubernetes, then delete it — no leftover state.

CI-friendly tricks

  • Import local images with k3d image import so a freshly built image is available without pushing to a registry — great for testing the exact artifact you just built.
  • Wait for readiness: k3d cluster create --wait blocks until the API and add-ons are up, so your pipeline does not race a half-started cluster.
  • Map the loadbalancer port so an Ingress is reachable from the CI runner on a known host port.
  • Register a mirror via --registry-config to pull through a cache and dodge Docker Hub rate limits in CI.

Fidelity

Because k3d runs the same k3s binary, behaviour matches your edge and production nodes closely — far more faithful than a mock. Reserve plain k3s-on-host for real edge/production; use k3d for laptops and pipelines.

Example

Example · bash
# Ephemeral CI cluster, waits until fully ready
k3d cluster create ci --agents 1 --wait \
  --port "8080:80@loadbalancer" \
  --registry-config /etc/rancher/k3s/registries.yaml

# Side-load the image you just built (no registry needed)
docker build -t myapp:ci .
k3d image import myapp:ci -c ci

# Run the test suite, then always clean up
kubectl apply -f k8s/ && ./run-tests.sh
k3d cluster delete ci

When to use it

  • A GitHub Actions workflow creates a k3d cluster at job start, runs Helm chart smoke tests against it, and deletes it on job exit to keep pipelines clean.
  • A developer imports a locally built Docker image into k3d and deploys it with imagePullPolicy Never to test without pushing to any registry.
  • A team configures k3d with a registry mirror pointing to their internal cache so CI pipeline pulls are fast and never rate-limited by Docker Hub.

More examples

Create k3d cluster for CI

Creates a lightweight k3d cluster without a load balancer or Traefik for fast CI startup, then waits for all nodes to be Ready.

Example · bash
k3d cluster create ci-test \
  --agents 1 \
  --no-lb \
  --k3s-arg '--disable=traefik@server:*'
kubectl cluster-info
kubectl wait --for=condition=Ready node --all --timeout=60s

Import local image and deploy

Builds a local image, imports it directly into the k3d cluster's container runtime, and verifies the pod starts correctly.

Example · bash
docker build -t myapp:ci-test .
k3d image import myapp:ci-test -c ci-test
kubectl run myapp --image=myapp:ci-test \
  --image-pull-policy=Never --restart=Never
kubectl wait pod/myapp --for=condition=Ready --timeout=30s

Use k3d with a registry mirror

Creates a k3d-managed registry and configures the cluster to use it as a mirror, enabling fast local image pulls in CI.

Example · bash
k3d registry create my-cache --port 5111
k3d cluster create ci-test \
  --registry-use k3d-my-cache:5111
# Push to the registry and pull in CI:
docker tag myapp:latest k3d-my-cache:5111/myapp:latest
docker push k3d-my-cache:5111/myapp:latest

Discussion

  • Be the first to comment on this lesson.