IoT

Raspberry Pi Kubernetes Cluster: k3s Multi-Node dengan Persistent Storage & Ingress

TOKEN

Bangun cluster Kubernetes mini menggunakan Raspberry Pi dan k3s — lengkap dengan MetalLB load balancer, Ingress controller, dan persistent storage

1. Mengapa Kubernetes di Raspberry Pi?

Kubernetes di Raspberry Pi bukan hanya untuk belajar — ini adalah cara yang sangat efektif untuk mengelola edge computing, IoT gateway, dan microservices di lingkungan resource-limited. Dengan k3s (lightweight Kubernetes dari Rancher/SUSE), kita bisa menjalankan cluster production-grade di hardware yang hemat listrik.

k3s vs K8s vs MicroK8s

Fiturk3sFull K8sMicroK8s
Memory~512 MB~2 GB~1 GB
Disk~100 MB~1 GB~300 MB
BinarySingle binaryMultipleSnap package
ARM SupportNativeManualNative
HA ClusterYa (embedded etcd)Ya (etcd)Ya (dqlite)
Install1 commandkubeadm (kompleks)snap install
Cocok untukEdge, IoT, HomelabProduction cloudDevelopment
🟢
k3s
Lightweight K8s
  • Single binary ~100MB
  • SQLite atau embedded etcd
  • Built-in Traefik ingress
  • CNCF certified
  • Install 1 command
🔵
Use Cases
Deploy di RPi Cluster
  • IoT edge computing
  • Home automation
  • CI/CD homelab
  • Microservices learning
  • Low-power server

2. Hardware yang Dibutuhkan

KomponenRekomendasiEstimasi Harga
Raspberry Pi 4 (x3-4)4GB RAM per unitRp 800rb × 4
MicroSD Card32GB Class 10 / A2 per unitRp 80rb × 4
Power SupplyUSB-C 5V/3A per unitRp 80rb × 4
Ethernet SwitchGigabit 5-8 portRp 150rb
Ethernet CableCat5e/Cat6Rp 20rb × 4
Case + Fan (opsional)Cluster case 3D-printedRp 200rb
NAS/USB HDD (opsional)Untuk persistent storageRp 300rb
💡 Minimum Setup

Untuk belajar, 2 unit Raspberry Pi 4 (2GB) sudah cukup — 1 server + 1 worker. Tapi untuk cluster yang lebih robust, 3-4 unit (4GB) direkomendasikan.

3. Setup OS Raspberry Pi

Bash
# 1. Download Raspberry Pi OS Lite (64-bit)
#    dari https://www.raspberrypi.com/software/
#    Pilih "Raspberry Pi OS Lite (64-bit)"

# 2. Flash ke SD card menggunakan Raspberry Pi Imager
#    Atau gunakan dd:
sudo dd if=rpios-lite-arm64.img of=/dev/sdX bs=4M status=progress

# 3. Sebelum eject, aktifkan SSH dan set hostname
#    Mount boot partition lalu buat file:
touch /media/$USER/boot/ssh

# 4. Set hostname unik untuk setiap node
echo "k3s-master" > /media/$USER/etc/hostname
# Atau gunakan Raspberry Pi Imager untuk advanced settings

# 5. Boot Pi dan SSH masuk
ssh pi@raspberrypi.local

# 6. Update sistem
sudo apt update && sudo apt upgrade -y

# 7. Install essentials
sudo apt install -y curl git vim net-tools

# 8. Set static IP (opsional tapi recommended)
# Edit /etc/dhcpcd.conf:
sudo tee -a /etc/dhcpcd.conf <<'EOF'
interface eth0
static ip_address=192.168.1.10/24
static routers=192.168.1.1
static domain_name_servers=8.8.8.8 1.1.1.1
EOF

# 9. Disable swap (required untuk Kubernetes)
sudo dphys-swapfile swapoff
sudo dphys-swapfile uninstall
sudo systemctl disable dphys-swapfile

# 10. Enable cgroup memory (required untuk k3s)
# Edit /boot/firmware/cmdline.txt, tambahkan:
# cgroup_memory=1 cgroup_enable=memory
echo " cgroup_memory=1 cgroup_enable=memory" | sudo tee -a /boot/firmware/cmdline.txt

# 11. Reboot
sudo reboot

4. Install k3s Cluster

k3s terkenal karena kemudahan install-nya — cukup satu command!

Bash — Master Node (k3s-master)
# Install k3s server (master node)
# --disable servicelb: kita pakai MetalLB sebagai gantinya
curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--disable servicelb --write-kubeconfig-mode 644" sh -

# Cek status
sudo systemctl status k3s
kubectl get nodes
kubectl get pods -A

# Dapatkan node token (untuk join worker)
sudo cat /var/lib/rancher/k3s/server/node-token

# Export kubeconfig untuk remote access
# (jalankan di laptop kamu, bukan di Pi)
mkdir -p ~/.kube
scp pi@192.168.1.10:/etc/rancher/k3s/k3s.yaml ~/.kube/config

# Edit server URL di kubeconfig
sed -i 's/127.0.0.1/192.168.1.10/g' ~/.kube/config

# Verifikasi dari laptop
kubectl get nodes
kubectl cluster-info

5. Multi-Node: Worker Nodes

Bash — Worker Nodes
# Di setiap worker node (k3s-worker1, k3s-worker2, dll):

# Install k3s agent dan join ke cluster
# Ganti SERVER_IP dan TOKEN sesuai master
curl -sfL https://get.k3s.io | K3S_URL="https://192.168.1.10:6443" K3S_TOKEN="TOKEN_DARI_MASTER" sh -

# Verifikasi dari master node
kubectl get nodes
# Harusnya terlihat:
# NAME          STATUS   ROLES                  AGE   VERSION
# k3s-master    Ready    control-plane,master   5m    v1.30+k3s1
# k3s-worker1   Ready    <none>                 2m    v1.30+k3s1
# k3s-worker2   Ready    <none>                 1m    v1.30+k3s1

# Label worker nodes
kubectl label node k3s-worker1 node-role.kubernetes.io/worker=worker
kubectl label node k3s-worker2 node-role.kubernetes.io/worker=worker

# Cek semua pods berjalan
kubectl get pods -A -o wide

6. MetalLB Load Balancer

k3s default menggunakan ServiceLB yang terbatas. MetalLB menyediakan LoadBalancer service yang proper dengan IP address pool dari jaringan lokal kita.

Bash — Install MetalLB
# Install MetalLB
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.14.5/config/manifests/metallb-native.yaml

# Tunggu hingga pods ready
kubectl wait --namespace metallb-system --for=condition=ready pod --selector=app=metallb --timeout=120s

# Buat IP address pool
cat <<'EOF' | kubectl apply -f -
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: default-pool
  namespace: metallb-system
spec:
  addresses:
  - 192.168.1.200-192.168.1.250

---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: default
  namespace: metallb-system
spec:
  ipAddressPools:
  - default-pool
EOF

# Verifikasi
kubectl get ipaddresspool -n metallb-system
# MetalLB akan assign IP dari pool ini ke LoadBalancer services

7. Ingress Controller (Nginx)

Bash — Install Nginx Ingress
# Install Nginx Ingress Controller
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.10.1/deploy/static/provider/baremetal/deploy.yaml

# Tunggu hingga ready
kubectl wait --namespace ingress-nginx --for=condition=ready pod --selector=app.kubernetes.io/component=controller --timeout=120s

# Cek External IP (dari MetalLB)
kubectl get svc -n ingress-nginx
# NAME                       TYPE           CLUSTER-IP     EXTERNAL-IP     PORT(S)
# ingress-nginx-controller   LoadBalancer   10.43.x.x      192.168.1.200   80:xxxxx/TCP,443:xxxxx/TCP

# Contoh Ingress rule
cat <<'EOF' | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: grafana-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - host: grafana.local
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: grafana
            port:
              number: 3000
EOF

# Tambahkan DNS di laptop: /etc/hosts
# 192.168.1.200 grafana.local

8. Persistent Storage dengan NFS

Persistent storage sangat penting untuk database dan stateful applications. Di RPi cluster, NFS server adalah solusi yang paling praktis.

Bash — Setup NFS Server di Master
# Install NFS server di master node
sudo apt install -y nfs-kernel-server

# Buat shared directory
sudo mkdir -p /srv/nfs/k3s
sudo chown nobody:nogroup /srv/nfs/k3s

# Configure exports
echo "/srv/nfs/k3s 192.168.1.0/24(rw,sync,no_subtree_check,no_root_squash)" | sudo tee /etc/exports
sudo exportfs -ra

# Restart NFS
sudo systemctl restart nfs-kernel-server
sudo systemctl enable nfs-kernel-server

# Install NFS CSI driver di k3s
cat <<'EOF' | kubectl apply -f -
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: nfs-storage
provisioner: nfs.csi.k8s.io
parameters:
  server: 192.168.1.10
  share: /srv/nfs/k3s
reclaimPolicy: Retain
volumeBindingMode: Immediate
mountOptions:
  - nfsvers=4.1
EOF

# Contoh PersistentVolumeClaim
cat <<'EOF' | kubectl apply -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: grafana-pvc
spec:
  storageClassName: nfs-storage
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi
EOF

9. Deploy Aplikasi IoT

Deploy aplikasi monitoring IoT menggunakan MQTT broker (Mosquitto), Grafana, dan InfluxDB di cluster.

YAML — Mosquitto MQTT Broker
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mosquitto
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mosquitto
  template:
    metadata:
      labels:
        app: mosquitto
    spec:
      containers:
      - name: mosquitto
        image: eclipse-mosquitto:2
        ports:
        - containerPort: 1883
          name: mqtt
        - containerPort: 9001
          name: websocket
        volumeMounts:
        - name: config
          mountPath: /mosquitto/config
        - name: data
          mountPath: /mosquitto/data
        resources:
          limits:
            memory: "128Mi"
            cpu: "200m"
      volumes:
      - name: config
        configMap:
          name: mosquitto-config
      - name: data
        persistentVolumeClaim:
          claimName: mosquitto-pvc
---
apiVersion: v1
kind: Service
metadata:
  name: mosquitto
spec:
  type: LoadBalancer
  selector:
    app: mosquitto
  ports:
  - port: 1883
    targetPort: 1883
    name: mqtt
  - port: 9001
    targetPort: 9001
    name: websocket

10. Quiz Pemahaman

Pertanyaan 1: Mengapa k3s lebih cocok dari K8s full untuk Raspberry Pi?

a) k3s lebih cepat dari K8s
b) k3s ringan (~512MB RAM) dan single binary
c) k3s gratis, K8s berbayar
d) k3s tidak support ARM

Pertanyaan 2: Apa fungsi MetalLB di k3s cluster?

a) Mengelola storage
b) Mengatur jaringan cluster
c) Menyediakan LoadBalancer IP dari pool lokal
d) Monitoring cluster

Pertanyaan 3: Mengapa swap harus dimatikan untuk Kubernetes?

a) Menghemat disk space
b) Kubernetes membutuhkan penjadwalan yang prediktable; swap menyebabkan OOM unpredictable
c) Swap tidak kompatibel dengan Linux
d) Untuk meningkatkan kecepatan CPU

Pertanyaan 4: Apa fungsi Ingress Controller?

a) Mengelola database
b) Routing HTTP/HTTPS traffic ke services berdasarkan domain/path
c) Mengatur storage
d) Monitoring CPU usage

Pertanyaan 5: Perintah untuk join worker node ke k3s cluster?

a) kubectl join --token=xxx
b) k3s join --server=xxx
c) curl -sfL https://get.k3s.io | K3S_URL=... K3S_TOKEN=... sh -
d) kubeadm join
← SebelumnyaArduino Library Selanjutnya →STM32 Bare Metal
🔍 Zoom
100%
🎨 Tema