Kubernetes is the industry-standard container orchestration platform for automating deployment, scaling, and management of containerised applications across clusters of servers. While Kubernetes is typically set up using managed services (EKS, GKE, AKS) in cloud environments, installing it with kubeadm on bare-metal or on-premises servers provides full control over the cluster configuration. kubeadm is the official Kubernetes cluster bootstrapping tool — it initialises the control plane, generates TLS certificates, configures kubeconfig files, and prints the exact command for joining worker nodes. This guide covers a single-node Kubernetes cluster installation on RHEL 9 using kubeadm, kubelet, and kubectl with containerd as the container runtime, which is the production-ready setup for on-premises RHEL deployments.
Prerequisites
- RHEL 9 with at least 2 CPUs and 2 GB RAM (control plane minimum)
- Unique hostname, MAC address, and product UUID across all nodes
Step 1 — System Preparation
# Disable swap (required by kubelet)
swapoff -a
sed -i '/swap/d' /etc/fstab
# Load required kernel modules
cat > /etc/modules-load.d/k8s.conf < /etc/sysctl.d/k8s.conf <<EOF
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF
sysctl --system
Step 2 — Install containerd
# Install containerd from Docker's repository
dnf config-manager --add-repo https://download.docker.com/linux/rhel/docker-ce.repo
dnf install -y containerd.io
# Configure containerd with systemd cgroup driver (required for kubeadm)
containerd config default > /etc/containerd/config.toml
sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
systemctl enable --now containerd
Step 3 — Install kubeadm, kubelet, kubectl
# Add the Kubernetes repository (v1.31)
cat > /etc/yum.repos.d/kubernetes.repo <<EOF
[kubernetes]
name=Kubernetes
baseurl=https://pkgs.k8s.io/core:/stable:/v1.31/rpm/
enabled=1
gpgcheck=1
gpgkey=https://pkgs.k8s.io/core:/stable:/v1.31/rpm/repodata/repomd.xml.key
EOF
dnf install -y kubelet kubeadm kubectl
systemctl enable --now kubelet
Step 4 — Initialise the Control Plane
# Initialise the cluster (replace with your server's IP)
kubeadm init --pod-network-cidr=10.244.0.0/16 --apiserver-advertise-address=192.168.1.100
# Configure kubectl access for root
mkdir -p $HOME/.kube
cp /etc/kubernetes/admin.conf $HOME/.kube/config
# Verify control plane is up
kubectl get nodes
Step 5 — Install a Pod Network (Flannel)
# Install Flannel CNI network plugin
kubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml
# Wait for the node to become Ready
kubectl get nodes -w
# Allow scheduling on the control plane (single-node setup)
kubectl taint nodes --all node-role.kubernetes.io/control-plane-
# Verify all system pods are running
kubectl get pods -n kube-system
Conclusion
A single-node Kubernetes cluster installed with kubeadm on RHEL 9 provides a fully functional cluster for development and small production workloads. The three most common installation failures are: swap not disabled (kubelet refuses to start), the containerd cgroup driver not set to systemd (cluster initialises but pods fail to schedule), and missing SELinux accommodation for container workloads. For multi-node clusters, run the same Steps 1–3 on all worker nodes, then use the kubeadm join command printed at the end of kubeadm init to join workers to the cluster.
Next steps: How to Install k3s on RHEL 9, How to Install Helm on RHEL 9, and How to Deploy Applications to Kubernetes on RHEL 9.