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:
- Initializes the control plane — sets up the API server, controller manager, scheduler, and etcd.
- Generates certificates for secure communication between components.
- Configures kubelet to connect to the cluster.
- Sets up bootstrap tokens so worker nodes can join securely.
- 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:
- Install container runtime — containerd or CRI-O.
- Install kubeadm, kubelet, and kubectl.
- Run
**kubeadm init**to set up the control plane. - Run
**kubeadm join**on worker nodes to connect them. - 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
2. Install Container Runtime (containerd)
sudo apt update
sudo apt install -y containerd
Generate a default configuration:
sudo mkdir -p /etc/containerd
sudo containerd config default | sudo tee /etc/containerd/config.toml
Restart and enable containerd:
sudo systemctl restart containerd
sudo systemctl enable containerd
sudo systemctl status containerd
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
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
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
Install packages:
sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl
Enable kubelet:
sudo systemctl enable --now kubelet
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
Then initialize the control-plane:
sudo kubeadm init --pod-network-cidr=192.168.88.0/24
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
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
Then need to check the containerd
sudo journalctl -u containerd -b --no-pager | tail -n 200
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"
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
After that again run the kubeadm init
sudo kubeadm init --pod-network-cidr=192.168.88.0/24
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.
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"
Restart containerd:
sudo systemctl restart containerd
Re-run kubeadm:
sudo kubeadm init --pod-network-cidr=192.168.88.0/24
If not running the kubeadm then reset the kubeadm
sudo kubeadm reset -f
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/
Then again run the kubeadm init:
sudo kubeadm init --pod-network-cidr=192.168.88.0/24
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
If root:
export KUBECONFIG=/etc/kubernetes/admin.conf
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
Option B : Calico (recommended)
kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.28.0/manifests/calico.yaml
Check node and pod status:
kubectl get nodes
kubectl get pods -n kube-system
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>
9. Troubleshooting
Issue 1 — Node NotReady
Reason: KubeletNotReady
Message: container runtime network not ready: CNI plugin not initialized
Fix: Install CNI (Flannel or Calico).
Then remove the taint:
kubectl taint nodes kubeadm node.kubernetes.io/not-ready:NoSchedule-
Issue 2 — CoreDNS Pending / Network Not Ready
If coredns pod is stuck in Pending:
Warning NetworkNotReady: CNI plugin not initialized
Fix:
kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.28.0/manifests/calico.yaml
Then verify:
kubectl get pods -n kube-system -w
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
✅ 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
Output
root@kubeadm:/home/ubuntu# kubectl get nodes
NAME STATUS ROLES AGE VERSION
kubeadm Ready control-plane 12m v1.34.2
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
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)