Running Kubernetes on Red Hat Enterprise Linux (RHEL) is a common requirement in enterprise environments, especially in regulated industries where stability, security, and support matter.
This guide walks through how to set up a Kubernetes cluster on RHEL 9.7, using a multi-node architecture suitable for production workloads.
Architecture Overview
A typical production setup includes:
- Control Plane Nodes (3)
- API server
- scheduler
- controller manager
etcd (stacked or external)
Worker Nodes
run application workloads
Load Balancer (recommended)
provides a single endpoint for the API server
This design ensures:
- high availability
- fault tolerance
- scalability
System Requirements
Each node should have:
- RHEL 9.7 installed
- at least 2 CPUs (4+ recommended)
- 4GB RAM minimum (8GB+ recommended)
- stable network connectivity
- unique hostname
Step 1: Disable Swap
Kubernetes requires swap to be disabled.
sudo swapoff -a
Remove it permanently:
sudo sed -i '/swap/d' /etc/fstab
Verify
free -h
swapon --show
Step 2: Configure Kernel Modules and Networking
Enable required modules:
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF
sudo modprobe overlay
sudo modprobe br_netfilter
Set sysctl parameters:
cat <<EOF | sudo tee /etc/sysctl.d/99-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 3: Configure Hostname and Hosts File
Set hostnames on each node:
hostnamectl set-hostname <node-name>
Update /etc/hosts on all nodes:
<IP> controlplane1
<IP> controlplane2
<IP> controlplane3
<IP> worker1
<IP> worker2
This helps with internal name resolution.
Step 4: Install Container Runtime (containerd)
Kubernetes no longer supports Docker directly as a runtime. Use containerd.
Install:
sudo dnf install -y containerd
Generate default config:
sudo mkdir -p /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml
Enable systemd cgroup driver:
Edit:
sudo vi /etc/containerd/config.toml
Set
SystemdCgroup = true
Restart
sudo systemctl restart containerd
sudo systemctl enable containerd
Step 5: Install Kubernetes Components
Add Kubernetes repo:
cat <<EOF | sudo tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://pkgs.k8s.io/core:/stable:/v1.29/rpm/
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://pkgs.k8s.io/core:/stable:/v1.29/rpm/repodata/repomd.xml.key
EOF
Install:
sudo dnf install -y kubelet kubeadm kubectl
Enable kubelet:
sudo systemctl enable kubelet
Step 6: Initialize the Control Plane
Run on the first control plane node:
sudo kubeadm init \
--control-plane-endpoint "<LOAD_BALANCER_DNS>:6443" \
--upload-certs
If no load balancer exists, you can temporarily use the first node’s IP.
After initialization:
mkdir -p $HOME/.kube
sudo cp /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
Verify:
kubectl get nodes
Step 7: Join Additional Control Plane Nodes
Use the join command generated from kubeadm init, including:
- token
- discovery token CA cert hash
- certificate key Example:
kubeadm join <endpoint>:6443 \
--token <token> \
--discovery-token-ca-cert-hash sha256:<hash> \
--control-plane \
--certificate-key <key>
Step 8: Join Worker Nodes
Run on each worker:
kubeadm join <endpoint>:6443 \
--token <token> \
--discovery-token-ca-cert-hash sha256:<hash>
Step 9: Install CNI (Networking)
Without a CNI plugin, pods cannot communicate.
Popular options:
- Calico
- Cilium
- Flannel Example using Calico:
kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml
Verify:
kubectl get pods -n kube-system
Step 10: Remove Control Plane Taints (Optional for testing)
By default, control planes don’t run workloads.
For lab/testing:
kubectl taint nodes --all node-role.kubernetes.io/control-plane-
For production, leave taints in place.
Step 11: Verify Cluster Health
kubectl get nodes
kubectl get pods -A
kubectl cluster-info
All nodes should be Ready.
Step 12: Add Load Balancer for Services (Optional)
For on-prem environments, you can use:
- MetalLB
- HAProxy + Keepalived
- external hardware load balancer MetalLB allows you to assign IPs to services of type LoadBalancer.
Common Pitfalls
- Swap not disabled
Cluster will fail to initialize.
- Wrong cgroup driver
Mismatch between containerd and kubelet causes instability.
- Firewall issues
Ensure required ports are open between nodes.
- Missing CNI
Pods will remain in Pending.
- kubeconfig not set
You’ll see errors like:
connection refused to localhost:8080
Production Considerations
For a real-world deployment:
- use a load balancer for API server
- separate etcd if scale increases
- implement monitoring (Prometheus, Grafana)
- enable logging aggregation
- enforce RBAC policies
- use TLS everywhere
- implement backup strategy for etcd
Conclusion
Setting up Kubernetes on RHEL 9.7 gives you:
- enterprise-grade stability
- full control over infrastructure
- flexibility for hybrid or on-prem environments
The key is not just getting the cluster running, but designing it for:
- resilience
- observability
- security
- scalability Once the foundation is solid, you can confidently run critical workloads on top of it.
Top comments (0)