DEV Community

Falolu Olaitan
Falolu Olaitan

Posted on

Setting Up a Production-Ready Kubernetes Cluster on RHEL 9.7

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:

  1. Control Plane Nodes (3)
  2. API server
  3. scheduler
  4. controller manager
  5. etcd (stacked or external)

  6. Worker Nodes

  7. run application workloads

  8. Load Balancer (recommended)

  9. 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
Enter fullscreen mode Exit fullscreen mode

Remove it permanently:

sudo sed -i '/swap/d' /etc/fstab
Enter fullscreen mode Exit fullscreen mode

Verify

free -h
swapon --show
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Step 3: Configure Hostname and Hosts File

Set hostnames on each node:

hostnamectl set-hostname <node-name>
Enter fullscreen mode Exit fullscreen mode

Update /etc/hosts on all nodes:

<IP> controlplane1
<IP> controlplane2
<IP> controlplane3
<IP> worker1
<IP> worker2
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Generate default config:

sudo mkdir -p /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml
Enter fullscreen mode Exit fullscreen mode

Enable systemd cgroup driver:

Edit:

sudo vi /etc/containerd/config.toml
Enter fullscreen mode Exit fullscreen mode

Set

SystemdCgroup = true
Enter fullscreen mode Exit fullscreen mode

Restart

sudo systemctl restart containerd
sudo systemctl enable containerd
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Install:

sudo dnf install -y kubelet kubeadm kubectl
Enter fullscreen mode Exit fullscreen mode

Enable kubelet:

sudo systemctl enable kubelet
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Verify:

kubectl get nodes
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

Step 8: Join Worker Nodes

Run on each worker:

kubeadm join <endpoint>:6443 \
  --token <token> \
  --discovery-token-ca-cert-hash sha256:<hash>
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Verify:

kubectl get pods -n kube-system
Enter fullscreen mode Exit fullscreen mode

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-
Enter fullscreen mode Exit fullscreen mode

For production, leave taints in place.

Step 11: Verify Cluster Health

kubectl get nodes
kubectl get pods -A
kubectl cluster-info
Enter fullscreen mode Exit fullscreen mode

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

  1. Swap not disabled

Cluster will fail to initialize.

  1. Wrong cgroup driver

Mismatch between containerd and kubelet causes instability.

  1. Firewall issues

Ensure required ports are open between nodes.

  1. Missing CNI

Pods will remain in Pending.

  1. kubeconfig not set

You’ll see errors like:

connection refused to localhost:8080
Enter fullscreen mode Exit fullscreen mode

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)