Dyego Maas - Blog

Generative AI Consultant and Software Architect

Creating a local K8s cluster with Kind

Creating a local K8s cluster with Kind

In this article, I show how to create a Kubernetes cluster for local development using the Kind and ctlptl tools.

5 min read

There are plenty of cases where setting up a local Kubernetes cluster comes in handy. When we’re learning Kubernetes for the first time, for example, running the whole thing locally helps a lot. Or maybe we just want to try out some Kubernetes feature without affecting a production cluster.

Either way, we need to pick a local cluster solution, and there are several to choose from:

Of these options, the only one I’ve never tried is Microk8s. Kind is quite lightweight. Not as lightweight as k3d, but by far much easier to install and configure. In this article we’ll focus on Kind.

Kind

Kind was originally created to test Kubernetes itself. It runs Kubernetes nodes in Docker containers, and it’s useful for local development and even for CI.

Installation

To install Kind, you need Docker and Go installed. The easiest way to install it is by running the following command in the terminal:

go get sigs.k8s.io/kind@v0.10.0

go get will place kind in $GOPATH/bin. You may need to add Kind’s directory to your $Path.

Kind’s documentation lists other ways to install it with package managers, such as Chocolatey on Windows or brew on Mac.

Once it’s installed, we’re ready to create our first cluster.

Creating our first cluster

Creating a new cluster is as easy as running the kind create cluster command:

Screenshot of the installation log, showing the nodes being created, the configuration being written, the control plane starting, and CNI and StorageClass being installed

We can also create other clusters by specifying a name with the kind create cluster --name kind-2 command.

And now we can list our clusters with the kind get clusters command:

Screenshot of the console, showing that the command simply printed kind

Listing the Docker containers with the docker ps command, we can see that Kind started a Kubernetes Control Plane inside a container:

Screenshot of the console, showing that the command simply printed kind

Interacting with a Kind cluster

To interact with a Kind cluster, just pass the cluster name as the context to kubectl:

kubectl cluster-info --context kind-kind
kubectl cluster-info --context kind-kind-2

To deploy an application to the cluster, we first need to load the base image onto the cluster’s nodes with the kind load command.

To load a Docker image, we can use the kind load docker-image my-custom-image command. By default, the image is loaded into every cluster, unless we specify the cluster with the --name <cluster-name> argument.

Alternatively, we can load an image archive all at once with the kind load image-archive /my-image-archive.tar command. These archives can be generated with the docker save [OPTIONS] image [image2...] command.

This enables a workflow like this one:

docker build -t my-custom-image:unique-tag ./my-image-dir
kind load docker-image my-custom-image:unique-tag
kubectl apply -f my-manifest-using-my-image:unique-tag

Working with a local Docker Registry

There are two ways to set up a local Docker registry with Kind. The first is to run a script provided in the documentation:

#!/bin/sh
set -o errexit

# create registry container unless it already exists
reg_name='kind-registry'
reg_port='5000'
running="$(docker inspect -f '{{.State.Running}}' "${reg_name}" 2>/dev/null || true)"
if [ "${running}" != 'true' ]; then
docker run \
  -d --restart=always -p "127.0.0.1:${reg_port}:5000" --name "${reg_name}" \
  registry:2
fi

# create a cluster with the local registry enabled in containerd
cat <<EOF | kind create cluster --config=-
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
containerdConfigPatches:
- |-
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."localhost:${reg_port}"]
  endpoint = ["http://${reg_name}:${reg_port}"]
EOF

# connect the registry to the cluster network
# (the network may already be connected)
docker network connect "kind" "${reg_name}" || true

# Document the local registry
# https://github.com/kubernetes/enhancements/tree/master/keps/sig-cluster-lifecycle/generic/1755-communicating-a-local-registry
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ConfigMap
metadata:
name: local-registry-hosting
namespace: kube-public
data:
localRegistryHosting.v1: |
  host: "localhost:${reg_port}"
  help: "https://kind.sigs.k8s.io/docs/user/local-registry/"
EOF

An easier way is to use the ctlptl tool.

ctlptl

ctlptl (pronounced “cattle paddle”) is a CLI built by the Tilt team to make setting up local clusters easier. It works with Kind, Docker for Desktop and Minikube.

It can be installed on Linux and Mac with Homebrew:

brew install tilt-dev/tap/ctlptl

And on Windows with Scoop:

scoop bucket add tilt-dev https://github.com/tilt-dev/scoop-bucket
scoop install ctlptl

Once it’s installed, we can use it to create a Kind cluster:

ctlptl create cluster kind

Or better yet, a cluster with a Docker registry already configured:

ctlptl create cluster kind --registry=ctlptl-registry
Command output in the console

As the image above shows, on top of creating the cluster, ctlptl also created a Docker registry and printed instructions on how to use it at the end.

The registry was created along the same lines as the script above, except that ctlptl automatically picks an available port for the registry.

docker ps lists two running containers: the control plane and the registry

Now we can list the clusters through ctlptl and check that the cluster and the registry are linked:

ctlptl get clusters
The command lists the cluster name along with the Docker registry's IP

And now the Kind cluster is ready to use.

If we want to delete the cluster, that’s easy to do with the ctlptl delete cluster cluster-name command.