planck — 20-node Raspberry Pi 4 home lab
20× Raspberry Pi 4 (8GB, ARM64), each booting a 240GB NVMe-in-USB stick. Fresh Raspberry Pi OS Lite (Debian 13) everywhere, running a k3s Kubernetes cluster: servers planck002/003/004 (embedded etcd), workers 001 + 005–020.
Home page: https://carr.pub (served by this cluster).
The map
| Path | What it is |
|---|---|
docs/PLAN.md |
Full history: what was built, every bug and its fix, postmortems. READ FIRST |
docs/IPS.md |
Node ↔ IP ↔ MAC table (static IPs, pinned on nodes) |
docs/INVENTORY.md |
Hardware inventory per node |
scripts/flash-one.sh |
Reimage a node's NVMe stick (run on laptop via pkexec) |
scripts/k3s-join.sh |
Join servers/agents to the cluster (needs K3S_TOKEN) |
scripts/loadtest.sh |
Spawn a k6 load swarm across N nodes |
scripts/inventory.sh |
Regenerate hardware inventory |
manifests/monitoring/ |
Prometheus, node-exporter, Grafana, DDNS CronJob |
manifests/loadtest/ |
k6 rig + practice target |
manifests/web/ |
The carr.pub site + Ingress |
manifests/cluster-issuer.yaml |
Let's Encrypt issuer |
configs/ |
Node password (gitignored), installer internals, retired netboot servers |
Daily operations
- kubectl on the laptop:
~/.local/bin/kubectl(kubeconfig~/.kube/config) - SSH any node:
ssh adamcarr@planck0NN.local(passwordless sudo) - Grafana:
kubectl -n monitoring port-forward svc/grafana 3000:3000 - Load test:
scripts/loadtest.sh <url> [pods] [vus-per-pod] [duration] - New public site: Ingress in
webnamespace on<name>.carr.pubwith thecert-manager.io/cluster-issuer: letsencrypt-prodannotation + DNSimple record
Agent documentation lives in ~/.agents/skills/planck-cluster/SKILL.md
(loaded automatically by opencode sessions).
Safety rules
- Never reboot more than ONE of planck002/003/004 at once (etcd quorum)
- Images must be linux/arm64 multi-arch
- The cluster room switch shares a PSU with nodes 011–015
Description
Languages
Shell
75%
Python
25%