DEV Community

Arnob
Arnob

Posted on

Installing kubeadm on Ubuntu (24.04 LTS)

kubeadm Logo

What is kubeadm?

kubeadm is a command-line tool provided by Kubernetes that helps you bootstrap (initialize and set up) a working Kubernetes cluster quickly and correctly.

It automates the entire process of setting up the control plane (the brain of the cluster) and joining worker nodes — so you don’t have to configure them manually.

Think of kubeadm as the installer or setup wizard for Kubernetes clusters.

What kubeadm Does?

When you run kubeadm init, the tool performs several important tasks:

  1. Initializes the control plane — sets up the API server, controller manager, scheduler, and etcd.
  2. Generates certificates for secure communication between components.
  3. Configures kubelet to connect to the cluster.
  4. Sets up bootstrap tokens so worker nodes can join securely.
  5. Provides a join command for adding worker nodes to the cluster.

kubeadm in the Kubernetes Architecture

Here’s how kubeadm fits into the cluster setup:

  1. Install container runtime — containerd or CRI-O.
  2. Install kubeadm, kubelet, and kubectl.
  3. Run **kubeadm init** to set up the control plane.
  4. Run **kubeadm join** on worker nodes to connect them.
  5. Install a CNI plugin (Calico or Flannel) for pod networking.

This guide walks through the complete process of installing Kubernetes using kubeadm — from preparing your environment to resolving common setup issues.

1. Check Required Ports

Ensure required ports are accessible:

nc 127.0.0.1 6443 -zv -w 2
Enter fullscreen mode Exit fullscreen mode

2. Install Container Runtime (containerd)

sudo apt update
sudo apt install -y containerd
Enter fullscreen mode Exit fullscreen mode

Generate a default configuration:

sudo mkdir -p /etc/containerd
sudo containerd config default | sudo tee /etc/containerd/config.toml
Enter fullscreen mode Exit fullscreen mode

Restart and enable containerd:

sudo systemctl restart containerd
sudo systemctl enable containerd
sudo systemctl status containerd
Enter fullscreen mode Exit fullscreen mode

Note: Docker Engine does not implement CRI. If you use Docker, you must install cri-dockerd separately.

3. Enable IP Forwarding

Enable and make IP forwarding persistent:

sudo sysctl -w net.ipv4.ip_forward=1
echo "net.ipv4.ip_forward=1" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
Enter fullscreen mode Exit fullscreen mode

4. Install kubeadm, kubelet, and kubectl

These are required on all nodes.

sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates curl gpg
Enter fullscreen mode Exit fullscreen mode

Add Kubernetes signing key and repository:

sudo mkdir -p -m 755 /etc/apt/keyrings
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.34/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.34/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list
Enter fullscreen mode Exit fullscreen mode

Install packages:

sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl
Enter fullscreen mode Exit fullscreen mode

Enable kubelet:

sudo systemctl enable --now kubelet
Enter fullscreen mode Exit fullscreen mode

The kubelet is now restarting every few seconds, as it waits in a crashloop for kubeadm to tell it what to do.

5. Initialize the Control Plane and Init

Check your default network interface:

ip route show
Enter fullscreen mode Exit fullscreen mode

Then initialize the control-plane:

sudo kubeadm init --pod-network-cidr=192.168.88.0/24
Enter fullscreen mode Exit fullscreen mode

After running this commend the teminal output will be

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
Alternatively, if you are the root user, you can run:
  export KUBECONFIG=/etc/kubernetes/admin.conf
You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
  https://kubernetes.io/docs/concepts/cluster-administration/addons/
Then you can join any number of worker nodes by running the following on each as root:
kubeadm join 192.168.88.194:6443 --token wa5krk.c7z965sbpbxi \
 --discovery-token-ca-cert-hash sha256:c4eda3e7cfacb25e43b30ca2e2aa950d68d7306851396e5014e63f981 
Enter fullscreen mode Exit fullscreen mode

After Success, if you check the node status, then the problem happed, the node not getting ready.

root@kubeadm:/home/ubuntu# kubectl get nodes
NAME      STATUS     ROLES           AGE   VERSION
kubeadm   NotReady   control-plane   10s   v1.34.2
Enter fullscreen mode Exit fullscreen mode

Then need to check the containerd

sudo journalctl -u containerd -b --no-pager | tail -n 200
Enter fullscreen mode Exit fullscreen mode

Output

Nov 14 17:20:17 kubeadm kubelet[18636]: E1114 17:20:17.649774   18636 kubelet.go:3012] "Container runtime network not ready" networkReady="NetworkReady=false reason:NetworkPluginNotReady message:Network plugin returns error: cni plugin not initialized"
Nov 14 17:20:22 kubeadm kubelet[18636]: E1114 17:20:22.650723   18636 kubelet.go:3012] "Container runtime network not ready" networkReady="NetworkReady=false reason:NetworkPluginNotReady message:Network plugin returns error: cni plugin not initialized"
Enter fullscreen mode Exit fullscreen mode

Then Run This Commend

root@kubeadm:/home/ubuntu# sudo sysctl -w net.ipv4.ip_forward=1
net.ipv4.ip_forward = 1
root@kubeadm:/home/ubuntu# echo "net.ipv4.ip_forward=1" | sudo tee -a /etc/sysctl.conf
net.ipv4.ip_forward=1
root@kubeadm:/home/ubuntu# sudo sysctl -p
net.ipv4.ip_forward = 1
root@kubeadm:/home/ubuntu# sudo swapoff -a
root@kubeadm:/home/ubuntu# sudo sed -i '/swap/s/^/#/' /etc/fstab
Enter fullscreen mode Exit fullscreen mode

After that again run the kubeadm init

 sudo kubeadm init --pod-network-cidr=192.168.88.0/24
Enter fullscreen mode Exit fullscreen mode

Then check the bash:

[init] Using Kubernetes version: v1.34.2
[preflight] Running pre-flight checks
[preflight] Pulling images required for setting up a Kubernetes cluster
[preflight] This might take a minute or two, depending on the speed of your internet connection
[preflight] You can also perform this action beforehand using 'kubeadm config images pull'
W1114 15:41:22.603932    2248 checks.go:827] detected that the sandbox image "registry.k8s.io/pause:3.8" of the container runtime is inconsistent with that used by kubeadm. It is recommended to use "registry.k8s.io/pause:3.10.1" as the CRI sandbox image.
Enter fullscreen mode Exit fullscreen mode

Goto containerd config and edit config.toml, Modify: /etc/containerd/config.toml:

[plugins."io.containerd.grpc.v1.cri".containerd]
  sandbox_image = "registry.k8s.io/pause:3.10.1"
Enter fullscreen mode Exit fullscreen mode

Restart containerd:

sudo systemctl restart containerd
Enter fullscreen mode Exit fullscreen mode

Re-run kubeadm:

sudo kubeadm init --pod-network-cidr=192.168.88.0/24
Enter fullscreen mode Exit fullscreen mode

If not running the kubeadm then reset the kubeadm

 sudo kubeadm reset -f
Enter fullscreen mode Exit fullscreen mode

Ouptut

sudo systemctl restart containerd
sudo rm -rf /etc/kubernetes/pki/etcd
[reset] Reading configuration from the "kubeadm-config" ConfigMap in namespace "kube-system"...
[reset] Use 'kubeadm init phase upload-config kubeadm --config your-config-file' to re-upload it.
W1114 17:16:23.883932   17975 reset.go:141] [reset] Unable to fetch the kubeadm-config ConfigMap from cluster: failed to get config map: Get "https://192.168.88.194:6443/api/v1/namespaces/kube-system/configmaps/kubeadm-config?timeout=10s": dial tcp 192.168.88.194:6443: connect: connection refused
[preflight] Running pre-flight checks
W1114 17:16:23.884022   17975 removeetcdmember.go:105] [reset] No kubeadm config, using etcd pod spec to get data directory
[reset] Deleted contents of the etcd data directory: /var/lib/etcd
[reset] Stopping the kubelet service
[reset] Unmounting mounted directories in "/var/lib/kubelet"
[reset] Deleting contents of directories: [/etc/kubernetes/manifests /var/lib/kubelet /etc/kubernetes/pki]
[reset] Deleting files: [/etc/kubernetes/admin.conf /etc/kubernetes/super-admin.conf /etc/kubernetes/kubelet.conf /etc/kubernetes/bootstrap-kubelet.conf /etc/kubernetes/controller-manager.conf /etc/kubernetes/scheduler.conf]
The reset process does not perform cleanup of CNI plugin configuration,
network filtering rules and kubeconfig files.
For information on how to perform this cleanup manually, please see:
    https://k8s.io/docs/reference/setup-tools/kubeadm/kubeadm-reset/
Enter fullscreen mode Exit fullscreen mode

Then again run the kubeadm init:

sudo kubeadm init --pod-network-cidr=192.168.88.0/24
Enter fullscreen mode Exit fullscreen mode

6. Configure kubectl Access

If running 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
Enter fullscreen mode Exit fullscreen mode

If root:

export KUBECONFIG=/etc/kubernetes/admin.conf
Enter fullscreen mode Exit fullscreen mode

7. Install a CNI Plugin

Without a CNI, the node will remain NotReady.

Option A : Flannel

kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml
Enter fullscreen mode Exit fullscreen mode

Option B : Calico (recommended)

kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.28.0/manifests/calico.yaml
Enter fullscreen mode Exit fullscreen mode

Check node and pod status:

kubectl get nodes
kubectl get pods -n kube-system
Enter fullscreen mode Exit fullscreen mode

8. Join Worker Nodes

Run this command on each worker node:

kubeadm join 192.168.88.194:6443 --token <token> \
  --discovery-token-ca-cert-hash sha256:<hash>
Enter fullscreen mode Exit fullscreen mode

9. Troubleshooting

Issue 1 — Node NotReady

Reason: KubeletNotReady
Message: container runtime network not ready: CNI plugin not initialized
Enter fullscreen mode Exit fullscreen mode

Fix: Install CNI (Flannel or Calico).

Then remove the taint:

kubectl taint nodes kubeadm node.kubernetes.io/not-ready:NoSchedule-
Enter fullscreen mode Exit fullscreen mode

Issue 2 — CoreDNS Pending / Network Not Ready

If coredns pod is stuck in Pending:

Warning  NetworkNotReady: CNI plugin not initialized
Enter fullscreen mode Exit fullscreen mode

Fix:

kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.28.0/manifests/calico.yaml
Enter fullscreen mode Exit fullscreen mode

Then verify:

kubectl get pods -n kube-system -w
Enter fullscreen mode Exit fullscreen mode

Example output:

calico-kube-controllers-6c77f9c4cc-ctnph   1/1   Running   0   97s
calico-node-qdkqx                          1/1   Running   0   97s
coredns-66bc5c9577-trq46                   1/1   Running   0   10m
Enter fullscreen mode Exit fullscreen mode

Your Kubernetes cluster is now up and running!

You can deploy workloads, monitor nodes, and manage your cluster using:

kubectl get nodes
kubectl get pods
Enter fullscreen mode Exit fullscreen mode

Output

root@kubeadm:/home/ubuntu# kubectl get nodes
NAME      STATUS   ROLES           AGE   VERSION
kubeadm   Ready    control-plane   12m   v1.34.2
Enter fullscreen mode Exit fullscreen mode
root@kubeadm:/home/ubuntu# kubectl get pods -n kube-system
NAME                                       READY   STATUS    RESTARTS   AGE
calico-kube-controllers-6c77f9c4cc-ctnph   1/1     Running   0          97s
calico-node-qdkqx                          1/1     Running   0          97s
coredns-66bc5c9577-trq46                   1/1     Running   0          10m
coredns-66bc5c9577-w4wnh                   1/1     Running   0          10m
etcd-kubeadm                               1/1     Running   25         10m
kube-apiserver-kubeadm                     1/1     Running   23         10m
kube-controller-manager-kubeadm            1/1     Running   25         10m
kube-proxy-2nh4w                           1/1     Running   0          10m
kube-scheduler-kubeadm                     1/1     Running   24         10m
Enter fullscreen mode Exit fullscreen mode

Done kubeadm running perfect. kubeadm is the easiest, safest, and most recommended way to create a Kubernetes cluster built and maintained by the Kubernetes project itself.

Note: This is more of a guideline document, so there’s no exact solution. You’ll need to follow the process step by step and check the flow as you go.

Top comments (0)