kind create cluster: Ephemeral Clusters in CI
kind create cluster runs a full Kubernetes cluster inside Docker containers, ready in under a minute for ephemeral CI testing.
kind (Kubernetes IN Docker) gives a real API server and nodes as containers, perfect for integration tests that need an actual cluster and tear down clean.
What it does
kind create cluster boots a control plane (and optional worker nodes) as Docker containers, writes a kubeconfig context named kind-<name>, and waits for the API server. A --config file defines node count, port mappings, and feature gates.
Common usage
kind create cluster --name ci
kind create cluster --name ci --config kind.yaml --wait 120s
kind create cluster --image kindest/node:v1.29.2
kubectl cluster-info --context kind-ciOptions
| Flag | What it does |
|---|---|
| --name | Cluster name (context becomes kind-<name>) |
| --config | Cluster config YAML (nodes, ports, gates) |
| --image | Node image, pinning the Kubernetes version |
| --wait | Wait up to a duration for the control plane |
| --kubeconfig | Write kubeconfig to a specific path |
| --retain | Keep containers on failure for debugging |
In CI
Pin --image kindest/node:vX.Y.Z so the Kubernetes version is reproducible. Add --wait 120s so the next step does not race the API server. On GitHub-hosted runners Docker is already present; create the cluster, run tests, then kind delete cluster --name ci.
Common errors in CI
ERROR: failed to create cluster: ... Cannot connect to the Docker daemon means Docker is not running or the socket is unavailable. failed to create cluster: node(s) already exist for a cluster with the name "ci" means a leftover cluster; delete it first. failed to init node with kubeadm ... timed out on small runners is usually too little memory; reduce nodes or raise resources.
Using this in CI
A runner has no kubeconfig, no cached context, and no interactive auth. Every kubectl invocation in CI needs the context supplied explicitly, and most confusing CI failures here are the command running against the wrong cluster or no cluster at all.
# never rely on the ambient context on a runner
kubectl --context "$KUBE_CONTEXT" -n "$NAMESPACE" get pods
# confirm what you are actually connected to before mutating anything
kubectl config current-context
kubectl cluster-info
# fail fast instead of hanging on an unreachable API server
kubectl --request-timeout=30s get nodes