Building a Kubernetes cluster with kubeadm
In this article, let’s create a basic Kubernetes cluster using kubeadm
. kubeadm
is a tool that simplifies the process of creating a k8s cluster.
I have set up three Ubuntu 20.04 VMs on the same virtual network with hostnames k8s-control
, k8s-worker1
and k8s-worker2
. The first one will be the control plane node and the rest two will be worker nodes.
Before we set up our cluster, there are a few packages and configurations we need to set up. First of all, let’s install a container runtime
which enables us to run pods in each of the nodes. There are several container runtimes supported by Kubernetes, here we will go with containerd
.
Before installing containerd
, there are a few prerequisites we need to install and configure, let’s get them done in each of the Ubuntu servers:
# Updating kernel conf to load some kernel modules(overlay and netfilter) on startup
cat << EOF | sudo tee /etc/modules-load.d/containerd.conf
> overlay
> br_netfilter
> EOF
# Enabling these modules in the current session as well
sudo modprobe overlay
sudo modprobe br_netfilter
# Add some network configuration for k8s to work properly:
cat << EOF | sudo tee /etc/sysctl.d/99-kubernetes-cri.conf
> net.bridge.bridge-nf-call-iptables = 1
> net.ipv4.ip_forward = 1
> net.bridge.bridge-nf-call-ip6tables = 1
> EOF
# These configurations will be loaded on startup. Applying them immediately as well
sudo sysctl --system
Now, we are ready to install the container runtime containerd
on each of the machines:
sudo apt update && sudo apt install -y containerd
Now, let’s create a default containerd configuration and save it to a file etc/containerd/config.toml
. To make sure containerd starts using that configuration immediately, we’ll also restart it:
sudo mkdir -p /etc/containerd
sudo containerd config default | sudo tee /etc/containerd/config.toml
sudo systemctl restart containerd
Kubernetes requires swap to be disabled. So, let’s disable it on each of the machines:
sudo swapoff -a
We will be installing Kubernetes packages from the custom apt
repository provided by Kubernetes. Let’s first install the packages needed to use the repository:
sudo apt update && sudo apt install -y apt-transport-https curl
Now, let’s download the Google Cloud public signing key and then add the Kubernetes apt
repository as suggested in the Kubernetes docs. We will also update our local package listings.
sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://packages.cloud.google.com/apt/doc/apt-key.gpg
echo "deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo apt update
Now, let’s install the 1.24 version of Kubernetes packages:
sudo apt install -y kubelet=1.24.0-00 kubeadm=1.24.0-00 kubectl=1.24.0-00
While we’re at it, let’s make sure that these packages aren’t updated automatically:
sudo apt-mark hold kubelet kubeadm kubectl
Finally, we are ready to initialize our Kubernetes cluster. Let’s create a cluster by explicitly specifying the k8s version and also the network cidr available for the pods. We will do that by running the following command on the k8s-control
server. This might take a couple minutes to run.
sudo kubeadm init --pod-network-cidr 192.168.0.0/16 --kubernetes-version 1.24.0
Now, on the same machine k8s-control
, let’s configure the kubeconfig
file. It is the file that allows us to authenticate and communicate with our cluster.
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
Now, we can use kubectl
to verify that our cluster is up and running:
kubectl get nodes
The output of the command is as:
NAME STATUS ROLES AGE VERSION
k8s-control NotReady control-plane 6m41s v1.24.0
Here, we see a single node k8s-control
. This is expected because we haven’t configured the worker nodes to be part of the cluster yet. However, the Status
is NotReady
. This is because set up a networking plugin yet. There are multiple choices for a networking plugin, here we will go with Calico. Installing Calico
is very simple. We will just use the manifest file provided by calico:
kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml
After a few moments, the output of kubectl get nodes
will show the Status
of k8s-control
control-plane node as Ready
.
NAME STATUS ROLES AGE VERSION
k8s-control Ready control-plane 7m22s v1.24.0
Now, we are ready to add the worker nodes(k8s-worker1
and k8s-worker2
) to our the cluster. We will do it using the kubeadm join
command. First, let’s create a token on k8s-control
:
kubeadm token create --print-join-command
The output is as:
kubeadm join 10.0.1.101:6443 --token nlq1pb.12mzri195rwupusj --discovery-token-ca-cert-hash sha256:b348bd389511386883ac392b3a92cddf6dced0fe4ef6366cd29ea09138868f0a
Now, we run this command on both of the worker machines to join them to the cluster. After waiting a few moments, we can see that the worker nodes and up and running and in Ready
state along with the control plane node.
kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-control Ready control-plane 12m v1.24.0
k8s-worker1 Ready <none> 95s v1.24.0
k8s-worker2 Ready <none> 47s v1.24.0
We now have a running kubernetes cluster where we can add container workloads.