System prerequisites for a kubeadm Kubernetes cluster: swap, kernel modules, sysctl, containerd, and repository setup.

“How hard can it be to set up a Kubernetes cluster?” - Famous last words before discovering kubeadm

ℹ️ Info
Originally written for Ubuntu 20.04 and Kubernetes 1.24. Updated for the pkgs.k8s.io repository and signed keyring method. Always check the official kubeadm docs for the latest instructions.

Overview

This part is boring but critical. You’re preparing the OS before installing Kubernetes. Skip a step and you’ll debug cryptic errors for an hour. Ask me how I know.

Part 1: prep all nodes (control plane and workers). Part 2: actually build the cluster.

Lab setup: 3 Ubuntu VMs (2 vCPU, 4 GB RAM, 50 GB disk, static IPs). Adjust for your environment.

k8s-lab-image


Disable Swap

“Kubernetes is opinionated about swap for the same reason surgeons are opinionated about sterile instruments.” - Resource Management 101

Kubernetes requires swap disabled. It needs precise resource accounting to schedule pods. Swap breaks that because the kernel can page out pod memory without Kubernetes knowing. Scheduler thinks a pod is using 1GB, it’s actually using 2GB on disk. Bad things happen.

Disable swap immediately:

sudo swapoff -a

Prevent swap from re-enabling on reboot by commenting it out of /etc/fstab:

sudo sed -e '/swap/ s/^#*/#/' -i /etc/fstab

Verify:

cat /etc/fstab
# /swap.img none swap sw 0 0
💡 Tip
After disabling swap, confirm it’s actually off with free -h. The Swap row should show all zeros. If swap is still active after swapoff -a, check for zram devices: cat /proc/swaps.

Kernel Modules

Pod networking requires overlay and br_netfilter modules.

Persist across reboots:

cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF

Load them now:

sudo modprobe overlay
sudo modprobe br_netfilter

Verify:

lsmod | grep overlay && lsmod | grep br_netfilter

Sysctl Settings

Enable IP forwarding and bridge iptables processing:

sudo tee /etc/sysctl.d/kubernetes.conf<<EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
EOF

sudo sysctl --system

Without these, pod-to-pod traffic across nodes gets dropped by the kernel.


Install Prerequisites

sudo apt-get update && sudo apt-get install -y \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg \
    lsb-release

Install Containerd

Kubernetes needs a container runtime. This guide uses containerd.

Add Docker’s GPG key and repository (containerd is distributed from Docker’s repo):

sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

Install:

sudo apt-get update && sudo apt-get install -y containerd.io

Configure Containerd

Generate the default config and enable SystemdCgroup. Kubernetes requires the systemd cgroup driver for proper resource management.

sudo containerd config default | sudo tee /etc/containerd/config.toml
sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml

Verify:

grep SystemdCgroup /etc/containerd/config.toml
# SystemdCgroup = true
⚠️ Warning
If SystemdCgroup is still false after the sed command, edit the file manually. The kubelet will fail to start if the cgroup driver doesn’t match.

Restart containerd:

sudo systemctl restart containerd
💡 Tip

Verify containerd is working before moving on. crictl talks directly to the container runtime:

sudo crictl info | head -20
sudo crictl images

If crictl can’t connect, check sudo systemctl status containerd for errors. Catching a broken runtime now saves time versus debugging a failed kubeadm init later.

💡 Tip
If using a different container runtime (CRI-O, Docker Engine), configure the appropriate cgroup driver. See Kubernetes container runtimes.

Add the Kubernetes Repository

Download the signing key:

sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.32/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
ℹ️ Info
Replace v1.32 with the minor version you want. The pkgs.k8s.io repository is versioned per minor release.

Add the repository:

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

Verify:

cat /etc/apt/sources.list.d/kubernetes.list

Run All Steps on All Nodes

Every command in this article needs to run on every node in the cluster - control plane and workers alike. Part 2 covers the node-specific steps.

💡 Tip
If you’re setting up multiple nodes, consider scripting these steps or using a configuration management tool like Ansible. Running the same 15 commands manually on 3+ machines is where mistakes happen.

References