# Installing Kubernetes with kubeadm

> Chapter 2 of the Courseiva CNCF-CKA curriculum — https://courseiva.com/learn/cncf-cka/installing-kubernetes-with-kubeadm

**Official objective:** Cluster Architecture, Installation & Configuration - 25% — Install a Kubernetes cluster using kubeadm.

## Introduction

How do you take a handful of Ubuntu servers and turn them into a fully functioning Kubernetes cluster without insane manual effort? This is the core problem that kubeadm solves, and installing Kubernetes with kubeadm is a required skill for the Certified Kubernetes Administrator (CKA) exam. Mastering this means you can set up a production-ready or exam-lab cluster from scratch, which directly tests your understanding of control plane and worker node architecture.

## The Catering for a Major Conference Analogy

Ever planned a large catering event for a conference? You have a head chef and a team of sous-chefs, each responsible for a different station: one handles appetisers, another mains, a third desserts. Each station has its own prep table, its own ingredients, and its own serving area. But they all need to be coordinated so that every guest receives a consistent, high-quality meal from any station they visit.

Now, imagine the head chef says, 'We need to set up the conference hall first. We'll use a standardised catering system called kubeadm.' Kubeadm is like a catering blueprint. You, the event organiser, feel daunted by the logistics of turning an empty hall into a fully operational food service. Kubeadm handles the heavy lifting: it installs the industrial fridges, sets the piping for the soda fountains, and pre-configures each station's equipment so they can communicate with each other.

The head chef becomes the 'control plane', the central brain. The sous-chefs become 'worker nodes'. Kubeadm is the tool that wires their stations together, ensuring the appetiser station knows how to hand off a plate to the mains station. Without kubeadm, you'd be manually running cables, configuring gas lines, and testing each station individually. With kubeadm, you run a single command and the blueprint is applied, the hall is built, and the catering system is ready. It’s not about cooking the food yet — it’s about getting the kitchen ready.

## Core explanation

Let’s break down what 'Installing Kubernetes with kubeadm' really means. First, understand that Kubernetes is a system for running containerised applications across multiple machines. Those machines are called 'nodes'. One special node, the 'control plane', manages the whole show. The other nodes, called 'worker nodes', actually run your applications.

Before you can use Kubernetes, you have to install it. That’s the 'bootstrapping' process. Kubeadm is a tool created by the Kubernetes community specifically to make this bootstrapping process standardised and reliable. It does not replace the need for a container runtime — you still need Docker or containerd installed. It also does not replace networking — you still need to install a 'Container Network Interface' (CNI) plugin like Calico or Flannel to let pods communicate across nodes.

Here’s what happens when you use kubeadm. You start by preparing your machines. You need a Linux system — usually Ubuntu or CentOS. You must ensure each machine has a unique hostname, MAC address, and product_uuid. You must also install a container runtime on every node. Then you run 'kubeadm init' on the control plane node. This command does several things:

- It runs a series of pre-flight checks to make sure your system is ready (like checking if ports are open, swap is disabled, and the container runtime is running).
- It generates a Certificate Authority (CA) to secure communication between components.
- It sets up the 'etcd' key-value store, which is the brain’s memory, storing all cluster data.
- It deploys the control plane components: the API server, the controller manager, and the scheduler.
- It creates a 'kubeconfig' file (admin.conf) that lets you control the cluster using 'kubectl'.
- It generates a join token and a command that you run on the worker nodes to attach them to the cluster.

After 'kubeadm init' finishes, you must set up networking by installing a CNI plugin. Without this, pods cannot talk to each other. Then you run 'kubeadm join' on each worker node, passing the token and the control plane’s IP address. This command configures the worker node to connect to the control plane securely.

Why does kubeadm exist? Before kubeadm, setting up Kubernetes was extremely manual and error-prone. You had to individually download each component, configure TLS certificates, set up etcd manually, and figure out how to restart services. Kubeadm automates this, providing a 'batteries included but swappable' approach. It’s the recommended way to create a production-like cluster for learning, testing, or even production use, though for massive scale you might use tools like kOps or AWS EKS.

For the CKA exam, you must know the exact commands: 'kubeadm init', 'kubeadm join', 'kubeadm reset', and 'kubeadm token'. You must also know the typical phases: pre-flight, certificate generation, control plane static pod manifests, bootstrap tokens, and CNI installation. The exam expects you to create a multi-node cluster from scratch using these tools.

## Real-world context

Let’s walk through a realistic scenario. You work for a startup called 'PixiePay', and you need to deploy a new microservices-based payment system. Your CTO says, 'We need a Kubernetes cluster in our own data centre for compliance reasons, not the cloud.' You have three physical servers each with 16 GB RAM and 4 vCPUs. They all run Ubuntu 22.04. You need to turn these into a three-node Kubernetes cluster: one control plane, two workers.

Here is exactly what an IT professional does:

- Ensure all nodes have Docker installed and swap is disabled. Disabling swap is critical; Kubernetes scheduler assumes it can rely on memory limits, and swap breaks that assumption.
- On the control plane node, SSH in and run 'kubeadm init --pod-network-cidr=192.168.0.0/16'. The CIDR specifies the IP range for pods. Calico requires that particular range.
- After the command succeeds, copy the admin.conf file to your local machine so you can run 'kubectl' from your laptop. You set 'KUBECONFIG' environment variable to point to it.
- Install Calico by running 'kubectl create -f calico.yaml'. This command applies the network plugin.
- View the join token from the output of 'kubeadm init'. That token looks like 'abc123.def456ghi789'. You also see a hash for discovery.
- On each worker node, run the join command: 'kubeadm join <control-plane-ip>:6443 --token abc123.def456ghi789 --discovery-token-ca-cert-hash sha256:...'.
- Validate by running 'kubectl get nodes' on the control plane. You see all three nodes listed as 'Ready'.

Now PixiePay has a functional cluster. The IT pro then installs an ingress controller, sets up persistent storage with NFS, and deploys their microservices. The key real-world challenge is that tokens expire after 24 hours. So if you need to add a worker later, you must create a new token with 'kubeadm token create'. Also, if a node goes down and comes back with a new hostname, the join process fails. In production, you would automate the join using configuration management tools like Ansible. Another real-world issue is that the control plane itself can become a single point of failure, so for production you would set up a 'stacked etcd' topology with three control plane nodes, each running its own etcd member, all joining using 'kubeadm init' with an external load balancer IP.

## Exam focus

The CKA exam does not ask you to 'explain kubeadm' in an essay format. Instead, you must perform tasks. You will be given access to one or more virtual machines (VMs) and asked to set up a cluster or troubleshoot an existing one. Here is exactly what you need to know.

Question types that appear:

- Create a Kubernetes cluster using kubeadm on given nodes. You will receive the hostnames and IPs. You must run 'kubeadm init' on the control plane and 'kubeadm join' on workers.
- Add a new worker node to an existing cluster. You will have a control plane already running, and you must find or generate the join token, then run the join command.
- Upgrade the cluster using 'kubeadm upgrade'. For example, from version 1.27 to 1.28. You need to know 'kubeadm upgrade plan' and 'kubeadm upgrade apply'.
- Initialise the cluster with a specific pod network CIDR or API server endpoint. They may give constraints like 'use 10.244.0.0/16 for pod network'.
- Troubleshoot a cluster that is not ready. Nodes may show 'NotReady', and you must check if the CNI plugin is installed or if swap is enabled.

Common traps and patterns:

- They will never give you the full command string. You must know the syntax, especially the '--pod-network-cidr' flag. Many candidates forget it and then the nodes stay 'NotReady' because no network plugin works correctly.
- They love to test 'kubeadm token create --print-join-command'. This prints a full join command with token and hash. If you don't rememeber this, you might waste time manually hashing the CA cert.
- They sometimes set up a cluster and then destroy the admin.conf file. You must know how to regenerate it using 'kubeadm init phase kubeconfig admin' or copy from the control plane.
- They often test 'kubeadm reset' to teardown a node so it can rejoin. You need to know that 'kubeadm reset' cleans up etcd data and removes the node from the cluster.
- They may disable swap or expect you to check it with 'free -h' or 'swapon --show'.

Key concepts to memorise:

- 'kubeadm init' phases: preflight, kubelet-start, certs, control-plane, etcd-local, wait-control-plane, etc.
- The kubelet is the 'node agent' that kubeadm configures. You must ensure it is running ('systemctl status kubelet').
- The admin.conf file lives in /etc/kubernetes/ on the control plane.
- Pod network CIDR must not overlap with host network or service CIDR.
- The core DNS add-on is automatically deployed by kubeadm; if it's not running, check pods in kube-system namespace.

## Step by step

1. **Prepare the nodes** — Ensure every machine has a unique hostname, correct MAC and product_uuid, and a supported container runtime (e.g., containerd). Disable swap using 'swapoff -a' and edit /etc/fstab to keep it off. Install kubeadm, kubelet, and kubectl using the official package repositories.
2. **Initialise the control plane** — On the control plane node, run 'sudo kubeadm init --pod-network-cidr=<CIDR>'. The CIDR depends on your chosen CNI (Calico uses 192.168.0.0/16). This command sets up etcd, the API server, controller manager, and scheduler as static pods.
3. **Set up kubectl access** — Copy the admin.conf file to your user's .kube directory: 'mkdir -p $HOME/.kube && sudo cp /etc/kubernetes/admin.conf $HOME/.kube/config && sudo chown $(id -u):$(id -g) $HOME/.kube/config'. Now you can run 'kubectl get nodes' from this machine.
4. **Install a CNI plugin** — Without a network plugin, pods cannot communicate. Apply a CNI manifest like Calico: 'kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml'. Wait for the calico pods to become 'Running' in the kube-system namespace.
5. **Join worker nodes** — On each worker node, run the join command from the init output: 'sudo kubeadm join <control-plane-ip>:6443 --token <token> --discovery-token-ca-cert-hash sha256:<hash>'. If the token expired, generate a new one with 'kubeadm token create --print-join-command' on the control plane.
6. **Verify the cluster** — Run 'kubectl get nodes' and ensure all nodes show 'Ready'. Run 'kubectl get pods -n kube-system' to confirm core DNS and CNI pods are running. You now have a functional Kubernetes cluster.

## Comparisons

### kubeadm init vs kubeadm join

**kubeadm init:**
- Runs on the control plane node
- Creates the cluster from scratch
- Sets up etcd, API server, etc.

**kubeadm join:**
- Runs on each worker node
- Attaches the node to an existing cluster
- Does not create etcd or control plane components

### Control plane node vs Worker node

**Control plane node:**
- Runs etcd, API server, scheduler, controller manager
- Acts as the cluster brain
- Often tainted to prevent app scheduling by default

**Worker node:**
- Runs only kubelet and kube-proxy
- Runs application pods
- No brain components

### Static pod manifests vs Standard pods

**Static pod manifests:**
- Placed in /etc/kubernetes/manifests by kubeadm
- Managed directly by kubelet, not API server
- Used for control plane components

**Standard pods:**
- Created via kubectl or API
- Managed by the scheduler
- Used for user applications

### kubeadm reset vs kubeadm upgrade

**kubeadm reset:**
- Tears down a cluster or node
- Removes etcd data and kubelet config
- Use to cleanly rejoin a node

**kubeadm upgrade:**
- Updates cluster version
- Requires draining nodes first
- Uses 'kubeadm upgrade plan' then 'apply'

## Diagram

_Flowchart showing the steps from node preparation to cluster completion using kubeadm._

```mermaid
flowchart TD
    A[Ubuntu Nodes] --> B{Install prerequisites}
    B --> C[Container Runtime (containerd)]
    B --> D[Kubeadm, Kubelet, Kubectl]
    B --> E[Disable Swap]
    C --> F[Control Plane: kubeadm init]
    D --> F
    E --> F
    F --> G[Admin.conf]
    G --> H[kubectl access]
    H --> I[Install CNI plugin]
    F --> J[Generate join token]
    J --> K[Worker nodes: kubeadm join]
    I --> L[Full cluster ready]
```

## Common misconceptions

- **Misconception:** Kubeadm installs everything including a container runtime like Docker. **Reality:** Kubeadm only installs Kubernetes components. You must still install Docker, containerd, or another CRI-compliant runtime separately on every node. (Beginners think kubeadm is an all-in-one installer because the official guides often include both steps together.)
- **Misconception:** After 'kubeadm init', the cluster is fully functional with networking. **Reality:** You must still install a Container Network Interface (CNI) plugin like Calico or Flannel after init. Without it, pods cannot communicate, and the core DNS will stay 'Pending'. (The init command prints a message about deploying a pod network, making beginners assume it’s included.)
- **Misconception:** You can join worker nodes to the cluster using the same token indefinitely. **Reality:** Bootstrap tokens expire after 24 hours by default. You must create a new token with 'kubeadm token create' if the original expires or is lost. (Many candidates copy the token from the init output hours later and wonder why the join fails.)
- **Misconception:** Kubeadm is only for test labs, not for production. **Reality:** Kubeadm is officially supported for production clusters. Major companies use it with stacked etcd control planes and external load balancers. (The misconception comes from its simplicity; people assume production tools must be complex like kOps or EKS.)

## Key takeaways

- Kubeadm automates the bootstrapping of a Kubernetes cluster, but it does not replace the need for a container runtime or a network plugin.
- Run 'kubeadm init --pod-network-cidr=192.168.0.0/16' on the control plane, then install a CNI like Calico before joining workers.
- Worker nodes are joined using 'kubeadm join' with a bootstrap token, which expires after 24 hours unless extended.
- The admin.conf file lives at /etc/kubernetes/admin.conf and grants full cluster admin access via kubectl.
- Swap must be disabled on all nodes; the kubelet will not work correctly if swap is enabled.
- Always run 'kubeadm reset' to tear down a node cleanly before rejoining it to the cluster.

## FAQ

**What is the difference between kubeadm, kubelet, and kubectl?**

Kubeadm is the tool to bootstrap the cluster, kubelet is the node agent that runs on every node and manages pods, and kubectl is the command-line client to control the cluster. You install all three but use them differently.

**Do I need to install Docker if I use kubeadm?**

Yes, you need a container runtime. Docker is common, but containerd or CRI-O also work. Kubeadm does not install the runtime; you must install it separately on every node.

**Why do my nodes stay 'NotReady' after joining?**

This usually means the CNI plugin is not installed or configured. Install a network plugin like Calico or Flannel. Also check that swap is disabled on all nodes.

**How long does the bootstrap token last?**

By default, 24 hours. If you need to join a new node after that, create a fresh token with 'kubeadm token create --print-join-command' on the control plane.

**Can I use kubeadm for a single-node cluster?**

Yes. During init, you can add 'kubeadm init --pod-network-cidr=10.244.0.0/16' and then remove the taint on the control plane to allow scheduling pods on it using 'kubectl taint nodes --all node-role.kubernetes.io/control-plane-'.

**What if kubeadm init fails?**

Check the pre-flight error messages. Common causes: swap is still on, container runtime not running, or required ports (6443, 10250) are in use. Run 'kubeadm reset' before retrying.

## Check your understanding

1. **What command initialises a control plane node with a specific pod network CIDR of 10.244.0.0/16?**

   Answer: sudo kubeadm init --pod-network-cidr=10.244.0.0/16

2. **What must you install after running kubeadm init to allow pod-to-pod communication?**

   Answer: A Container Network Interface (CNI) plugin such as Calico or Flannel.

3. **On which node should you run 'kubeadm join'?**

   Answer: On each worker node that needs to be added to the cluster.

4. **What command generates a new bootstrap token and prints the full join command?**

   Answer: kubeadm token create --print-join-command

5. **What does 'kubeadm reset' do?**

   Answer: It cleans up the node's configuration and removes it from the cluster, allowing it to be rejoined or reused.

---

Interactive version with quiz and diagrams: https://courseiva.com/learn/cncf-cka/installing-kubernetes-with-kubeadm
