kind: Local Kubernetes in Docker
kind creates a Kubernetes cluster from Docker containers: control-plane and worker nodes are kindest/node images. Primary use cases are local development and CI. GitHub Actions has an official create-kind action that makes pipelines with K8s tests straightforward.
Compared to minikube, kind has no hypervisor dependency and natively supports multi-node topologies. Compared to k3d, it requires no Rancher and talks to CRI/containerd directly.
Installation
macOS, Linux, and Windows (via WSL2) — download the binary from GitHub Releases.
Docker is required (or Podman with kind use docker driver). Make sure Docker has at least 4 GB of memory allocated for all containers.
First Cluster in One Command
kind created a cluster named kind and wrote kubeconfig to ~/.kube/config. Verify:
Done. Single-node cluster is up in a minute.
Config: Multi-node and Runtime
For a cluster with multiple worker nodes, use a YAML config. Let’s create three workers:
Cluster creation flags:
| Flag | Purpose | Example |
|---|---|---|
--name | Cluster name | kind create cluster --name prod |
--config | Path to YAML | --config ./kind.yaml |
--image | Custom node image | --image kindest/node:v1.28.0 |
--wait | Readiness timeout | --wait 5m |
--kubeconfig | Alternative kubeconfig | --kubeconfig ~/.kube/dev |
Instead of --image, you can set node.internalImage in the config — useful for air-gapped environments.
Loading Images into the Cluster
kind uses a separate container runtime inside the node. Images from your local Docker daemon are not visible. To load them:
For CI, you often load from a tar archive:
After loading, the image is available in the cluster without a registry.
extraMounts and kubeadm patches
Mount a host directory into a node — useful for a local registry or fixture files:
Tune kubelet or kube-proxy via kubeadm patches:
If the API server port 6443 is already taken, set another in the cluster config:
kind with kubeconfig
By default, kind merges the context into ~/.kube/config. For isolation:
Managing multiple clusters:
Cleanup
Without --name, the default cluster (kind) is deleted. All Docker resources are removed with the nodes. If Docker was stopped while the cluster was running, nodes remain in NotReady on the next start. Fix by recreating the cluster.
Gotchas
containerd inside the node. kubectl talks to containerd directly. Familiar docker ps and docker exec won’t show pods — they live inside the kind node. For debugging:
HostNetworking and PortMappings. For external access to pods, you need extraPortMappings in the config. Without it, hostPort does not work — pod networking in kind is isolated.
PersistentVolumes. kind creates a kind-node StorageClass backed by local-path-provisioner. Data lives on the host at /var/local-path-provisioner. For a clean environment, just delete the cluster.
cgroups v2. In newer distros (Ubuntu 22.04+, Fedora), Docker may require configuration:
kind works with both versions, but rare issues with memory limits occur with cgroups v2 on Arch Linux. Solution — pass in the config:
Versions. kind lags behind upstream Kubernetes by 1-2 minor versions. Check the compatibility matrix in the project README before setting up a prod-like environment.
Port already allocated. kind could not bind the API server or a mapped host port. Check that 6443 is free, or change networking.apiServerPort. For Ingress, extraPortMappings must not collide with host services.
No space left on device. Docker ran out of disk. Clean unused images, then recreate the cluster:
kind is a fast way to spin up Kubernetes on a developer machine or in CI without virtualization. Main loop: kind create cluster, work, kind delete cluster. For air-gapped or multi-node scenarios — YAML config and kind load docker-image. Known limitations: no GPU support, no real network stack, performance below bare metal. For everything else — it works.