Creating Kubernetes clusters using kubeadm

In this article, we will learn to create a single master Kubernetes (k8s) cluster using kubeadm.

What is kubeadm ?
Kubeadm is a tool that helps you bootstrap a simple Kubernetes cluster and simplifies the deployment process. It performs the actions necessary to get a minimum viable cluster up and running such that it passes Kubernetes Conformance tests.
A typical Kubernetes cluster set-up with kubeadm consists of a single Kubernetes master, which is the machine coordinating the cluster, and multiple Kubernetes nodes, which are the machines running the actual workload.

Setting up the machines
We will deploy our k8s cluster on Amazon EC2 instances.
While launching the EC2 instance, select Ubuntu Server 16.04 LTS as the Machine Image.
Select type of instance as t2.medium because kubeadm needs 2 or more CPUs as well as minimum 2 GB RAM.
Enter the number of instances required.
Add following Inbound rules to the instances respectively.

Master node(s)

  • TCP Inbound 6443
  • TCP Inbound 2379–2380
  • TCP Inbound 10250
  • TCP Inbound 10251
  • TCP Inbound 10252

Worker node(s)

  • TCP Inbound -10250
  • TCP Inbound 30000–32767

Install Docker on the instances
From Docker’s repositories for Ubuntu:

apt-get update
apt-get install -y apt-transport-https ca-certificates curl software-properties-common
curl -fsSL | apt-key add -
add-apt-repository “deb$(. /etc/os-release; echo “$ID”) $(lsb_release -cs) stable”
apt-get update 
apt-get install -y docker-ce

Installing kubeadm, kubelet and kubectl on the instances

apt-get update && apt-get install -y apt-transport-https curl
curl -s | apt-key add -
cat <<EOF >/etc/apt/sources.list.d/kubernetes.list
deb kubernetes-xenial main
apt-get update
apt-get install -y kubelet kubeadm kubectl
apt-mark hold kubelet kubeadm kubectl

Configure cgroup driver used by kubelet on Master Node
When using Docker, kubeadm will automatically detect the cgroup driver for the kubelet and set it in the /var/lib/kubelet/kubeadm-flags.env file during runtime.
If you are using a different CRI, you have to modify the file /etc/default/kubelet with your cgroup-driver value, like so:
KUBELET_KUBEADM_EXTRA_ARGS= — cgroup-driver=<value>
Restarting the kubelet is required:

systemctl daemon-reload
systemctl restart kubelet

Please bear in mind, that you only have to do that if the cgroup driver of your CRI is not cgroupfs.

Initializing your master
The master is the machine where the control plane components run, including etcd (the cluster database) and the API server (which the kubectl CLI communicates with).
We have to install a pod network so that our pods can communicate with each other. Kubeadm only supports Container Network Interface (CNI) based networks.
We use Calico as our pod network add-on and install it using following commands

kubectl apply -f
kubectl apply -f

Then run

kubeadm init — kubernetes-version=1.11.0 — apiserver-advertise-address=<master_ip-address> — pod-network-cidr=

Installs specified version of k8s and uses the network interface to advertise the master’s IP.
kubeadm init first runs a series of prechecks to ensure that the machine is ready to run Kubernetes. These prechecks expose warnings and exit on errors. It then downloads and installs the cluster control plane components.

To make kubectl work for your non-root user, run these commands

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

Alternatively, if you are the root user, you can run:
export KUBECONFIG=/etc/kubernetes/admin.conf
 Make a record of the kubeadm init command’s output. You need this command to join the worker nodes to your cluster.

Joining worker nodes
 Nodes are where your workloads (containers and pods, etc) run.
 Run the following commands on each worker machine by first SSH-ing into it and become root (sudo -i)

kubeadm join — token <token> <master-ip>:<master-port> — discovery-token-ca-cert-hash sha256:<hash>

(This command is the output of the kubeadm init command run on the master node)

 To undo what kubeadm did, you should first drain the node and make sure that the node is empty before shutting it down.
 On the master run:

kubectl drain <node name> — delete-local-data — force — ignore-daemonsets
kubectl delete node <node name>

Then, on the node being removed, reset all kubeadm installed state:

kubeadm reset

Now you can start over by simply running kubeadm init again.

That’s it folks. You now have your first k8s cluster deployed using kubeadm :) In the next post, we will be creating Highly Available clusters with kubeadm.