Raspberry Pi Cluster Setup (Kubernetes)

Build a Raspberry Pi cluster running Kubernetes. Step-by-step guide covering networking, K3s install, and multi-node workloads.

Andreas · April 12, 2026 · 12 min read

Introduction

Build a 4-node Pi cluster running Kubernetes and handle multi-machine workloads. This guide covers hardware selection, networking setup, K3s installation across nodes, shared NFS storage, and monitoring with Lens. For homelabs running multiple services, clusters offer redundancy and horizontal scaling beyond single-machine capabilities.

Prerequisites

  • 3-4 Raspberry Pi 4 (8GB) or Pi 5 (8GB minimum)
  • One 8-port Gigabit PoE switch (optional but recommended)
  • Four 32GB+ USB SSDs for each Pi
  • USB 3.0 hub + cables (if not using PoE switch)
  • Ethernet cables (one per Pi)
  • Static IP range reserved on router (e.g., 192.168.1.100-110)

Hardware & Cost Breakdown

Item Cost Notes
Pi 4 (8GB) × 4 $360 $90 each, or use mix of Pi 4/5
USB 3.0 SSD 1TB × 4 $200 $50 each, critical for performance
PoE Switch (8 port) $80 Powers + networks in one cable
PoE HAT × 4 $40 For PoE power
Ethernet cables × 4 $15 CAT6 recommended
Total $695 Scales to 6-8 nodes for ~$1K

Network Architecture

Internet
  |
Router (192.168.1.1)
  |
PoE Switch (192.168.1.50)
  |
  +-- Pi-Master (192.168.1.100)  [K3s server]
  +-- Pi-Worker-1 (192.168.1.101) [K3s agent]
  +-- Pi-Worker-2 (192.168.1.102) [K3s agent]
  +-- Pi-Worker-3 (192.168.1.103) [K3s agent]

Step 1 — Configure Static IPs

On each Pi, set static IP via systemd-networkd:

sudo nano /etc/systemd/network/99-static.network

Add:

[Match]
Name=eth0

[Network]
Address=192.168.1.100/24
Gateway=192.168.1.1
DNS=8.8.8.8 8.8.4.4

Adjust address for each Pi (100, 101, 102, 103).

Restart networking:

sudo systemctl restart systemd-networkd
ip a

Verify static IP assigned.

Step 2 — Prepare All Nodes

Run on all four Pis (master and workers):

sudo apt update && sudo apt upgrade -y

Enable required kernel modules:

sudo nano /boot/firmware/cmdline.txt

Append to end of line:

cgroup_memory=1 cgroup_enable=memory

Reboot each Pi:

sudo reboot

Step 3 — Install K3s on Master

SSH into master Pi (192.168.1.100):

curl -sfL https://get.k3s.io | sh -

Verify:

sudo k3s kubectl get nodes

Get the node token (needed for workers):

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

Copy this token—you'll use it on all workers.

Step 4 — Install K3s on Worker Nodes

SSH into first worker (192.168.1.101):

curl -sfL https://get.k3s.io | \
  K3S_URL=https://192.168.1.100:6443 \
  K3S_TOKEN=<paste-token-here> \
  sh -

Repeat for workers 102 and 103, changing token and URL only.

Step 5 — Verify Cluster

From master, check all nodes:

sudo k3s kubectl get nodes

Expected output:

NAME               STATUS   ROLES                  AGE
pi-master          Ready    control-plane,master  5m
pi-worker-1        Ready    <none>                2m
pi-worker-2        Ready    <none>                2m
pi-worker-3        Ready    <none>                2m

Check pods across cluster:

kubectl get pods --all-namespaces

Step 6 — Configure Shared NFS Storage

Set up NFS server on master to share storage across cluster:

sudo apt install nfs-kernel-server -y

Create shared directory:

sudo mkdir -p /srv/nfs/shared
sudo chmod 777 /srv/nfs/shared

Export via NFS:

sudo nano /etc/exports

Add:

/srv/nfs/shared 192.168.1.0/24(rw,sync,no_subtree_check,no_root_squash)

Restart NFS:

sudo exportfs -a
sudo systemctl restart nfs-kernel-server

Install NFS on Workers

On each worker:

sudo apt install nfs-common -y

Create Persistent Volume in K3s

From master, create NFS-backed storage:

cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-shared
spec:
  capacity:
    storage: 100Gi
  accessModes:
    - ReadWriteMany
  nfs:
    server: 192.168.1.100
    path: "/srv/nfs/shared"

---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nfs-shared-claim
spec:
  accessModes:
    - ReadWriteMany
  storageClassName: ""
  resources:
    requests:
      storage: 50Gi
  volumeName: nfs-shared
EOF

Verify:

kubectl get pv,pvc

Step 7 — Deploy Test Application

Deploy Nginx across cluster:

cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-cluster
spec:
  replicas: 4
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - web
            topologyKey: kubernetes.io/hostname
      containers:
      - name: nginx
        image: nginx:1.26-alpine
        ports:
        - containerPort: 80
        resources:
          requests:
            memory: "64Mi"
            cpu: "100m"
          limits:
            memory: "128Mi"
            cpu: "200m"

---
apiVersion: v1
kind: Service
metadata:
  name: web-service
spec:
  selector:
    app: web
  type: LoadBalancer
  ports:
  - port: 80
    targetPort: 80
EOF

Check pod distribution:

kubectl get pods -o wide

Each pod should land on different nodes (pod anti-affinity).

Step 8 — Monitor Cluster with Lens

Install Lens (Kubernetes IDE) on your local machine:

# Mac
brew install lens

# Linux
snap install kontena-lens

# Windows
choco install lens

Copy kubeconfig from master:

sudo cat /etc/rancher/k3s/k3s.yaml

In Lens, click + → paste kubeconfig → select cluster. View all nodes, pods, and resource usage in real time.

Step 9 — Enable Metrics & Monitoring

Install metrics-server for kubectl top:

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

Wait 30 seconds, then check:

kubectl top nodes
kubectl top pods --all-namespaces

Step 10 — Useful Cluster Operations

Add a 5th node

On new Pi, run K3s agent with same token/URL as workers.

Remove a node

Drain then delete:

kubectl drain pi-worker-2 --ignore-daemonsets
kubectl delete node pi-worker-2

On that Pi, uninstall K3s:

/usr/local/bin/k3s-agent-uninstall.sh

Restart master

All workloads survive (they're on workers). Master restarts gracefully:

sudo systemctl restart k3s

Backup cluster state

Use velero (backup tool):

helm repo add vmware-tanzu https://vmware-tanzu.github.io/helm-charts
helm install velero vmware-tanzu/velero --namespace velero --create-namespace

Resource Usage (4-Node Cluster)

Metric Per Node Total
RAM overhead (K3s) ~500 MB 2 GB
Available for apps ~7.5 GB 30 GB
Storage (SSD 1TB each) 1 TB 4 TB

Each Pi can run ~10-15 small containers safely.

Troubleshooting

Worker stuck in NotReady

Check node logs: kubectl describe node <name>. Common: cgroup memory not enabled. Verify /boot/firmware/cmdline.txt changes and reboot.

Pods evicted (disk pressure)

SSDs filling up. Check: df -h on each node. Clean old images: docker image prune -a.

NFS mount fails

Verify NFS running on master: sudo systemctl status nfs-kernel-server. Check firewall: sudo ufw allow nfs.

Network latency between nodes

Expected on 100 Mbps Ethernet. Upgrade to Gigabit switch for 1 Gbps (15-20x faster).

Summary

A 4-node Pi cluster costs under $700 and runs hundreds of containers. Use it for redundant services, testing multi-node workloads, or learning Kubernetes at scale. Start with 3 nodes (master + 2 workers), add 4th for true HA. Monitor with Lens, manage storage with NFS, and scale applications with kubectl.

Related Tools

Comments