Introduction
First of all let’s explain what KinD
is, because maybe you are familiar with Kubernetes but don’t know KinD
yet. As per official documentation:
“KinD is a tool for running local Kubernetes clusters using Docker container nodes.”
KinD
stands for “Kubernetes in Docker” and was primarily designed for testing Kubernetes itself, but it can be also used to do a K8s development or CI as well so it is very useful for PoC implementations and in general playing with K8s things. The official website for KinD
is https://kind.sigs.k8s.io/ and contains a lot of useful information, for instance:
- how to install it (in few ways)
- how to create our own configuration for cluster
- describes known issues you can face with
- and many many more…
Prerequisites
The KinD
tool lets you run a Kubernetes on you machine/server but it requires two related tools:
Docker
to be installed and configured.
I recommend to use the official Docker documentation to perform such installation, because you can choose you Linux distro and just follow the instructions.- Kubernetes command-line tool –
kubectl
– to be installed.
I also recommend to use the official Kubernetes documentation to installkubectl
as you have ready commands that you just copy paste into your terminal and it works!
In my case I’m quite lazy so I create a script that is doing all required things for me (both installing Docker
and kubectl
). File is called kind-prereq.sh
and the content of it is as follows:
#!/bin/bash
### INSTALL DOCKER ###
# Uninstall old versions
for pkg in docker.io docker-doc docker-compose podman-docker containerd runc; do sudo apt-get remove $pkg; done
# Add Docker's official GPG key:
sudo apt-get update
sudo apt-get install ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
# Add the repository to Apt sources:
echo \
"deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
"$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
# Install docker packages
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
# Start and enable service
sudo systemctl enable --now docker
# Add your account to Docker group
sudo usermod -aG docker $USER
DOCKER_VER=`docker version | grep -i "^ Version" | cut -d : -f2 | tr -d " "`
### INSTALL KUBECTL ###
sudo curl -L "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" -o /usr/local/bin/kubectl
sudo chmod +x /usr/local/bin/kubectl
KUBECTL_VER=`kubectl version --client | grep -i "client Version" | cut -d : -f2 | tr -d " "`
### SHOW INSTALATION DETAIL ###
echo
if [[ ! -z "$DOCKER_VER" ]]; then
echo -e "DOCKER ENGINE INSTALLATION \t\t\t\t [ 3[32mSUCCESS3[0m ]"
echo "DOCKER VERSION: $DOCKER_VER"
else
echo -e "DOCKER ENGINE INSTALLATION \t\t\t\t [ 3[31mFAILED3[0m ]"
fi
echo
if [[ ! -z "$KUBECTL_VER" ]]; then
echo -e "KUBECTL INSTALLATION \t\t\t\t\t [ 3[32mSUCCESS3[0m ]"
echo "KUBECTL VERSION: $KUBECTL_VER"
else
echo -e "KUBECTL INSTALLATION \t\t\t\t\t [ 3[31mFAILED3[0m ]"
fi
echo
echo -e "3[33mNote: Please logout of your SSH session and log back in."
echo -e "This is required to take effect of Docker changes that were applied to a user '$USER'3[0m."
echo
Script is doing all steps from the official documentation and is applicable for Ubuntu – so feel free to use it to simplify the Docker
engine and kubectl
tool installation. To execute the script use following command:
# source kind-prereq.sh
After we execute it we need to log off and log in again to make effect of Docker configuration for our user. Please do so and validate if you have no error after execution of command:
# docker ps -a
If you see only headers output similar to this:

It means all is good and now we are ready to install a KinD
.
KinD Installation
Once we have all prerequisites installed, again I encourage you to go to official documentation and install it according the instructions, however you can also use my script to install it as well. It is called kind-install.sh
and content as below:
#!/bin/bash
# Install KinD from Binaries
[ $(uname -m) = x86_64 ] && curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.20.0/kind-linux-amd64
chmod +x ./kind
sudo mv ./kind /usr/local/bin/kind
KIND_VER=`kind version | cut -d " " -f2`
# Increase the ulimit for max_user_watches and max_user_instances
echo fs.inotify.max_user_watches=655360 | sudo tee -a /etc/sysctl.conf
echo fs.inotify.max_user_instances=1280 | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
echo
if [[ ! -z "$KIND_VER" ]]; then
echo -e "KIND INSTALLATION \t\t\t\t\t [ 3[32mSUCCESS3[0m ]"
echo "KIND VERSION: $KIND_VER"
else
echo -e "KIND INSTALLATION \t\t\t\t\t [ 3[31mFAILED3[0m ]"
fi
echo
kind get clusters
echo "Ready to create clusters."
echo
echo "Examples:"
echo -e "\t kind create cluster"
echo -e "\t kind create cluster --name k8s-cluster"
echo -e "\t kind create cluster --image=kindest/node:v1.25.1"
echo -e "\t kind create cluster --config my-cluster.yaml"
echo -e "\t kind create cluster --name k8s-cluster --image=kindest/node:v1.28.0 --config k8s-cluster.yaml"
echo
Script is actually installing a KinD
from binaries and then also list an installed version and give you some basic commands as output to help you build your own cluster. Execute it by typing:
# source kind-install.sh
Now everything is setup and we can start creating a Kubernetes cluster. Running the command:
kind create cluster
will give you a simple, predefined by KinD
Kubernetes cluster, but with default settings. Those default settings are:
- cluster name equal
kind
- one node cluster (control plane node only)
This is a possibility to overwrite some settings, but we need to use specific parameters to do so.
I want to change the cluster name and also I want to have a specific version of my Kubernetes cluster. Then I need to use the following command to get the Kubernetes cluster with a specific version and name:
# kind create cluster --image=kindest/node:v1.28.0 --name dev-cluster
Note that this step will take about few minutes to complete. The output would look like:

Notice that there is only one node in the KinD
cluster (only control plane). You can check this also by executing:
# kubectl get nodes

In my case this cluster configuration is not a perfect one so let’s create some specific cluster config that will be closer to the production Kubernetes clusters. What I mean actually by that? I want to have:
- 3 control plane nodes (to provide HA on K8s mgmt layer)
- 3 worker nodes (to be ready to handle some more workload).
- specific K8s version
- specific name for my cluster
- exposes container ports to the host machine (to access the cluster form outside)
- ingress support (for future exposure)
To do that we need to create a YAML config file. I will create my-cluster.yaml
file with following content:
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: 8081
protocol: TCP
- containerPort: 443
hostPort: 8443
protocol: TCP
- role: control-plane
- role: control-plane
- role: worker
- role: worker
- role: worker
This cluster configuration met all my requirements so it requests KinD
to spin up a Kubernetes cluster comprised of a 3 control plane and 3 worker nodes, supporting ingress to be used in the future, expose cluster to host machine on port 8081 (http) and 8443 (https) – all I want. Of course any additional configuration can be added later on as well, those options are fully customizable and I used only several of them. The one that is quite commonly used is mapping the host mountpoint into container:
nodes:
- role: control-plane
extraMounts:
— hostPath: .
containerPath: /app
A full list of configuration parameters that you can use are available here.
Now let’s create our as if production cluster using custom cluster YAML file:
# kind create cluster --image=kindest/node:v1.28.0 --config my-cluster.yaml --name prod-cluster
As you should see the output is a little bit different, there are some additional tasks like joining other control planes to master one or configuring the external load balancer and preparing nodes contains more items than before. Complete output looks like this:

As you probably noticed I created a second Kubernetes cluster without removing previous one. This is one of the main advantage of a KinD
, so you can have in one host machine multiple clusters that are in specific version (each can be at different K8s version) having different config for control plane and worker nodes and that’s all in one place. Management of this can be also easily done because we have multiple contexts that are created per cluster basis. To list all available contexts run:
# kubectl config get-contexts

And if you want to switch between different cluster contexts you just simply execute:
# kubectl config use-context kind-dev-cluster

That concludes the installation part.
However this is not enough and below you can find some other stuff in terms of supporting KinD
Kuberentes clusters.
SSH into a node
Once we have a running cluster we need to know how to access the nodes. As these nodes are running as Docker
containers, we will have to use the docker
command which we normally use to attach to the containers. First you need to get the container ID:
# docker ps

And then next thing is to login to container using docker exec
command:
# docker exec -it 3f44efa77d17 /bin/sh

As you can see I’m on control plane 2nd node and can do anything I want. Same story if we want do the same on any other node – list docker containers, pick right one we want to operate on and go inside.
Deploying an Application
Last step of dealing with the Kubernetes clusters is to create a simple application that will run on top of our cluster. I will use the kubectl
command-line tool to deploy the nginx application into my KinD prod-cluster
. I will create a deployment definition file that contains the specifics of the application including the service that will expose web server outside. An example web-app.yaml
file you can find below:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
name: nginx
spec:
replicas: 3
selector:
matchLabels:
name: nginx
template:
metadata:
labels:
name: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
name: nginx
spec:
type: NodePort
ports:
- port: 80
nodePort: 30080
name: http
selector:
name: nginx
Create a web application by applying the YAML file:
# kubectl apply -f web-app.yaml
I used NodePort as a service type so I need to find what is the worker node IP:
# kubectl get nodes -o wide

I pick up first worker IP that is 172.18.0.6, and validate if application is up and running in web browser:

Test is successful so deploying the web application is completed.
Delete cluster
To delete a specific cluster just execute:
# kind delete cluster --name dev-cluster

Conclusion
There we are at the end, in this article I have covered how to set up a single and multi-node KinD
cluster, including all prerequisites and installation instructions how to install KinD,
configure the cluster, and deploy an application to the cluster. KinD
is a useful tool for testing and development because it allows us to set up either standalone or multiple local Kubernetes clusters. KinD
allows us to experiment with different configurations and test wide range of applications, making it a valuable tool for any kind of Kubernetes developer. Thanks for reading!