Tuesday, 14 July 2026

Kubernetes cluster setup on Ubuntu 26.04 using Kubeadm

Step1: Disable swap memory: Kubernetes requires swap to be disabled for the kubelet to function correctly

# swapoff -a

# sudo sed -i '/ swap / s/^/#/' /etc/fstab


This disables swap immediately and make this change permanent


Step2: Load required kernel modules: Enable the overlay and br_netfilter modules needed for container networking

# cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf

overlay

br_netfilter

EOF


Run the following commands to load the modules

# modprobe overlay

# modprobe br_netfilter


These modules enable overlay networking and bridge netfilter functionality required by Kubernetes networking.


Step3: Configure sysctl parameters: Set kernel parameters for Kubernetes networking


# cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf

net.bridge.bridge-nf-call-iptables  = 1

net.bridge.bridge-nf-call-ip6tables = 1

net.ipv4.ip_forward                 = 1

EOF

# sysctl --system

These settings enable iptables to process bridged traffic and allow IP forwarding between network interfaces.


Step4: Verify prerequisites: Confirm all settings are correctly applied

# free -h | grep -i swap && lsmod | grep -E "overlay|br_netfilter" && sysctl net.ipv4.ip_forward

Swap should show 0B, both kernel modules should be listed, and ip_forward should equal 1.


Step5: Install Container Runtime

Kubernetes requires a container runtime to run containers. Ubuntu 26.04 includes containerd in its default repositories, which is the recommended runtime for Kubernetes deployments.


Install containerd: Install the container runtime from Ubuntu repositories

# apt update && apt install containerd -y


Generate default configuration: Create the containerd configuration directory and generate a default config file

# mkdir -p /etc/containerd

# containerd config default | sudo tee /etc/containerd/config.toml


Step6: Enable SystemdCgroup: Configure containerd to use systemd as the cgroup driver, which is required for Kubernetes

# sed -i 's/SystemdCgroup = false/SystemdCgroup = true/g' /etc/containerd/config.toml

This ensures containerd and kubelet use the same cgroup driver, preventing resource management conflicts.


Restart containerd: Apply the configuration changes

# systemctl restart containerd

# systemctl enable containerd


Step7: Install Kubernetes Components on Ubuntu 26.04

With the container runtime configured, you can now install the core Kubernetes components. The installation requires adding the official Kubernetes package repository to your system.


Install required packages: Install dependencies needed to add the Kubernetes repository

# apt install apt-transport-https ca-certificates curl gnupg conntrack -y


Add Kubernetes GPG key: Download and install the repository signing key

# curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.36/deb/Release.key | sudo gpg --dearmor --yes -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg

This key verifies the authenticity of packages downloaded from the Kubernetes repository.


Add Kubernetes repository: Add the official Kubernetes apt repository

# echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.36/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list


Install Kubernetes packages: Update package lists and install kubeadm, kubelet, and kubectl

# apt update && apt install kubelet kubeadm kubectl -y


Hold packages: Prevent automatic upgrades that could break your cluster

# apt-mark hold kubelet kubeadm kubectl

Holding these packages ensures version consistency across your cluster and prevents unintended upgrades during system updates.



Step8: Initialize the Kubernetes Cluster

Now you can initialize your Kubernetes cluster using kubeadm. This process creates the control plane components and configures the cluster for operation.


Initialize the cluster: Run kubeadm init with the pod network CIDR

# kubeadm init --pod-network-cidr=10.244.0.0/16

The --pod-network-cidr flag specifies the IP address range for pod networking. The value 10.244.0.0/16 is compatible with Flannel, which we will install in the next section.


Sample output after the "kubeadm init"

-----------------

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.192.134:6443 --token gh7gno.yworbsfmf69g12g2 \

        --discovery-token-ca-cert-hash sha256:1bd571d1a1993841478caf85a7f150100daa5062ddb00f05b8f4c8d3f67c7ace

-----------------


Configure kubectl for your user: Set up kubectl access for the regular user. Run the following command as the regular user

$ mkdir -p $HOME/.kube

$ cp -i /etc/kubernetes/admin.conf $HOME/.kube/config

$ sudo chown $(id -u):$(id -g) $HOME/.kube/config


These commands copy the cluster admin configuration to your home directory and set proper ownership, allowing you to run kubectl commands without sudo.


Remove control plane taint (single-node only): Allow scheduling pods on the control plane node

$ kubectl taint nodes --all node-role.kubernetes.io/control-plane-


By default, Kubernetes prevents workloads from running on control plane nodes. For a single-node development cluster, removing this taint allows pods to be scheduled on the only available node.


Step9: Install Network Plugin

A pod network plugin is required for pods to communicate with each other across the cluster. Flannel is a simple and reliable choice that works well for most deployments.


$ kubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml


This command downloads and applies the Flannel configuration, creating the necessary DaemonSet and ConfigMap resources


Verify network plugin deployment: Check that Flannel pods are running

$ kubectl get pods -n kube-flannel

Wait until all Flannel pods show a Running status before proceeding.


Verify Kubernetes Installation on Ubuntu 26.04

Check node status: Verify the node is ready

$ kubectl get nodes


Output should show your node with STATUS “Ready”. If the status shows “NotReady”, wait a few moments for the network plugin to initialize.


Check system pods: Verify all Kubernetes system components are running

$ kubectl get pods -n kube-system


All pods should show Running or Completed status.


Step10: Deploy a test application: Create a test pod to verify the cluster accepts workloads

$ kubectl run nginx --image=nginx --port=80

$ kubectl get pods


The nginx pod should transition to Running status within a minute, confirming that your cluster can pull images and schedule pods.



Accessing the nginx webserver outside the cluster for a local development setup

If you are running on-premises or using a local setup like Minikube/Kind where cloud load balancers aren't available, NodePort service is your go-to.


How it works:

Kubernetes opens a specific port (by default, in the high range of 30000–32767) on every single node (machine) in your cluster. Any traffic hitting that port on any node's IP address will be forwarded to your Nginx web server.


Label nginx pod so that it can be selected in service manifest for the pod discovery

$ kubectl label pod nginx app=nginx-webserver


vi nginx-nodeport.yaml

apiVersion: v1

kind: Service

metadata:

  name: nginx-nodeport

spec:

  type: NodePort

  selector:

    app: nginx-webserver

  ports:

    - protocol: TCP

      port: 80

      targetPort: 80

      nodePort: 32080 # Optional: Specify a port in the 30000-32767 range


$ kubectl apply -f nginx-nodeport.yaml

$ kubectl get service 

NAME             TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE

nginx-nodeport   NodePort   10.101.244.247   <none>        80:32080/TCP   18m


Find the nodes IP address and access over the browser as http://NODE_IP_ADDRESS:32080

Sample output:







Kubernetes cluster setup on Ubuntu 26.04 using Kubeadm

Step1: Disable swap memory: Kubernetes requires swap to be disabled for the kubelet to function correctly # swapoff -a # sudo sed -i '/...