#Why self-host a cluster at all
This is a draft I’ll keep expanding — right now it’s the skeleton of the
story, not the full write-up. The short version: I got tired of paying
monthly for things a $150 mini-PC and a weekend could replace, and I wanted
to actually understand Kubernetes by running it for real workloads instead
of a toy minikube on my laptop.
The constraint that shaped everything: no clicking things into existence.
If a change isn’t in git, it doesn’t happen. That single rule is why
everything below ends up going through Flux instead of kubectl apply from
a terminal at midnight.
#The bootstrap: flux-template
The cluster itself is unremarkable — a few nodes running k3s, chosen
specifically because it strips out the parts of full Kubernetes I didn’t
need (in-tree cloud provider stuff, some default addons). What makes it
repeatable is a small repo I built called flux-template: point it at a
fresh k3s install, and it bootstraps Flux, sets up the base
GitRepository/Kustomization objects, and hands control of the cluster
back to git.
A trimmed version of the bootstrap kustomization looks like this:
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: apps
namespace: flux-system
spec:
interval: 10m
path: ./clusters/home/apps
prune: true
sourceRef:
kind: GitRepository
name: flux-system
dependsOn:
- name: infra
Every service on the cluster — immich, harbor, nextcloud, the gitlab
runners — is just another directory under clusters/home/apps, reconciled
the same way.
#What’s still provisional here
- Diagrams of the node/network layout — not drawn yet.
- The actual hardware list and why I picked it.
- How storage/backups are wired (NAS + off-site) — deserves its own section.
- A honest section on what broke and what I’d do differently.
#Next up
Once the diagrams exist I’ll split “how it’s bootstrapped” from “what runs on it” — this piece is trying to do both right now and it shows. For the current state of what’s actually deployed, see the homelab page.