Create a Local Kubernetes Cluster with kind: Multi-Node, Ingress and Local Images

· 2 min read · Kubernetes Tutorials

What is kind #

kind means "Kubernetes in Docker": each node of the cluster is a Docker container. You get a real multi-node Kubernetes cluster in about a minute, and kind delete cluster removes it with no trace. It is the usual choice to test manifests and Helm charts locally and in CI. Other local options are K3s and Rancher Desktop.

You need Docker running and kubectl.

Install #

curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.24.0/kind-linux-amd64
chmod +x ./kind && sudo mv ./kind /usr/local/bin/kind
kind version

On macOS: brew install kind. Check the releases page for the current version number.

First cluster #

kind create cluster --name lab
kubectl cluster-info --context kind-lab
kubectl get nodes

kind adds the context kind-lab to your kubeconfig and selects it.

Multi-node cluster with exposed ports #

A configuration file defines the nodes and publishes ports of the node to your machine, which is how you reach an ingress controller:

kind-config.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
  - role: control-plane
    kubeadmConfigPatches:
      - |
        kind: InitConfiguration
        nodeRegistration:
          kubeletExtraArgs:
            node-labels: "ingress-ready=true"
    extraPortMappings:
      - containerPort: 80
        hostPort: 8080
        protocol: TCP
      - containerPort: 443
        hostPort: 8443
        protocol: TCP
  - role: worker
  - role: worker
kind delete cluster --name lab
kind create cluster --name lab --config kind-config.yaml
kubectl get nodes

You now have one control plane and two workers, all containers (docker ps shows them).

Deploy an application #

kubectl create deployment web --image=nginx:stable --replicas=3
kubectl expose deployment web --port=80
kubectl get pods -o wide
kubectl port-forward svc/web 8081:80
curl http://localhost:8081

The pods are spread over the two workers. For HTTP routing, install an ingress controller. The ingress-nginx project provides a manifest for kind (see its "kind" deployment guide) that uses the ingress-ready label set above, and then requests to http://localhost:8080 reach your Ingress rules.

Use local images without a registry #

kind nodes cannot see the images in your Docker daemon, so load them:

docker build -t myapp:dev .
kind load docker-image myapp:dev --name lab
kubectl create deployment myapp --image=myapp:dev
kubectl set image deployment/myapp myapp=myapp:dev

Use a specific tag (not latest) and set imagePullPolicy: IfNotPresent, or Kubernetes will try to pull the image from Docker Hub and fail.

Everyday commands #

kind get clusters
kind export logs ./logs --name lab     # debugging information
kind delete cluster --name lab
kubectl config get-contexts

Use kind in CI #

Create the cluster in a job, apply your manifests, run tests, delete it. With GitHub Actions the helm/kind-action action does the setup (GitHub Actions).

Next steps #

Package an app with Kustomize, install charts with Helm and deliver them with Argo CD.

#Kubernetes #Kind #Docker