AlmaLinux

Deploy HA Kubernetes Cluster on Rocky Linux 10 using RKE2

RKE2 (Rancher Kubernetes Engine 2) is a CNCF-certified Kubernetes distribution built by Rancher/SUSE. It combines the ease of deployment from K3s with close upstream Kubernetes alignment, and it does not depend on Docker – control plane components run as static pods managed by the kubelet. RKE2 is also known as “RKE Government” due to its focus on security and FIPS 140-2 compliance.

This guide walks through deploying a highly available RKE2 Kubernetes cluster on Rocky Linux 10 / AlmaLinux 10 with 3 server (control plane) nodes and 2 agent (worker) nodes. The latest stable RKE2 release at the time of writing is v1.35.1+rke2r1, which ships Kubernetes v1.35.1, etcd v3.6.7, and Containerd v2.1.5.

Prerequisites

  • 5 servers running Rocky Linux 10 or AlmaLinux 10 (3 server nodes + 2 agent nodes)
  • Minimum 4 GB RAM and 2 vCPUs per node (8 GB / 4 vCPUs recommended for server nodes)
  • Root or sudo access on all nodes
  • Network connectivity between all nodes on required ports (see firewall section)
  • A fixed registration address – either a load balancer, DNS round-robin, or VIP pointing to the server nodes

Cluster Node Layout

We use the following node layout for this HA RKE2 deployment on Rocky Linux 10:

RoleHostnameIP Address
Server Node 1server110.0.1.10
Server Node 2server210.0.1.11
Server Node 3server310.0.1.12
Agent Node 1agent110.0.1.20
Agent Node 2agent210.0.1.21

In this setup, server1 (10.0.1.10) serves as both the first server node and the fixed registration address. For production environments, place an Nginx load balancer in front of the Kubernetes API on ports 9345 and 6443.

Step 1: Prepare All Nodes

Run the following steps on all 5 nodes. Set the hostname on each node accordingly:

sudo hostnamectl set-hostname server1

Repeat with server2, server3, agent1, and agent2 on the respective nodes.

Add all cluster nodes to /etc/hosts on every node:

sudo vi /etc/hosts

Add the following entries:

10.0.1.10 server1
10.0.1.11 server2
10.0.1.12 server3
10.0.1.20 agent1
10.0.1.21 agent2

Install required packages:

sudo dnf -y install curl vim wget

Load the required kernel modules and make them persistent across reboots:

sudo modprobe br_netfilter
sudo modprobe overlay

Create a modules load file to persist them:

sudo vi /etc/modules-load.d/rke2.conf

Add the following content:

br_netfilter
overlay

Set the required sysctl parameters:

sudo vi /etc/sysctl.d/99-rke2.conf

Add these lines:

net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1

Apply the sysctl settings:

sudo sysctl --system

Step 2: Configure Firewall Rules for RKE2

RKE2 requires several ports to be open between cluster nodes. On all server nodes, open the following ports:

sudo firewall-cmd --permanent --add-port=6443/tcp
sudo firewall-cmd --permanent --add-port=9345/tcp
sudo firewall-cmd --permanent --add-port=10250/tcp
sudo firewall-cmd --permanent --add-port=2379-2380/tcp
sudo firewall-cmd --permanent --add-port=8472/udp
sudo firewall-cmd --permanent --add-port=4789/udp
sudo firewall-cmd --permanent --add-port=51820-51821/udp
sudo firewall-cmd --permanent --add-port=30000-32767/tcp
sudo firewall-cmd --permanent --add-masquerade
sudo firewall-cmd --reload

On all agent nodes, open these ports:

sudo firewall-cmd --permanent --add-port=10250/tcp
sudo firewall-cmd --permanent --add-port=8472/udp
sudo firewall-cmd --permanent --add-port=4789/udp
sudo firewall-cmd --permanent --add-port=51820-51821/udp
sudo firewall-cmd --permanent --add-port=30000-32767/tcp
sudo firewall-cmd --permanent --add-masquerade
sudo firewall-cmd --reload

Here is a summary of the required ports:

PortProtocolPurpose
6443TCPKubernetes API server
9345TCPRKE2 supervisor API (node registration)
10250TCPKubelet metrics
2379-2380TCPetcd client and peer communication
8472UDPCanal/Flannel VXLAN
4789UDPCalico VXLAN (if using Calico CNI)
51820-51821UDPCanal/Flannel WireGuard
30000-32767TCPNodePort services range

Step 3: Install RKE2 on the First Server Node

SSH into server1 (10.0.1.10) and download the RKE2 installer script:

curl -sfL https://get.rke2.io --output install.sh
chmod +x install.sh

Run the installer in server mode:

sudo INSTALL_RKE2_TYPE=server ./install.sh

Create the RKE2 configuration directory and config file:

sudo mkdir -p /etc/rancher/rke2
sudo vi /etc/rancher/rke2/config.yaml

Add the following configuration. The tls-san entries ensure the Kubernetes API certificate is valid for both the hostname and IP of the registration address:

write-kubeconfig-mode: "0644"
tls-san:
  - server1
  - 10.0.1.10

Enable and start the RKE2 server service:

sudo systemctl enable --now rke2-server

The first server node takes a few minutes to start as it bootstraps etcd and the control plane. Verify the service is running:

sudo systemctl status rke2-server

Retrieve the node token – you will need this to join additional server and agent nodes to the cluster:

sudo cat /var/lib/rancher/rke2/server/node-token

Save the output. It looks similar to this:

K1079187d01ac73b1a17261a475cb1b8486144543fc59a189e0c4533ef252a26450::server:33f5c1a2b7721992be25e340ded19cac

Step 4: Configure kubectl on the First Server

RKE2 installs its own kubectl binary under /var/lib/rancher/rke2/bin/. Add this to your PATH and set the kubeconfig environment variable. If you are familiar with kubectl commands and shortcuts, you can also set up shell aliases at this point.

sudo vi ~/.bashrc

Add these lines at the end of the file:

export PATH=$PATH:/var/lib/rancher/rke2/bin
export KUBECONFIG=/etc/rancher/rke2/rke2.yaml

Source the file to apply changes in the current session:

source ~/.bashrc

Verify the first node is ready:

kubectl get nodes

Expected output:

$ kubectl get nodes
NAME      STATUS   ROLES                       AGE   VERSION
server1   Ready    control-plane,etcd,master    2m    v1.35.1+rke2r1

Check that all system pods are running:

kubectl get pods -A

Step 5: Join Additional Server Nodes to the RKE2 Cluster

Run the following on server2 (10.0.1.11) and server3 (10.0.1.12). Download and run the RKE2 installer:

curl -sfL https://get.rke2.io --output install.sh
chmod +x install.sh
sudo INSTALL_RKE2_TYPE=server ./install.sh

Create the configuration file:

sudo mkdir -p /etc/rancher/rke2
sudo vi /etc/rancher/rke2/config.yaml

Add the following, replacing the token value with the one obtained from server1:

server: https://10.0.1.10:9345
token: K1079187d01ac73b1a17261a475cb1b8486144543fc59a189e0c4533ef252a26450::server:33f5c1a2b7721992be25e340ded19cac
write-kubeconfig-mode: "0644"
tls-san:
  - server1
  - 10.0.1.10

Enable and start the RKE2 server service. Join one server at a time – wait for each node to reach Ready status before starting the next one:

sudo systemctl enable --now rke2-server

After both additional server nodes have joined, verify from server1:

$ kubectl get nodes
NAME      STATUS   ROLES                       AGE   VERSION
server1   Ready    control-plane,etcd,master    10m   v1.35.1+rke2r1
server2   Ready    control-plane,etcd,master    5m    v1.35.1+rke2r1
server3   Ready    control-plane,etcd,master    2m    v1.35.1+rke2r1

All three server nodes are now part of the HA control plane with an embedded etcd cluster. The cluster can tolerate the loss of one server node and continue operating.

Step 6: Join Agent Nodes (Workers) to the Cluster

Run the following on agent1 (10.0.1.20) and agent2 (10.0.1.21). Download and run the installer in agent mode:

curl -sfL https://get.rke2.io --output install.sh
chmod +x install.sh
sudo INSTALL_RKE2_TYPE=agent ./install.sh

Create the agent configuration file:

sudo mkdir -p /etc/rancher/rke2
sudo vi /etc/rancher/rke2/config.yaml

Add the following configuration, using the same token from server1:

server: https://10.0.1.10:9345
token: K1079187d01ac73b1a17261a475cb1b8486144543fc59a189e0c4533ef252a26450::server:33f5c1a2b7721992be25e340ded19cac

Enable and start the RKE2 agent service:

sudo systemctl enable --now rke2-agent

Check the agent service status:

sudo systemctl status rke2-agent

After both agents join, verify the full cluster from server1:

$ kubectl get nodes
NAME      STATUS   ROLES                       AGE   VERSION
server1   Ready    control-plane,etcd,master    15m   v1.35.1+rke2r1
server2   Ready    control-plane,etcd,master    10m   v1.35.1+rke2r1
server3   Ready    control-plane,etcd,master    7m    v1.35.1+rke2r1
agent1    Ready    <none>                       3m    v1.35.1+rke2r1
agent2    Ready    <none>                       1m    v1.35.1+rke2r1

Step 7: Verify the RKE2 Kubernetes Cluster

Confirm all system pods are running across the cluster:

kubectl get pods -A

You should see pods for CoreDNS, the NGINX Ingress Controller, metrics-server, Canal CNI, and etcd running in the kube-system namespace. All pods should show Running or Completed status.

Check cluster component health:

kubectl cluster-info
kubectl get componentstatuses

Step 8: Access the Cluster from Outside

To manage the cluster from a workstation outside the cluster, copy the kubeconfig file from server1. If you need to install kubectl on your local machine, do that first.

scp [email protected]:/etc/rancher/rke2/rke2.yaml ~/.kube/config

Edit the kubeconfig to point to the server’s external IP instead of 127.0.0.1:

sed -i 's/127.0.0.1/10.0.1.10/g' ~/.kube/config

Verify connectivity from your workstation:

kubectl get nodes

Step 9: Deploy a Test Application

Deploy a sample Nginx application to confirm the cluster is functioning correctly. Create the deployment manifest:

sudo vi /tmp/nginx-test.yaml

Add the following content:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-test
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx-test
  template:
    metadata:
      labels:
        app: nginx-test
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-test
spec:
  type: NodePort
  selector:
    app: nginx-test
  ports:
  - port: 80
    targetPort: 80

Apply the manifest:

kubectl apply -f /tmp/nginx-test.yaml

Verify the pods are running:

$ kubectl get pods -l app=nginx-test
NAME                          READY   STATUS    RESTARTS   AGE
nginx-test-6d4cf56db6-2xk9m   1/1     Running   0          30s
nginx-test-6d4cf56db6-f7h3w   1/1     Running   0          30s

Get the NodePort assigned to the service:

$ kubectl get svc nginx-test
NAME         TYPE       CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
nginx-test   NodePort   10.43.85.120   <none>        80:31042/TCP   15s

Access the application using any node IP with the assigned NodePort. For example, http://10.0.1.20:31042 should return the default Nginx welcome page.

Clean up the test deployment when done:

kubectl delete -f /tmp/nginx-test.yaml

RKE2 Cluster Management Tips

Check the RKE2 server logs for troubleshooting:

sudo journalctl -u rke2-server -f

For agent nodes, check the agent logs:

sudo journalctl -u rke2-agent -f

To uninstall RKE2 from a server node:

sudo /usr/bin/rke2-uninstall.sh

To uninstall from an agent node:

sudo /usr/bin/rke2-agent-uninstall.sh

Once your cluster is operational, you can deploy an Nginx Ingress Controller with Helm for production traffic routing, though RKE2 already includes an NGINX Ingress Controller by default in the kube-system namespace.

Conclusion

We have deployed a 5-node HA Kubernetes cluster using RKE2 on Rocky Linux 10 / AlmaLinux 10 with 3 control plane nodes and 2 worker nodes. The embedded etcd cluster provides fault tolerance – the cluster survives the loss of any single server node.

For production use, add a dedicated load balancer in front of the API server on port 6443, configure automated etcd backups, set up monitoring with Prometheus and Grafana, and enable RBAC policies to restrict cluster access.

Related Articles

Containers Install Kubernetes Cluster on Ubuntu 22.04 using kubeadm CentOS Install GitHub Desktop on Rocky / CentOS / AlmaLinux AlmaLinux Configure PostgreSQL 17 Streaming Replication on Rocky Linux 10 / AlmaLinux 10 Kubernetes Enable CloudWatch logging in EKS Kubernetes Cluster

Press ESC to close