twenty-four: the platform
This is the infrastructure that makes twenty-four possible.
The Cluster
k3s on a mix of hardware that was lying around:
Control plane:
master- Ubuntu 22.04, x86_64, handles scheduling
Workers:
arm1,arm2,arm3- Fedora Asahi Remix on Apple Silicon (M1/M2 Mac Minis)lab- Ubuntu 24.04, x86_64, old desktop turned compute nodebrain- Ubuntu 24.04, x86_64, currently offline (it’ll be back)
The ARM nodes do most of the work. They’re fast, quiet, and sip power. The x86 box handles anything that doesn’t have ARM builds yet.
Networking: The .home Domain
Everything runs on .home. Local DNS via dnsmasq on my router (192.168.0.1), which forwards .home queries to CoreDNS in the cluster (10.233.64.1).
|
|
MetalLB provides LoadBalancer IPs in the 10.233.64.x - 10.233.66.x range. Each service gets its own IP, exposed on port 80. No Ingress controller, no reverse proxy complexity. Just HTTP on the LAN.
Works great until I’m not on my LAN. Then it doesn’t work at all. That’s fine - these services are for me, at home.
Storage: Synology NFS
Persistent volumes backed by a Synology NAS (192.168.1.2) via the Synology CSI driver.
AWS S3, of course.
The Build System
Multi-arch is non-negotiable when you’re running arm64 + amd64. Docker Buildx with remote BuildKit instances in the cluster:
- BuildKit AMD64 - 10.233.65.3:1234 (runs on
lab) - BuildKit ARM64 - 10.233.66.9:1234 (runs on
arm1/arm2/arm3)
Every make dbuild pushes to both architectures, creates a multi-arch manifest, and shoves it into the local registry at docker.registry.home:5000.
Standard Makefile pattern (used across all services):
|
|
Git SHA as the version tag. Deploy updates the image and k8s pulls from the local registry. No Docker Hub rate limits, no external dependencies.
Deployment Pattern
Every service follows the same structure:
|
|
Node affinity targets ARM where possible. LoadBalancer type gets a MetalLB IP automatically. Health checks at /health, version info at /version, logs at /logs.
It just makes it so much easier.
See also: Part 1: Building with Claude | Part 2: Calendar Service | Part 3: Gym Service | Part 4: Strava Service | Part 5: Workout Generator | Part 6: AI Recommendations | Part 7: Service Consolidation | Part 8: What’s Next
🤖 Generated with Claude Code
Co-Authored-By: Claude noreply@anthropic.com