Germany is still in Corona lockdown, which means we can not go outside, meet friends and do other activities. Therefore, I spend more time acquiring a new skill. I have been using Docker Compose and Swarm to run multi-containers application for development and testing for last 2 years. I always thought of adding Kubernetes (K8s) in my skill sets but somehow I have been busy with Hyperledger Fabric, IPFS, ESP, Arduino etc. A silver lining in COVID-19 pandemic for me is to have time to learn Kubernetes. The IoTCrawler project also gave me impetus to move in this direction. I am going to share my knowledge and leanings from time to time with a series of blogs on Kubernetes. In this blog, I will explain how can you run a single node Kubernetes cluster locally and deploy a simple container on the cluster.

What is Kubernetes ?

Docker containers are everywhere and they run your applications in total isolation (quarantine mode) as we are now in Corana time. A container is very simple to work with but it gets really messy when their number rise up. Kubernetes is an open source container orchestration system which can be used to deploy, scale, monitor and manage production grade container applications efficiently. Kubernetes eliminates manual processes involved in container management. In the beginning, container deployment on Kubernetes might be difficult and complex for Docker Swarm users but in the long run it is worth as it provides better and sophisticated resources. Here, you can find concepts and resources of Kubernetes in detail. We have many things to do, so lets start by setting up the environment.

Prerequisites

I use Ubuntu 16.04 and installation instructions for tools are specific to it. We require two essential tools, one to setup a Kubernetes cluster and second to manage containers on the cluster. There are multiple tools available to setup Kubernetes learning environment locally. I find both Kind and Minikube are the best suited for the task. I am going to use kubectl to deploy and interact with the local Kubernetes resources. First lets start by installing all the tools. Create a project directory for Kubernetes.

mkdir -p ~/Project/k8s/bin
cd ~/Project/k8s/bin

Kind

curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.7.0/kind-$(uname)-amd64
chmod +x ./kind

Minikube

curl -Lo minikube https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
chmod +x ./minikube

Kubectl

curl -LO https://storage.googleapis.com/kubernetes-release/release/`curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt`/bin/linux/amd64/kubectl
chmod +x ./kubectl

If everything worked well, you can check version using following commands.

kind version
minikube version
kubectl version

Create Cluster

Use kind or minikube to create a local Kubernetes cluster.

Kind

kind create cluster --name kind

The output is similar to this

Creating cluster "kind" ...
✓ Ensuring node image (kindest/node:v1.17.0) 🖼
✓ Preparing nodes 📦
✓ Writing configuration 📜
✓ Starting control-plane 🕹️
✓ Installing CNI 🔌
✓ Installing StorageClass 💾

Get information about the cluster

kubectl cluster-info --context kind-kind

The output should be similar to following

Kubernetes master is running at https://127.0.0.1:32768
KubeDNS is running at https://127.0.0.1:32768/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy

Minikube

minikube start

Output should be similar to following

😄 minikube v1.9.2 on Ubuntu 16.04
✨ Using the docker driver based on existing profile
👍 Starting control plane node m01 in cluster minikube
🚜 Pulling base image ...
🤷 docker "minikube" container is missing, will recreate.
🔥 Creating Kubernetes in docker container with (CPUs=2) (8 available), Memory=3900MB (15937MB available) ...
🐳 Preparing Kubernetes v1.18.0 on Docker 19.03.2 ...
▪ kubeadm.pod-network-cidr=10.244.0.0/16
E0427 11:52:56.095757 13734 kubeadm.go:331] Overriding stale ClientConfig host https://172.17.0.2:8443 with https://172.17.0.3:8443
🌟 Enabling addons: default-storageclass, storage-provisioner
🏄 Done! kubectl is now configured to use "minikube"

Deployment

We have a kubernetes cluster running locally. Now, it is time to deploy a container on the cluster. I will use kubectl utility for this task. For an instance, one could use following command to deploy echoserver image on the cluster. The echoserver is an existing image which is a simple HTTP server.

kubectl create deployment hello-world --image=k8s.gcr.io/echoserver:1.10
deployment.apps/hello-world created

kubectl is a very powerful tool which has many commands to manage and monitor containers on a cluster. I am going to demonstrate get, exec and logs sub-commands

kubectl get deployment
NAME        READY UP-TO-DATE AVAILABLE AGE
hello-world 1/1   1          1         43s
kubectl get pods
NAME                        READY STATUS  RESTARTS AGE
hello-world-6fc4596b9-wqvm6 1/1   Running 0        49s
kubectl exec -it hello-world-6fc4596b9-wqvm6 bash
root@hello-world-6fc4596b9-wqvm6:/# echo "Learning Kubernetes is silver lining for me in Covid-19"
Learning Kubernetes is silver lining for me in Covid-19
exit
kubectl logs hello-world-6fc4596b9-wqvm6
Generating self-signed cert
Generating a 2048 bit RSA private key
....................+++
...........................+++
writing new private key to '/certs/privateKey.key'
-----
Starting nginx

Expose the Deployment to Kubernetes Service.

kubectl expose deployment hello-world-deployment --type=ClusterIP --port=8080

Get the Service

kubectl get svc hello-world-deployment

Now, the Service is running inside the cluster. You can’t access by its IP address. Kubernetes provides a proxy to expose its resources outside the cluster. Run the following command to run proxy.

kubectl proxy
Starting to serve on 127.0.0.1:8001

At this point, you can access the service in your browser on the following link

http://localhost:8001/api/v1/namespaces/default/services/hello-world-deployment:8080/proxy/

It will show the output similar to this

CLIENT VALUES:
client_address=10.244.0.1
command=GET
real path=/
query=nil
request_version=1.1
request_uri=http://localhost:8080/

SERVER VALUES:
server_version=nginx: 1.10.0 - lua: 10001

HEADERS RECEIVED:
accept=text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
accept-encoding=gzip, deflate, br
accept-language=en-US,en;q=0.9,de;q=0.8
cookie=SID=itedaqsc8g9rmo75lom9fbr5901nvo3e
host=localhost:8001
sec-fetch-dest=document
sec-fetch-mode=navigate
sec-fetch-site=cross-site
sec-fetch-user=?1
upgrade-insecure-requests=1
user-agent=Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/80.0.3987.163 Chrome/80.0.3987.163 Safari/537.36
x-forwarded-for=127.0.0.1, 172.17.0.1
x-forwarded-uri=/api/v1/namespaces/default/services/hello-world-deployment:8080/proxy/
BODY:
-no body in request-

Clean Up

You can use following command to clean the environment.

For kind cluster

kind delete cluster --name kind
Deleting cluster "kind" ...

For minikube cluster

minikube stop
✋ Stopping "minikube" in docker ...
🛑 Node "m01" stopped.