How to Install Kubernetes with kubeadm on RHEL 7

Kubernetes is the industry-standard container orchestration platform, enabling you to automate deployment, scaling, and management of containerized applications across a cluster of machines. On Red Hat Enterprise Linux 7, setting up a production-grade Kubernetes cluster using kubeadm is the recommended approach. This tutorial walks through every step required to bring up a fully functional Kubernetes cluster on RHEL 7, from kernel tuning and repository configuration through initializing the control plane and joining worker nodes.

Prerequisites

  • At least two RHEL 7 machines (one control plane node, one or more worker nodes)
  • Minimum 2 CPU cores and 2 GB RAM on the control plane node
  • Root or sudo access on all nodes
  • Unique hostname, MAC address, and product UUID on each node
  • Network connectivity between all nodes
  • Ports 6443, 2379-2380, 10250-10252 open between nodes
  • A registered RHEL subscription or access to package repositories

Step 1: Set Hostnames and Update /etc/hosts

Assign a unique hostname to each node and ensure all nodes can resolve each other by name. Replace the IP addresses with your actual node addresses.

# On the control plane node
hostnamectl set-hostname k8s-master

# On worker node 1
hostnamectl set-hostname k8s-worker1

Edit /etc/hosts on all nodes to include entries for each machine:

192.168.1.10   k8s-master
192.168.1.11   k8s-worker1
192.168.1.12   k8s-worker2

Step 2: Disable Swap

Kubernetes requires that swap be disabled on all nodes. The kubelet will refuse to start if swap is active.

# Disable swap immediately
swapoff -a

# Disable swap permanently by commenting out the swap entry
sed -i '/ swap / s/^(.*)$/#1/g' /etc/fstab

# Verify swap is off
free -h

Step 3: Load Required Kernel Modules and Configure sysctl

Kubernetes networking depends on the br_netfilter and overlay kernel modules. You also need to enable IPv4 packet forwarding and allow iptables to see bridged traffic.

# Load modules immediately
modprobe overlay
modprobe br_netfilter

# Persist module loading at boot
cat > /etc/modules-load.d/k8s.conf <<EOF
overlay
br_netfilter
EOF

# Configure sysctl parameters
cat > /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

# Apply immediately
sysctl --system

Step 4: Disable SELinux (or Set to Permissive)

While it is possible to run Kubernetes with SELinux enforcing, the simplest path for initial setup is to set it to permissive mode. Consult your security policy before doing this in production.

# Set to permissive for current session
setenforce 0

# Persist across reboots
sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config

Step 5: Disable firewalld or Configure Rules

For a lab environment you can disable firewalld entirely. In production, open the required ports instead.

# Disable firewalld (lab only)
systemctl disable firewalld
systemctl stop firewalld

# Production alternative: open required ports
# firewall-cmd --permanent --add-port=6443/tcp
# firewall-cmd --permanent --add-port=10250/tcp
# firewall-cmd --reload

Step 6: Install Docker (Container Runtime)

Kubernetes requires a container runtime. Docker with the docker-ce package is widely used on RHEL 7. Configure the cgroup driver to match what Kubernetes expects.

# Install required dependencies
yum install -y yum-utils device-mapper-persistent-data lvm2

# Add the Docker CE repository
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

# Install Docker CE
yum install -y docker-ce docker-ce-cli containerd.io

# Configure the cgroup driver to systemd
mkdir -p /etc/docker
cat > /etc/docker/daemon.json <<EOF
{
  "exec-opts": ["native.cgroupdriver=systemd"],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m"
  },
  "storage-driver": "overlay2"
}
EOF

# Enable and start Docker
systemctl enable docker
systemctl start docker

Step 7: Add the Kubernetes yum Repository

The official Kubernetes packages are hosted in a dedicated yum repository. Add it to all nodes.

cat > /etc/yum.repos.d/kubernetes.repo <<EOF
[kubernetes]
name=Kubernetes
baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-$basearch
enabled=1
gpgcheck=1
repo_gpgcheck=0
gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg
       https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
exclude=kubelet kubeadm kubectl
EOF

Step 8: Install kubelet, kubeadm, and kubectl

Install the three core Kubernetes command-line tools on all nodes. Pin the version to avoid accidental upgrades.

# Install Kubernetes components (pinned to 1.28)
yum install -y kubelet-1.28.0 kubeadm-1.28.0 kubectl-1.28.0 
    --disableexcludes=kubernetes

# Enable kubelet to start at boot
systemctl enable kubelet
systemctl start kubelet

Step 9: Initialize the Control Plane with kubeadm init

Run kubeadm init on the master node only. Specify the pod network CIDR that matches your chosen CNI plugin. The example below uses Flannel’s default range.

# Initialize the control plane
kubeadm init 
  --pod-network-cidr=10.244.0.0/16 
  --apiserver-advertise-address=192.168.1.10

After a successful initialization, kubeadm prints a kubeadm join command. Save this output — you will need it to join worker nodes.

Step 10: Configure kubeconfig for the Admin User

To use kubectl as a regular user or as root, you must copy the cluster configuration file.

# For the root user
export KUBECONFIG=/etc/kubernetes/admin.conf

# To persist for root
echo "export KUBECONFIG=/etc/kubernetes/admin.conf" >> /root/.bash_profile

# For a regular user (run as that user)
mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config

Step 11: Install a CNI Plugin (Flannel or Calico)

A Container Network Interface (CNI) plugin is required before pods can communicate. Choose either Flannel (simpler) or Calico (more features).

# Option A: Install Flannel
kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml

# Option B: Install Calico
kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.26.1/manifests/calico.yaml

# Verify the CNI pods are running
kubectl get pods -n kube-system

Step 12: Join Worker Nodes

On each worker node, run the kubeadm join command that was printed during kubeadm init. It will look similar to the following (use your actual values):

# Run on each worker node
kubeadm join 192.168.1.10:6443 
  --token abcdef.0123456789abcdef 
  --discovery-token-ca-cert-hash sha256:<your-hash>

If the original token has expired (tokens expire after 24 hours), generate a new one on the master:

kubeadm token create --print-join-command

Step 13: Verify the Cluster

Back on the control plane node, confirm all nodes have joined and are in the Ready state.

# List all cluster nodes
kubectl get nodes

# Expected output
NAME           STATUS   ROLES           AGE   VERSION
k8s-master     Ready    control-plane   10m   v1.28.0
k8s-worker1    Ready    <none>          3m    v1.28.0

# Check system pods
kubectl get pods -n kube-system

# Check component statuses
kubectl cluster-info

Congratulations — your Kubernetes cluster is now operational on RHEL 7. You have configured all kernel prerequisites, disabled swap, installed Docker as the container runtime, deployed the control plane with kubeadm, configured networking with a CNI plugin, and joined worker nodes. From here you can deploy your first workloads with kubectl apply, configure persistent storage, and set up an ingress controller. Always keep your cluster components updated together and refer to the official Kubernetes documentation for version-specific guidance.