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