2.2 kind: Kubernetes in Docker for CI and Testing
Alright, let’s get our hands dirty. If you’re at the point where you need a Kubernetes cluster for testing, CI, or just to bash around in without getting a massive cloud bill, kind is your new best friend. The name stands for “Kubernetes in Docker,” and it does exactly what it says on the tin: it gives you a fully functional K8s cluster running inside Docker containers. It’s not some half-baked mock service; it’s the real kube-apiserver, etcd, and all the other gory bits, just containerized. The beauty is its sheer speed. You can spin up a cluster, wreck it, and nuke it in the time it takes most cloud providers to return an API call.
The first thing you’ll need, obviously, is Docker itself. Don’t come to me with Podman or some other fancy container runtime; kind is built specifically for the Docker API. Make sure it’s running. I’ll wait.
Next, grab the kind binary. The least fussy way is via curl. Pop this in your terminal:
curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.20.0/kind-linux-amd64
chmod +x ./kind
sudo mv ./kind /usr/local/bin/
Check the official docs for the latest version if you’re paranoid. Windows folks, you can do the same in Powershell or just use choco install kind. Yes, it works there too.
Your First Cluster (The Boring, Default Way)
With the binary installed, creating a cluster is almost embarrassingly simple. The default command uses a sensible configuration for a quick start.
kind create cluster
That’s it. No, really. Go get a coffee. By the time you’re back, you’ll have a cluster named kind (see, naming is hard) and your kubectl context will be pointed at it. Verify it with kubectl cluster-info and kubectl get nodes. You’ll see one node, and it will have a role of control-plane. That’s because kind,
in its infinite wisdom, combines the control plane and worker node into a single container by default to save resources. It’s a test cluster, not a production-grade HA setup. Don’t @ me.
Crafting a kind Configuration File
The default is fine for a quick smoke test, but you’ll quickly outgrow it. You need multiple nodes, specific Kubernetes versions, or to mount a host directory for persistence. This is where a config file comes in. kind uses a YAML config that maps almost directly to the cluster resources. Let’s create a more useful cluster.
Create a file named kind-config.yaml:
# kind-config.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
# Map port 80 on the host to port 80 on the control plane node
extraPortMappings:
- containerPort: 80
hostPort: 80
protocol: TCP
- role: worker
- role: worker
Now tell kind to use this blueprint:
kind create cluster --name multi-node --config kind-config.yaml
This gives you a cluster with one control-plane node and two workers, and it helpfully exposes port 80 on your localhost. This is essential for testing things like ingress controllers. You’re not just guessing which port some service got assigned; you’ve defined it upfront.
The Absolute Worst Pitfall: Image Loading
Here’s the part that trips up everyone, and it’s a doozy. Docker doesn’t magically know about the images on your host. If your manifest specifies image: my-app:latest, the kubelet inside the kind node will try to pull it from Docker Hub and fail spectacularly. You have to load your local images into the cluster. It’s a bit of a chore.
Build your image as usual, then use kind to load it into all nodes:
docker build -t my-app:latest .
kind load docker-image my-app:latest --name multi-node
The load command copies the image from your local Docker daemon into each node in the cluster. Yes, it’s a necessary evil. No, there’s no way around it for local images. Forget this step, and you’ll be staring at ImagePullBackOff for hours, questioning all your life choices.
Tearing It All Down
The best part of kind is the destruction. It’s gloriously final.
kind delete cluster --name multi-node
It’s gone. Poof. No leftover volumes, no mysterious security groups, no $300 bill for a cluster you forgot about for a weekend. This is why it’s perfect for CI. Every pipeline run can start with a pristine cluster and nuke it after the tests, completely clean.
So, use it. Abuse it. It’s the fastest, most reliable way to test real Kubernetes without the real-world consequences. Just remember to load your images. Seriously, I can’t stress that enough.