K3s Kubernetes cluster running on a Raspberry Pi 4 controller with four Pi Zero 2 W worker nodes via a ClusterHAT.
Hardware:
- Controller: Raspberry Pi 4 (4GB RAM, K3s control plane)
- Workers: 4× Raspberry Pi Zero 2 W (512MB RAM each, connected via ClusterHAT)
⚠️ Power Supply Required: The Pi 4 requires 5V/3A via USB-C. Use a USB-C to USB-C cable with a proper PD power brick to avoid brownouts under load.
Complete setup guides are in bootstrap/docs/:
- ClusterHAT OS & CNAT setup — image selection, flashing, first boot
- K3s server on Pi 4 — control plane setup
- K3s agents on Pi Zeros — worker setup
- MetalLB load balancer
- Traefik ingress controller
- Longhorn distributed storage (removed — using local-path-provisioner)
- ArgoCD GitOps — deployed via
helmfile sync - Monday AI assistant — Ollama + Open WebUI
Rebuilding after a reflash? →
bootstrap/docs/post-reflash.md
See bootstrap/scripts/README.md for the script reference.
raspi-k3s-cluster/
├── bootstrap/ # One-time setup (manual, hands-off after)
│ ├── scripts/ # Installation scripts
│ │ ├── README.md # Script reference
│ │ ├── install-helm.sh # Helm, Helmfile
│ │ ├── install-k3s-agent.sh # K3s agent on workers
│ │ ├── install-k3s-server.sh # K3s control plane
│ │ ├── set-static-ip.sh # Static IP setup
│ │ ├── setup-agents.sh # Pi Zero agent setup
│ │ ├── setup-controller.sh # Pi 4 controller setup
│ │ └── uninstall-k3s.sh # K3s teardown
│ └── docs/ # Setup guides & architecture
│ ├── 01-clusterhat-setup.md # ClusterHAT hardware & OS
│ ├── 02-k3s-server.md # K3s control plane setup
│ ├── 03-k3s-agents.md # K3s worker setup
│ ├── 04-metallb-load-balancer.md # MetalLB load balancer
│ ├── 05-traefik-ingress.md # Traefik ingress controller
│ ├── 06-longhorn.md # Longhorn — removed, see note in file
│ ├── 08-prometheus-grafana-monitoring.md # Monitoring stack
│ ├── 10-monday-ai-assistant.md # Monday AI assistant (Ollama + Open WebUI)
│ └── architecture.md # Architecture & decisions
│
├── cluster/ # Kubernetes manifests (managed by ArgoCD)
│ ├── core-system/ # Core infrastructure (via helmfile)
│ │ ├── metallb/ # Load balancer
│ │ │ ├── ipaddresspool.yaml # IP pool
│ │ │ ├── l2advertisement.yaml # L2 advertisement
│ │ │ └── values.yaml # Helm values
│ │ └── traefik/ # Ingress controller
│ │ ├── values.yaml # Helm values
│ │ └── traefik-test-ingress.yaml # Test ingress
│ ├── monitoring/ # Monitoring (Prometheus via Kustomize)
│ │ ├── namespace.yaml
│ │ └── prometheus/ # Prometheus StatefulSet + config
│ └── argocd/ # GitOps management (via helmfile)
│ ├── namespace.yaml
│ ├── application-cluster.yaml
│ ├── ingress.yaml
│ └── values.yaml
│
├── workloads/ # User applications (managed by ArgoCD)
│ └── monday/ # Monday AI assistant (Ollama + Open WebUI)
│ ├── namespace.yaml
│ ├── ollama.yaml # Ollama LLM backend + PVC
│ ├── open-webui.yaml # Open WebUI chat interface + PVC
│ ├── ingress.yaml # Traefik ingress → monday.cluster.local
│ └── kustomization.yaml
│
├── helmfile.yaml # Helm release definitions
├── local_ci.sh # Local manifest validation
├── README.md # This file
└── .gitignore
| Directory | Purpose | Managed By |
|---|---|---|
| bootstrap/ | One-time setup scripts & docs | Manual (don't run after setup) |
| cluster/ | Infrastructure-as-code for cluster | ArgoCD (auto-synced from Git) |
| workloads/ | User applications & services | ArgoCD (auto-synced from Git) |
- MetalLB — bare-metal load balancer
- Traefik — ingress controller
- ArgoCD — GitOps continuous deployment
- Ollama — local LLM inference (Monday AI assistant)
- Open WebUI — chat interface for Monday
- kubeconform — Kubernetes manifest schema validation
- Pluto — API deprecation detection
See bootstrap/docs/architecture.md for the full tech stack, network layout, and design decisions.