Skip to main content

Creating Cluster with Kubeadm

Creating a cluster with kubeadm is a fairly simple process.

Some requirements are necessary for the machines.

In an exam environment it probably won't be necessary to pay attention to this, but it's good to know to ensure.

First, swap and firewall need to be disabled and some modules loaded.

## Following the documentation https://kubernetes.io/docs/setup/production-environment/
## https://docs.docker.com/engine/install/ubuntu/container-runtimes/

echo -e "\n##### Disabling swap #####"
sudo sed -i '/swap/d' /etc/fstab
sudo swapoff -a

echo -e "\n##### Disabling firewall #####"
sudo systemctl disable --now ufw >/dev/null 2>&1

echo -e "\n##### Enabling kernel modules required for containerd #####"
cat <<EOF >> /etc/modules
ip_vs
ip_vs_rr
ip_vs_wrr
ip_vs_sh
br_netfilter
nf_conntrack
EOF

systemctl restart systemd-modules-load.service
# sysctl params required by setup, params persist across reboots
# IPv6 settings can be removed if not using IPv6
cat <<EOF | sudo tee /etc/sysctl.d/10-kubernetes.conf
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1
net.bridge.bridge-nf-call-iptables=1
net.ipv4.ip_forward=1
EOF
# Apply sysctl params without reboot
sudo sysctl --system
#sudo mkdir -p /var/lib/kubernetes/

Then it's necessary that the machines have a container runtime installed as well as kubeadm kubelet and kubectl. Containerd is already in the Kubernetes repository.

echo -e "\n##### Installing Container Runtime Interface #####"
echo -e "\n##### 1 - Adding the kubernetes repository #####"
sudo mkdir -p /etc/apt/keyrings

# The latest version can be checked at https://dl.k8s.io/release/stable.txt. The example value would be 1.29.3 but we only need 1.29. To facilitate we have the command below.
KUBE_LATEST=$(curl -L -s https://dl.k8s.io/release/stable.txt | awk 'BEGIN { FS="." } { printf "%s.%s", $1, $2 }')

curl -fsSL https://pkgs.k8s.io/core:/stable:/${KUBE_LATEST}/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg

echo "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/${KUBE_LATEST}/deb/ /" | sudo tee /etc/apt/sources.list.d/kubernetes.list

# This would be an example for a specific kubernetes version
#curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.28/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg

# echo "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.28/deb/ /" | sudo tee /etc/apt/sources.list.d/kubernetes.list

echo -e "\n##### 2 - Installing packages #####"
sudo apt update
sudo apt install -y containerd ipvsadm ipset

echo -e "\n##### 3 - Enabling systemd Cgroups in containerd #####"
sudo cp /etc/containerd/config.toml /etc/containerd/config.toml.default
containerd config default | sed 's/SystemdCgroup = false/SystemdCgroup = true/' | sudo tee /etc/containerd/config.toml

sudo systemctl restart containerd.service
systemctl status containerd.service

# After we have the container runtime installed we can add kubeadm kubelet and kubectl
sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl

sudo systemctl enable kubelet
sudo systemctl status kubelet

Usually this entire process shouldn't be asked during the exam, but if it is, it's good to know.

Kubeadm checks if the node meets the requirements. It requires 2 GiB or more of RAM and at least 2 CPUs on control-plane machines. This can be ignored in the command we're going to execute. In the exam if this is requested they may not provide machines with these resources, after all it's not a production environment.

Once we have kubeadm kubectl and kubelet available on the master node we can execute:


# To facilitate the command it's good to run a completion
source <(kubeadm completion bash)

# If no version is passed it will install the latest available for the specified kubeadm. We can check what we have available in kubeadm before installing.

# To see versions we can use based on the installed version
apt-cache madison kubeadm

# Here we are setting up control plane.
kubeadm init --kubernetes-version=1.29.0 --pod-network-cidr 192.168.0.0/16 --ignore-preflight-errors=NumCPU --ignore-preflight-errors=Mem

In the case of workers, all bootstrap is the same, but the kubeadm command will be the join provided by the kubeadm init command

If you lost the join command in the kubeadm output on the control-plane we can generate another one.

controlplane $ kubeadm token create --print-join-command
#kubeadm join 172.30.1.2:6443 --token i80ben.9k3mlcpc0flghkny --discovery-token-ca-cert-hash sha256:190ba21620d6cd0fa70a014fa5c7f66e48055885cd844eba55d85a4eac0bb8aa