Installing Kubernetes with kubeadm

kubeadm is the official tool for bootstrapping production-grade Kubernetes clusters. Unlike k3s (single binary, lightweight) or Minikube (local development), kubeadm gives you full control over the cluster configuration and is the approach used when you need to run a standard, unmodified Kubernetes cluster. This guide covers a two-node setup: one control plane node and one worker, which you can extend to as many workers as needed.

Prerequisites

Requirements for each node:
  - Ubuntu 22.04 LTS (all nodes)
  - 2 CPUs minimum (control plane), 1 CPU (worker)
  - 2 GB RAM minimum per node
  - Full network connectivity between all nodes
  - Unique hostname, MAC address, and product_uuid on each node
  - Ports open: 6443 (API server), 2379-2380 (etcd), 10250 (kubelet),
                10259 (scheduler), 10257 (controller manager)
  - Swap DISABLED on all nodes
# Run on ALL nodes:

# Disable swap (Kubernetes requires swap off):
sudo swapoff -a
sudo sed -i '/swap/d' /etc/fstab    # Permanently disable swap

# Verify swap is off:
free -h    # Swap row should show 0

# Set hostname (use unique names):
# On control plane:  sudo hostnamectl set-hostname k8s-master
# On worker 1:       sudo hostnamectl set-hostname k8s-worker-01

# Load required kernel modules:
cat <

Install container runtime

# Install containerd (the container runtime Kubernetes uses):
sudo apt update
sudo apt install -y containerd

# Generate default containerd config:
sudo mkdir -p /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml

# Enable systemd cgroup driver (required for kubeadm):
sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml

sudo systemctl restart containerd
sudo systemctl enable containerd

Install kubeadm, kubelet, kubectl

# Add Kubernetes apt repository:
sudo apt install -y apt-transport-https ca-certificates curl gpg
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.29/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.29/deb/ /' |   sudo tee /etc/apt/sources.list.d/kubernetes.list

sudo apt update
sudo apt install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl    # Prevent accidental upgrades

# Verify versions:
kubeadm version
kubectl version --client

Initialize the control plane

⚠️ WARNING: Run kubeadm init only on the designated control plane node. Running it on a worker node will turn that node into an unintended control plane.

# On the CONTROL PLANE node only:
sudo kubeadm init --pod-network-cidr=10.244.0.0/16

kubeadm init output (end)

Your Kubernetes control-plane has initialized successfully!

To start using your cluster, you need to run the following as a regular user:
  mkdir -p $HOME/.kube
  sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
  sudo chown $(id -u):$(id -g) $HOME/.kube/config

You can now join any number of worker nodes by running:
kubeadm join 192.168.1.100:6443 --token abc123.xyz789     --discovery-token-ca-cert-hash sha256:1234abcd...
# Set up kubectl for your user:
mkdir -p $HOME/.kube
sudo cp /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

# Install Flannel CNI (Container Network Interface — pods cannot communicate without this):
kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml

# Wait for the control plane node to become Ready:
kubectl get nodes -w    # Watch until STATUS shows Ready

Join worker nodes

# On each WORKER node, run the join command from kubeadm init output:
sudo kubeadm join 192.168.1.100:6443 --token abc123.xyz789     --discovery-token-ca-cert-hash sha256:1234abcd...

# If the token expired (tokens expire after 24h), generate a new one on control plane:
kubeadm token create --print-join-command

# Back on control plane — verify all nodes are Ready:
kubectl get nodes

kubectl get nodes output after joining workers

NAME            STATUS   ROLES           AGE     VERSION
k8s-master      Ready    control-plane   15m     v1.29.2
k8s-worker-01   Ready              3m      v1.29.2

Conclusion

The kubeadm installation sequence always follows the same order: disable swap on all nodes, install containerd with systemd cgroup driver, install kubeadm/kubelet/kubectl, run kubeadm init on the control plane, install a CNI plugin (Flannel or Calico), then join workers with the printed token. The most common failure point is forgetting to install the CNI plugin — without it, pods stay in Pending state and nodes show NotReady because inter-pod networking is broken.

FAQ

Is Installing Kubernetes with kubeadm important for Ubuntu administrators?+

Yes. It supports practical Ubuntu administration because it connects directly to server reliability, security, troubleshooting, or daily operations.

Should I practice this on a live server?+

Use a lab VM first. After you understand the command output and rollback path, apply the workflow carefully on real systems.

What should I do after reading this article?+

Run the practice commands, write down what each one shows, and continue to the next article in the Ubuntu roadmap.

Need help with Ubuntu administration?

Work directly with Muhammad Irfan Aslam for Ubuntu Server, Linux, cloud, Docker, DevOps, CI/CD, or infrastructure troubleshooting support.

Hire Me for Support