Containers and Virtualization Kind Multinode K8s Distro Lead image: Lead Image © Kirsty Pargeter, Fotolia.com
Lead Image © Kirsty Pargeter, Fotolia.com
 

Run Kubernetes in a container with Kind

One of a Kind

Create a full-blown Kubernetes cluster in a Docker container with just one command. By Chris Binnie

Not often are you compelled to test unfamiliar software in the time it takes to read just a few lines on its website. Of course, the software has to be extremely accessible to allow you to get started quickly. An interesting application that recently fell into this category is Kind [1], a multinode Kubernetes distribution that is quick to install and configure for testing. The reason Kind was so intriguing is that it uses Docker containers for its nodes. Think about that for a minute and consider how versatile such an approach would be for quick testing. The clever Kind manages to squeeze a Kubernetes cluster inside containers.

In this article, I look at creating a freshly built Kind cluster installation to show off the infrastructure created by Kind. You will see how one container runs an entire node – in this case, the control plane and master node.

Thank You, Kindly

Some really well constructed documentation about the Kind installation can be found as a Quick Start page online [2]. You should be the root user or prepend your commands with sudo for most of the commands that follow. If needed, install Docker CE first [3] (choosing the correct Operating System for your needs).

To begin, install kubectl so you can interact with your Kubernetes cluster in a coherent way. The Kind documentation points you to a page online if you get stuck [4]. In my case, I just needed to run the following commands to download the binary file, check that it was safe, and download and check the checksum file:

$ curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
$ curl -LO "https://dl.k8s.io/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl.sha256"
$ echo "$(<kubectl.sha256) kubectl" | sha256sum --check

If the output from the kubectl command is kubectl: OK, move the binary into a directory in your path, set the permissions on the binary if you only want root user access (skip this command if you've downloaded it into the /root directory), and allow other non-root users to run the binary:

$ mv kubectl /usr/local/bin
$ chown root:root /usr/local/bin/kubectl
$ chmod 0755 /usr/local/bin/kubectl

If you are using a Debian derivative and want to use the package manager to install kubectl, start with the commands:

$ apt-get update
$ apt-get install -y apt-transport-https ca-certificates curl
$ curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg \ https://packages.cloud.google.com/apt/doc/apt-key.gpg

which will also add the repository key (ideally as one line). Check the documentation for Red Hat Enterprise Linux derivatives. In the /etc/apt/sources.list.d/kubernetes.list file, add the single line without splitting it up:

deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main

Note that you might need to change xenial to match your Linux distribution name. Finally, install kubectl after refreshing the sources:

$ apt-get update
$ apt-get install -y kubectl

Whichever route you take, once installed, test that you can use the command:

$ kubectl version
...
Client Version: version.Info{Major:"1", Minor:"21", GitVersion:"v1.21.1"
...

The quick output is welcome. You can proceed if your result looks like the (abbreviated) output shown.

Be Kind To One Another

The next stage is of course installing Kind. Options include a Go module or downloading the source and running make build. You're advised to use the latest Go version if you do so. Check the documentation for more pointers about how to get started.

In this example, I download a binary, move it to the correct path, and check that it works from that path:

$ curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.10.0/kind-linux-amd64
$ chmod +x ./kind
$ mv ./kind /usr/local/bin/kind
$ kind --version
kind version 0.10.0

Get an incredibly quick start with the sophisticated functionality of Kind by creating a cluster (Listing 1). As soon as you run the command, you should see some clever whirring in the background with animated output as Kind gets a cluster ready.

Listing 1: Creating a Cluster

$ kind create cluster
Creating cluster "kind" ...
 - Ensuring node image (kindest/node:v1.20.2)
 - Preparing nodes
 - Writing configuration
 - Starting control-plane
 - Installing CNI
 - Installing StorageClass
Set kubectl context to "kind-kind"
You can now use your cluster with:
kubectl cluster-info --context kind-kind
Have a nice day!

Take the advice of the output in Listing 1, and run the suggested command (Listing 2). The output is good news. If you run the command suggested at the end of the output, you receive a massive list of configuration data in JSON format that, as the output suggests, is excellent for debugging issues should you have any with your new Kubernetes installation.

Listing 2: Starting Up the Cluster

$ kubectl cluster-info --context kind-kind
Kubernetes control plane is running at https://127.0.0.1:34369
KubeDNS is running at https://127.0.0.1:34369/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.

As mentioned earlier, Kind is using Docker in a very clever way, as the heavily abbreviated output of the docker ps command shows (Listing 3).

Listing 3: docker (excerpt)

$ docker ps
IMAGE                 STATUS        PORTS                       NAMES
kindest/node:v1.20.2  Up 6 minutes  127.0.0.1:34369->6443/tcp   kind-control-plane

What the example has done so far is bootstrap a Kubernetes cluster (with one node) with the node image supplied directly by Kind. You can look deeper at images online [5], and other images (check the release notes for the correct versions) let you choose the specific Kubernetes version you want to use.

Although difficult to believe, the single container above is running a fully fledged Kubernetes cluster. You can check easily by running the command:

$ kubectl get pods -A

The -A is shorthand for --all-namespaces. Figure 1 shows the output is as expected and very welcome. The magic of Kind is clearly visible: A Kubernetes cluster running in a container!

A sentence that I never thought I'd write: Look at the Kubernetes cluster running in a container.
Figure 1: A sentence that I never thought I'd write: Look at the Kubernetes cluster running in a container.

The output of the command in Listing 4 reveals that you have a control plane coupled tightly with a node acting as the master node in the cluster. The documentation continues with instructions on how to create multiple clusters with different names with --name another-cluster switch.

Listing 4: kubectl get nodes

$ kubectl get nodes
NAME                 STATUS     ROLES                  AGE   VERSION
kind-control-plane   Ready      control-plane,master   21m   v1.20.2

Deleting a cluster is as simple as entering the delete command:

$ kind delete cluster --name another-cluster

Make sure you use the --name flag if you don't want to delete the cluster named kind, which is the default name.

Kindly Advance

For more advanced configurations, see the kind documentation [6]. That section provides insight into setting up multinode clusters and opening host machine network ports so the cluster will allow applications to be accessed from outside of Docker.

Additionally, you'll find a section in the documentation on "ingress" controllers [7] to get traffic into the cluster, and there's even a section about the use of Kind when Docker runs in rootless mode, without being the root user [8], which is the dream for Docker security and helps your container's security posture in numerous ways.

The documentation is clearly constructed, so the pages referenced here and others are well worth a look.

So Kind

To prove that you have a Kubernetes build on which you can run workloads, install an nginx deployment. Listing 5 is the YAML configuration file. To ingest the YAML into Kubernetes, simply save the content in a file called nginx.yaml and run the command:

$ kubectl create -f nginx.yaml
deployment.apps/nginx-deployment created

Listing 5: nginx Deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 80

The output looks successful. To see whether pods were created, as hoped, check the default namespace (Listing 6). As requested in the YAML file, two pods are running for extra resilience.

Listing 6: Check for Pods

$ kubectl get pods -n default
NAME                               READY   STATUS    RESTARTS   AGE
nginx-deployment-585449566-99qk6   1/1     Running   0          44s
nginx-deployment-585449566-pbzg2   1/1     Running   0          44s

If you want to expose a container's service to a port on your host machine (although I haven't experimented with this yet), the process would involve something like:

--config cluster-config.yaml

Listing 7: Host Port Configuration File

kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
  extraPortMappings:
  - containerPort: 80
    hostPort: 80
    listenAddress: "0.0.0.0"

If you then run a tool like lsof or netstat to show open ports, the output would show that the host machine's port was opened:

docker-pr     535     root    3u  IPv4  14678 0t0 TCP *:80 (LISTEN)

If you get stuck setting that up, I'd suggest disabling iptables and then restarting Docker. I look forward to experimenting with ingress controllers and host machine ports when I get a chance. By doing so, you can then connect to your nginx pods in a meaningful way to test applications being exposed outside of the Kubernetes cluster.

The End Is Nigh

To create a full-blown Kubernetes cluster with just one command – and rapidly, at that – is a sight to behold. That the standard kubectl commands work seamlessly is just a bonus. Remember to run the

kubectl cluster-info --context kind-kind

command after building your cluster.

For proof of concept deployments, compatibility, testing, and indeed other development activities, Kind is an excellent place to start with Kubernetes. I trust you will enjoy employing the excellent kind. I intend to use it as much as possible when running quick tests.