This guide provides a comprehensive, step-by-step walkthrough on setting up a Kubernetes cluster using Kubeadm. It covers everything from preparing the nodes and installing the necessary components like Containerd, Kubeadm, Kubelet, and Kubectl, to initializing the control plane, joining worker nodes, and verifying the cluster setup. This guide is designed for both beginners and DevOps professionals who want to gain a deeper understanding of Kubernetes and its underlying infrastructure.
🚀 Introduction
Setting up a Kubernetes cluster from scratch might sound intimidating — but with Kubeadm, it becomes clean, predictable, and repeatable.
Unlike managed services like EKS, GKE, or AKS, Kubeadm gives you full control over your cluster’s infrastructure. You get to learn how Kubernetes works under the hood — the control plane, networking, certificates, and more.
In this tutorial, we’ll go step by step to build your own Kubernetes cluster using Kubeadm on Ubuntu 22.04.
By the end, you’ll have a fully working multi-node cluster ready for workloads — exactly like you’d run in a real-world DevOps setup. ⚙️

🧩 Prerequisites
Before we start, make sure you have:

We’ll use these hostnames for clarity:
master-node→ Control planeworker-node1→ Worker nodeworker-node2→ (optional)

⚙️ Step 1: Prepare All Nodes
Login to each node (master and workers) and run the following setup commands.
1.1 Update System
sudo apt update && sudo apt upgrade -y
1.2 Disable Swap
Kubernetes requires swap to be disabled.
sudo swapoff -a
sudo sed -i '/ swap / s/^/#/' /etc/fstab
1.3 Enable Required Kernel Modules
sudo modprobe overlay
sudo modprobe br_netfilter
1.4 Apply Network Settings
cat <<EOF | sudo tee /etc/sysctl.d/kubernetes.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF
sudo sysctl --system
🐋 Step 2: Install Container Runtime (Containerd)
Kubernetes needs a container runtime.
We’ll use containerd, the most recommended one (used by Docker and Kubernetes itself).
2.1 Install Dependencies
sudo apt install -y apt-transport-https ca-certificates curl gnupg lsb-release
2.2 Install Containerd
sudo apt install -y containerd
2.3 Configure Containerd
sudo mkdir -p /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml > /dev/null
Edit the config to use systemd as cgroup driver:
sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
Restart and enable containerd:
sudo systemctl restart containerd
sudo systemctl enable containerd
🧱 Step 3: Install Kubeadm, Kubelet, and Kubectl
Kubeadm will bootstrap your cluster, kubelet runs on all nodes, and kubectl is the CLI to manage it.
sudo apt update
sudo apt install -y apt-transport-https curl
sudo curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.30/deb/Release.key | sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/kubernetes.gpg
echo "deb https://pkgs.k8s.io/core:/stable:/v1.30/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
Check versions:
kubeadm version
kubectl version --client
🧠 Step 4: Initialize the Control Plane (Master Node)
Run this only on the master node:
sudo kubeadm init --pod-network-cidr=10.244.0.0/16
Tip:
The --pod-network-cidr flag depends on which network plugin (CNI) you plan to install.
- For Flannel → use
10.244.0.0/16 - For Calico → use
192.168.0.0/16
When initialization finishes, you’ll see a join command like this:
kubeadm join 10.0.0.1:6443 --token abcd12.efgh34ijkl56 --discovery-token-ca-cert-hash sha256:xxxx...
Save this — you’ll need it for worker nodes.
4.1 Configure kubectl Access
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
Now verify:
kubectl get nodes
You’ll see the master node in NotReady state — that’s because the CNI isn’t installed yet.
🌐 Step 5: Install a Pod Network Add-on (CNI)
Let’s use Flannel (simple and beginner-friendly).
kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml
Wait a minute, then check:
kubectl get pods -n kube-system
kubectl get nodes
Your master node should now be in Ready state. ✅
🧩 Step 6: Join Worker Nodes
Run this on each worker node, replacing the join command you got earlier:
sudo kubeadm join 10.0.0.1:6443 --token abcd12.efgh34ijkl56 --discovery-token-ca-cert-hash sha256:xxxx...
If you lost the token, create a new one:
sudo kubeadm token create --print-join-command
🧾 Step 7: Verify Your Cluster
On the master node:
kubectl get nodes
Output example:
NAME STATUS ROLES AGE VERSION
master-node Ready control-plane 10m v1.30.0
worker-node1 Ready <none> 5m v1.30.0
You now have a fully functional Kubernetes cluster! 🎉
🧰 Step 8: Deploy a Sample Application
Let’s verify the setup with an NGINX deployment:
kubectl create deployment nginx --image=nginx
kubectl expose deployment nginx --port=80 --type=NodePort
kubectl get pods,svc
Access via any worker node IP and the assigned NodePort.
🔐 Step 9: (Optional) Enable Cluster Access for Other Users
If you need to share access with teammates:
kubectl config view --flatten > cluster-config.yaml
They can use this kubeconfig file with restricted RBAC permissions.
🛠️ Troubleshooting Tips
| Issue | Solution |
|---|---|
| Node not joining | Check network/firewall between nodes |
| Pod stuck in Pending | Verify CNI (Flannel/Calico) is running |
| kubelet not starting | Recheck containerd config and systemd cgroups |
| DNS not resolving | Restart coredns and check kube-proxy logs |
🏁 Conclusion
And that’s it! You’ve successfully created a Kubernetes cluster using Kubeadm — the most powerful way to understand how Kubernetes actually works.
With this setup, you can:
- Practice real-world cluster administration
- Deploy monitoring (Prometheus/Grafana)
- Configure Ingress controllers
- Experiment with scaling, RBAC, and security policies
When you’re ready, you can even turn this into a highly available (HA) cluster by adding more control planes and etcd nodes.

🔖 Key Takeaways
- Kubeadm simplifies the setup but doesn’t abstract Kubernetes internals — you learn the real deal.
- Containerd is now the standard runtime for most clusters.
- CNI (Flannel, Calico) defines how pods communicate — choose wisely for production.
- Always disable swap and configure systemd cgroups.
- For production, enable audit logs, certificates, and backup automation.