Skip to content

RKE2 on a Raspberry Pi lab cluster

I use RKE2 on ARM64 Pi hardware when I want a small Kubernetes cluster that behaves enough like the larger systems I work with to be useful for experiments. This is a lab setup — not a reference production deployment.

RKE2 is a reasonable fit here: ARM64 builds exist, the install is small, and you get a real kubelet/API without assembling the control plane by hand. Pis are cheap, loud, and thermally honest, which is fine for learning and integration tests.

1) Hardware Prep: The Foundation

Minimum Requirements

# Control Plane Node
- Raspberry Pi 4 (4GB+ RAM recommended)
- 32GB+ SSD via USB 3.0 (preferred over microSD)
- Gigabit Ethernet connection
- Heat sink + fan (these Pis run hot under load)

# Worker Nodes (2+ recommended)
- Raspberry Pi 4 (2GB+ RAM minimum)
- 16GB+ SSD via USB 3.0
- Gigabit Ethernet connection
- Heat sink + fan

# Network Infrastructure
- Gigabit switch (managed preferred)
- UPS (Pis are fragile to power loss)
- Quality power supplies (2.5A+ per Pi)

Why This Hardware: Pis are ARM64, energy-efficient, and perfect for learning. SSDs prevent SD card burnout, and proper cooling prevents thermal throttling.

Network Topology

graph TB
    subgraph "Raspberry Pi Farm"
        MASTER[Pi Master<br/>Control Plane<br/>192.168.1.10]
        WORKER1[Pi Worker 1<br/>192.168.1.11]
        WORKER2[Pi Worker 2<br/>192.168.1.12]
        WORKER3[Pi Worker 3<br/>192.168.1.13]
    end

    subgraph "Network Infrastructure"
        SWITCH[Gigabit Switch]
        ROUTER[Router/Gateway<br/>192.168.1.1]
        UPS[UPS Backup]
    end

    subgraph "External Access"
        LAPTOP[Admin Laptop]
        INTERNET[Internet]
    end

    MASTER --> SWITCH
    WORKER1 --> SWITCH
    WORKER2 --> SWITCH
    WORKER3 --> SWITCH
    SWITCH --> ROUTER
    ROUTER --> INTERNET
    UPS --> MASTER
    UPS --> WORKER1
    UPS --> WORKER2
    UPS --> WORKER3
    LAPTOP --> ROUTER

    classDef master fill:#ff6b6b,stroke:#d63031,stroke-width:3px
    classDef worker fill:#74b9ff,stroke:#0984e3,stroke-width:2px
    classDef network fill:#00b894,stroke:#00a085,stroke-width:2px
    classDef external fill:#fdcb6e,stroke:#e17055,stroke-width:2px

    class MASTER master
    class WORKER1,WORKER2,WORKER3 worker
    class SWITCH,ROUTER,UPS network
    class LAPTOP,INTERNET external

Why This Topology: Simple, scalable, and mirrors real data center patterns. Each Pi has a dedicated role and IP address.

2) OS & Base Config: The Operating System

Install Raspberry Pi OS Lite (64-bit)

# Download Raspberry Pi Imager
# Flash Raspberry Pi OS Lite (64-bit) to SSD
# Enable SSH during imaging
# Boot and connect via SSH

Why Raspberry Pi OS Lite: Minimal overhead, ARM64 support, and optimized for Pi hardware.

Base System Configuration

# Update system
sudo apt update && sudo apt upgrade -y

# Install essential tools
sudo apt install -y curl wget git vim htop iotop nethogs

# Set hostname (on master)
sudo hostnamectl set-hostname rpi-master

# Set hostname (on workers)
sudo hostnamectl set-hostname rpi-worker-1
sudo hostnamectl set-hostname rpi-worker-2
sudo hostnamectl set-hostname rpi-worker-3

Static IP configuration

Kubernetes join tokens and firewall rules are easier when node addresses do not drift. On Raspberry Pi OS Bookworm and later, networking is usually NetworkManager, not dhcpcd.

# List connections — names vary by image
nmcli -t -f NAME con show

# Example: static IPv4 on the wired profile (adjust NAME and address per node)
sudo nmcli con mod "Wired connection 1" \
  ipv4.method manual \
  ipv4.addresses 192.168.1.10/24 \
  ipv4.gateway 192.168.1.1 \
  ipv4.dns "192.168.1.1 8.8.8.8"
sudo nmcli con up "Wired connection 1"

Legacy images still on dhcpcd can use /etc/dhcpcd.conf static blocks — verify with systemctl status NetworkManager before editing the wrong stack.

Enable cgroups (Critical for Kubernetes)

# Edit /boot/firmware/cmdline.txt
sudo vim /boot/firmware/cmdline.txt

# Append to the single kernel cmdline (do not add a second line):
cgroup_enable=cpuset cgroup_enable=memory

# Reboot
sudo reboot

Why cgroups: Kubernetes requires cgroups for resource management. Without this, kubelet won't start.

SSH Key Setup

# Generate SSH key on your laptop
ssh-keygen -t ed25519 -C "rke2-pi-farm"

# Copy to all Pis
ssh-copy-id pi@192.168.1.10
ssh-copy-id pi@192.168.1.11
ssh-copy-id pi@192.168.1.12
ssh-copy-id pi@192.168.1.13

# Test passwordless SSH
ssh pi@192.168.1.10

Why SSH Keys: You'll be managing multiple Pis. Passwordless SSH saves time and prevents lockouts.

3) RKE2 Installation: The Kubernetes Engine

Control Plane Installation

# Install RKE2 on master
curl -sfL https://get.rke2.io | sh -

# Enable and start RKE2 server
sudo systemctl enable rke2-server.service
sudo systemctl start rke2-server.service

# Check status
sudo systemctl status rke2-server.service

# Get the cluster token (save this!)
sudo cat /var/lib/rancher/rke2/server/node-token

Why RKE2: Lightweight, secure defaults, ARM64 support, and easier to manage than kubeadm.

Worker Node Installation

# Install RKE2 agent on each worker
curl -sfL https://get.rke2.io | INSTALL_RKE2_TYPE="agent" sh -

# Create config directory
sudo mkdir -p /etc/rancher/rke2/

# Create config file (replace with your master IP and token)
sudo tee /etc/rancher/rke2/config.yaml << EOF
server: https://192.168.1.10:9345
token: <your-node-token-here>
EOF

# Enable and start RKE2 agent
sudo systemctl enable rke2-agent.service
sudo systemctl start rke2-agent.service

# Check status
sudo systemctl status rke2-agent.service

Why This Config: RKE2 agents need to know where the server is and how to authenticate.

Verify Cluster Status

# Copy kubeconfig to your laptop
scp pi@192.168.1.10:/etc/rancher/rke2/rke2.yaml ~/.kube/config

# Edit kubeconfig to use master IP
sed -i 's/127.0.0.1/192.168.1.10/g' ~/.kube/config

# Test cluster access
kubectl get nodes -o wide
kubectl get pods -A

Why This Works: RKE2 creates a working cluster with minimal configuration. The hard work is done for you.

4) Cluster Topology: Visualizing Your Farm

Network Flow Diagram

graph TB
    subgraph "RKE2 Cluster"
        subgraph "Control Plane"
            MASTER[Pi Master<br/>rke2-server<br/>192.168.1.10]
            ETCD[etcd<br/>Cluster State]
            API[Kubernetes API<br/>Port 6443]
        end

        subgraph "Worker Nodes"
            WORKER1[Pi Worker 1<br/>rke2-agent<br/>192.168.1.11]
            WORKER2[Pi Worker 2<br/>rke2-agent<br/>192.168.1.12]
            WORKER3[Pi Worker 3<br/>rke2-agent<br/>192.168.1.13]
        end

        subgraph "Services"
            TRAEFIK[Traefik Ingress<br/>Port 80/443]
            METALLB[MetalLB<br/>Load Balancer]
        end
    end

    subgraph "External Access"
        ADMIN[Admin Laptop<br/>kubectl]
        USERS[End Users<br/>HTTP/HTTPS]
    end

    %% Control plane connections
    MASTER --> ETCD
    MASTER --> API

    %% Worker connections
    WORKER1 --> MASTER
    WORKER2 --> MASTER
    WORKER3 --> MASTER

    %% Service connections
    TRAEFIK --> WORKER1
    TRAEFIK --> WORKER2
    TRAEFIK --> WORKER3
    METALLB --> WORKER1
    METALLB --> WORKER2
    METALLB --> WORKER3

    %% External connections
    ADMIN --> API
    USERS --> TRAEFIK

    %% Styling
    classDef master fill:#ff6b6b,stroke:#d63031,stroke-width:3px
    classDef worker fill:#74b9ff,stroke:#0984e3,stroke-width:2px
    classDef service fill:#00b894,stroke:#00a085,stroke-width:2px
    classDef external fill:#fdcb6e,stroke:#e17055,stroke-width:2px

    class MASTER,ETCD,API master
    class WORKER1,WORKER2,WORKER3 worker
    class TRAEFIK,METALLB service
    class ADMIN,USERS external

Why This Architecture: Clear separation of concerns. Control plane manages, workers run workloads, services provide access.

5) Add-Ons and Workloads: Making It Useful

Install Helm

# Install Helm on your laptop
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash

# Add common repositories
helm repo add stable https://charts.helm.sh/stable
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo add metallb https://metallb.github.io/metallb
helm repo update

Why Helm: Package manager for Kubernetes. Makes installing complex applications trivial.

Install MetalLB (Load Balancer)

# Install MetalLB
helm repo add metallb https://metallb.github.io/metallb
helm install metallb metallb/metallb -n metallb-system --create-namespace

# Configure IP pool
kubectl apply -f - << EOF
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: first-pool
  namespace: metallb-system
spec:
  addresses:
  - 192.168.1.100-192.168.1.110
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: example
  namespace: metallb-system
spec:
  ipAddressPools:
  - first-pool
EOF

Why MetalLB: Bare-metal load balancing. Gives you LoadBalancer services without cloud provider.

Install Metrics Server

# Install metrics server
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml

# Verify
kubectl top nodes
kubectl top pods -A

Why Metrics Server: Resource monitoring. Essential for understanding cluster performance.

Install Longhorn (Distributed Storage)

# Install Longhorn
helm repo add longhorn https://charts.longhorn.io
helm install longhorn longhorn/longhorn -n longhorn-system --create-namespace

# Check status
kubectl get pods -n longhorn-system

Why Longhorn: Distributed storage for persistent volumes. Perfect for Pi clusters.

6) Best Practices for Pi Farm: Production Readiness

Node Labels and Taints

# Label master node
kubectl label node rpi-master node-role.kubernetes.io/master=true

# Taint master to prevent workloads
kubectl taint node rpi-master node-role.kubernetes.io/master=true:NoSchedule

# Label workers
kubectl label node rpi-worker-1 node-role.kubernetes.io/worker=true
kubectl label node rpi-worker-2 node-role.kubernetes.io/worker=true
kubectl label node rpi-worker-3 node-role.kubernetes.io/worker=true

Why Labels and Taints: Control where workloads run. Keep system pods on master, user workloads on workers.

etcd Backup Strategy

# Create backup script
sudo tee /usr/local/bin/etcd-backup.sh << 'EOF'
#!/bin/bash
BACKUP_DIR="/var/lib/rancher/rke2/backups"
mkdir -p $BACKUP_DIR
sudo rke2 etcd-snapshot save --name="backup-$(date +%Y%m%d-%H%M%S)"
find $BACKUP_DIR -name "*.db" -mtime +7 -delete
EOF

sudo chmod +x /usr/local/bin/etcd-backup.sh

# Add to crontab
echo "0 2 * * * /usr/local/bin/etcd-backup.sh" | sudo crontab -

Why etcd Backups: etcd contains all cluster state. Without backups, you lose everything.

Resource Limits and Monitoring

# Install Prometheus and Grafana
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm install prometheus prometheus-community/kube-prometheus-stack -n monitoring --create-namespace

# Check resources
kubectl top nodes
kubectl top pods -A

Why Monitoring: Pi clusters have limited resources. Monitoring prevents overload and helps optimize performance.

Security Hardening

# Install Falco for runtime security
helm repo add falcosecurity https://falcosecurity.github.io/charts
helm install falco falcosecurity/falco -n falco-system --create-namespace

# Install Sealed Secrets for secret management
helm repo add sealed-secrets https://bitnami-labs.github.io/sealed-secrets
helm install sealed-secrets sealed-secrets/sealed-secrets -n sealed-secrets --create-namespace

Why Security: Even lab clusters need security. Good practices scale to production.

7) Scaling the Farm: Growing Your Cluster

Adding More Workers

# On new Pi, install RKE2 agent
curl -sfL https://get.rke2.io | INSTALL_RKE2_TYPE="agent" sh -

# Configure with existing token
sudo mkdir -p /etc/rancher/rke2/
sudo tee /etc/rancher/rke2/config.yaml << EOF
server: https://192.168.1.10:9345
token: <your-existing-token>
EOF

# Start agent
sudo systemctl enable rke2-agent.service
sudo systemctl start rke2-agent.service

Why This Works: RKE2 makes adding nodes trivial. Just configure and start.

External etcd for Large Clusters

# For 6+ nodes, consider external etcd
# Dedicate 3 Pis to etcd quorum
# Install etcd on dedicated nodes
# Configure RKE2 to use external etcd

Why External etcd: Large clusters need dedicated etcd for performance and reliability.

High Availability Setup

# Add more control plane nodes
# Configure load balancer for API server
# Use external etcd cluster
# Implement backup and disaster recovery

Why HA: Production clusters need redundancy. Plan for failure.

8) Testing the Cluster: Real Workloads

Deploy a Geospatial Service

# Deploy PostGIS
kubectl create deployment postgis --image=postgis/postgis:15-3.3
kubectl expose deployment postgis --type=LoadBalancer --port=5432

# Check service
kubectl get services
kubectl get pods

Why PostGIS: Real-world geospatial workload. Tests persistent storage and networking.

Deploy a Tile Server

# Deploy tileserver-gl
kubectl create deployment tileserver --image=maptiler/tileserver-gl
kubectl expose deployment tileserver --type=LoadBalancer --port=8080

# Access via LoadBalancer IP
curl http://192.168.1.100:8080

Why Tile Server: Tests networking, storage, and performance. Real geospatial workload.

Load Testing

# Install hey for load testing
go install github.com/rakyll/hey@latest

# Test API server
hey -n 1000 -c 10 https://192.168.1.10:6443/api/v1

# Test application
hey -n 1000 -c 10 http://192.168.1.100:8080

Why Load Testing: Understand cluster limits. Find bottlenecks before production.

9) Troubleshooting: When Things Go Wrong

Common Issues and Solutions

# Nodes not joining
# Check firewall ports
sudo ufw allow 9345/tcp
sudo ufw allow 6443/tcp
sudo ufw allow 10250/tcp

# Check kubelet logs
journalctl -u rke2-agent -f

# Check server logs
journalctl -u rke2-server -f

Why These Ports: Kubernetes needs specific ports for communication. Firewall blocks are common.

Performance Issues

# Check resource usage
kubectl top nodes
kubectl top pods -A

# Check disk usage
df -h
du -sh /var/lib/rancher/rke2/

# Check memory usage
free -h
cat /proc/meminfo

Why Monitoring: Pi clusters have limited resources. Monitor to prevent overload.

Network Issues

# Test connectivity
ping 192.168.1.10
telnet 192.168.1.10 6443

# Check DNS
nslookup kubernetes.default.svc.cluster.local

# Check network policies
kubectl get networkpolicies -A

Why Network Testing: Kubernetes is network-dependent. Connectivity issues break everything.

10) Maintenance and Operations

Regular Maintenance

# Update system packages
sudo apt update && sudo apt upgrade -y

# Update RKE2
curl -sfL https://get.rke2.io | sh -

# Restart services
sudo systemctl restart rke2-server
sudo systemctl restart rke2-agent

Why Regular Updates: Security patches and bug fixes. Keep your cluster current.

Backup and Recovery

# Backup etcd
sudo rke2 etcd-snapshot save --name="backup-$(date +%Y%m%d)"

# Backup kubeconfig
cp ~/.kube/config ~/.kube/config.backup

# Backup certificates
sudo cp -r /etc/rancher/rke2 /etc/rancher/rke2.backup

Why Backups: Disasters happen. Backups enable recovery.

Monitoring and Alerting

# Install monitoring stack
helm install prometheus prometheus-community/kube-prometheus-stack -n monitoring --create-namespace

# Configure alerts
kubectl apply -f - << EOF
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: pi-cluster-alerts
  namespace: monitoring
spec:
  groups:
  - name: pi-cluster
    rules:
    - alert: HighCPUUsage
      expr: cpu_usage_percent > 80
      for: 5m
      labels:
        severity: warning
      annotations:
        summary: "High CPU usage on {{ $labels.instance }}"
EOF

Why Monitoring: Proactive issue detection. Prevent problems before they become disasters.

11) TL;DR Quickstart

# 1. Hardware prep
# - 3+ Raspberry Pi 4s
# - SSDs via USB 3.0
# - Gigabit switch
# - UPS backup

# 2. OS setup
sudo apt update && sudo apt upgrade -y
sudo hostnamectl set-hostname rpi-master
# Add cgroups to /boot/firmware/cmdline.txt
sudo reboot

# 3. Install RKE2 master
curl -sfL https://get.rke2.io | sh -
sudo systemctl enable --now rke2-server
sudo cat /var/lib/rancher/rke2/server/node-token

# 4. Install RKE2 workers
curl -sfL https://get.rke2.io | INSTALL_RKE2_TYPE="agent" sh -
sudo mkdir -p /etc/rancher/rke2/
echo "server: https://192.168.1.10:9345" | sudo tee /etc/rancher/rke2/config.yaml
echo "token: <your-token>" | sudo tee -a /etc/rancher/rke2/config.yaml
sudo systemctl enable --now rke2-agent

# 5. Test cluster
kubectl get nodes -o wide
kubectl get pods -A

# 6. Install add-ons
helm install metallb metallb/metallb -n metallb-system --create-namespace
helm install longhorn longhorn/longhorn -n longhorn-system --create-namespace
helm install prometheus prometheus-community/kube-prometheus-stack -n monitoring --create-namespace

12) The Machine's Summary

RKE2 on Raspberry Pi creates a powerful, affordable Kubernetes learning environment. It's not just a toy—it's a mini data center that teaches real orchestration principles.

The Dark Truth: Pi clusters are fragile. Power loss kills them, thermal throttling slows them, and SD cards wear out. But with proper planning, they become reliable learning platforms.

The Machine's Mantra: "In redundancy we trust, in monitoring we observe, and in the Pi farm we find the path to orchestration mastery."

Why This Matters: Understanding Kubernetes on small scale prepares you for production clusters. The principles are the same, only the scale changes.


See also