Introduction

Kubernetes is here, and it’s here in a big way. Whilst not the easiest way to deploy a kubernetes cluster (try a managed service such as EKS) kubeadm is by and far the best way to learn how to build a Kubernetes cluster. In this tutorial, we’ll build a Kubernetes cluster using kubeadm and 3 nodes running Ubuntu 18.04.

Reference Architecture

Name IP Address Role
kub1 192.168.0.10 Master
kub2 192.168.0.11 Node
kub3 192.168.0.12 Node

Kubernetes requires at least 2 CPUs and for the swap file to be disabled. Please ensure you read the following system requirements:

Kubernetes System Requirements

Installation and dependancies

sudo apt update -y && sudo apt upgrade -y

Enable the “Universe” Repositories in Ubuntu:

sudo add-apt-repository universe

Update apt:

sudo apt update

Modfify the local hosts file accordingly, adding host entries for each of the hosts within the cluster.

sudo vim /etc/hosts
127.0.0.1	localhost.localdomain	localhost
::1		localhost6.localdomain6	localhost6

# The following lines are desirable for IPv6 capable hosts
::1     localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
ff02::3 ip6-allhosts
192.168.0.10	kub1
192.168.0.11	kub2
192.168.0.13	kub3

Next, we need to install and enable docker on all nodes within the cluster:

sudo apt install docker.io
sudo systemctl enable --now docker

And check docker is running on all nodes:

docker --version

Will output something similar to:

Docker version 18.09.5, build e8ff056

Next we need to install the Kubernetes repositories for Ubuntu 10.04 (Bionic) on all nodes in the cluster. We start by configuring some dependancies first:

sudo apt install -y apt-transport-https ca-certificates curl software-properties-common

And now, we add the Kubernetes repository keys from Google:

curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add
OK

And now install the correct repository:

sudo apt-add-repository "deb http://apt.kubernetes.io/ kubernetes-xenial main"

And finally, we install the Kubernetes packages:

sudo apt install -y kubeadm kubelet kubectl

For the final step, we need to ensure the swap file is off on all hosts in the cluster:

sudo swapoff -a

Additionally, please disable swap in /etc/fstab by commenting out the relevant section.

Setup / Configuration

With the prerequistites installed, the next task is to configure the Kubernetes cluster (finally!)

First, lets initialise the cluster on the master node (kub1). We’ll start by creating a kubernetes cluster folder in our home directory:

cd ~
mkdir kubernetes
cd kubernetes

Next, we initialise the cluster:

sudo kubeadm init

This will provide output similar to the following:

You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
https://kubernetes.io/docs/concepts/cluster-administration/addons/

Then you can join any number of worker nodes by running the following on each as root:

kubeadm join 192.168.0.10:6443 --token 8i0jw2.ka62upoxwe8jxw0w \
    --discovery-token-ca-cert-hash sha256:17070aab139b6f884d9321834a17e13c38ee664dbd673c7c9e629e3a3211f1ed 

Next, we simply run the command as described preceeded with “sudo”

sudo kubeadm join 192.168.0.10:6443 --token 8i0jw2.ka62upoxwe8jxw0w \
    --discovery-token-ca-cert-hash sha256:17070aab139b6f884d9321834a17e13c38ee664dbd673c7c9e629e3a3211f1ed

With that completed on each of the nodes (kub2 and kub3) you can now check the current statuc of the cluster by running the following on the master node (kub1):

$ kubectl get nodes
NAME   STATUS     ROLES    AGE    VERSION
kub1   NotReady   master   173m   v1.15.0
kub2   NotReady   <none>   4s     v1.15.0
kub3   NotReady   <none>   168m   v1.15.0

We can see the cluster status is “NotReady”. We can run the following to examine this further:

$ kubectl get pods --all-namespaces
NAMESPACE     NAME                           READY   STATUS    RESTARTS   AGE
kube-system   coredns-5c98db65d4-4d9vs       0/1     Pending   0          176m
kube-system   coredns-5c98db65d4-wj97v       0/1     Pending   0          176m
kube-system   etcd-kub1                      1/1     Running   1          175m
kube-system   kube-apiserver-kub1            1/1     Running   1          175m
kube-system   kube-controller-manager-kub1   1/1     Running   1          175m
kube-system   kube-proxy-qsxsr               1/1     Running   0          3m11s
kube-system   kube-proxy-rdjdl               1/1     Running   1          172m
kube-system   kube-proxy-s96n6               1/1     Running   1          176m
kube-system   kube-scheduler-kub1            1/1     Running   1          175m

This shows that the coredns pods are not running. As a result, the cluster cannot start. To resolve this, we need to deploy a Pod Network. For this, we will use weaveworks becuase it supports a CNI plug-in.

Further information of Pod Networks can be found here:

Cluster Networking

kubectl apply -n kube-system -f "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 | tr -d '\n')"

Running “get pods –all-namespaces” again will show the current deployment status of the Pod network.

$ kubectl get pods --all-namespaces
NAMESPACE     NAME                           READY   STATUS              RESTARTS   AGE
kube-system   coredns-5c98db65d4-4d9vs       0/1     Pending             0          3h6m
kube-system   coredns-5c98db65d4-wj97v       0/1     Pending             0          3h6m
kube-system   etcd-kub1                      1/1     Running             1          3h5m
kube-system   kube-apiserver-kub1            1/1     Running             1          3h5m
kube-system   kube-controller-manager-kub1   1/1     Running             1          3h5m
kube-system   kube-proxy-qsxsr               1/1     Running             0          12m
kube-system   kube-proxy-rdjdl               1/1     Running             1          3h1m
kube-system   kube-proxy-s96n6               1/1     Running             1          3h6m
kube-system   kube-scheduler-kub1            1/1     Running             1          3h5m
kube-system   weave-net-54dqh                0/2     ContainerCreating   0          2m41s
kube-system   weave-net-flw4h                0/2     ContainerCreating   0          2m41s
kube-system   weave-net-svvfh                0/2     ContainerCreating   0          2m41s

Eventually, the weave-net pods will enter a running state:

$ kubectl get pods --all-namespaces
NAMESPACE     NAME                           READY   STATUS    RESTARTS   AGE
kube-system   coredns-5c98db65d4-4d9vs       1/1     Running   3          3h16m
kube-system   coredns-5c98db65d4-wj97v       1/1     Running   3          3h16m
kube-system   etcd-kub1                      1/1     Running   1          3h15m
kube-system   kube-apiserver-kub1            1/1     Running   1          3h16m
kube-system   kube-controller-manager-kub1   1/1     Running   1          3h16m
kube-system   kube-proxy-qsxsr               1/1     Running   0          23m
kube-system   kube-proxy-rdjdl               1/1     Running   1          3h12m
kube-system   kube-proxy-s96n6               1/1     Running   1          3h16m
kube-system   kube-scheduler-kub1            1/1     Running   1          3h15m
kube-system   weave-net-54dqh                2/2     Running   0          13m
kube-system   weave-net-flw4h                2/2     Running   0          13m
kube-system   weave-net-svvfh                2/2     Running   0          13m

And “kubectl get nodes” will report all nodes are rady:

$ kubectl get nodes
NAME   STATUS   ROLES    AGE     VERSION
kub1   Ready    master   3h18m   v1.15.0
kub2   Ready    <none>   24m     v1.15.0
kub3   Ready    <none>   3h13m   v1.15.0

At this stage, you have successfully deployed a 3 node Kubernetes cluster on Ubuntu 18.04