The lab is a Kubernetes testbed: try cluster layouts here before they go to production. After a short manual bootstrap, Flux keeps the cluster in sync with Git — the usual GitOps loop of declared state in version control and controllers that apply diffs.
Nodes run Talos Linux on Turing Pi RK1 boards. Images come from the
Talos Image Factory (metal-arm64, sbc-rockchip / turingrk1). Talos keeps the
node OS small and API-driven: you do not SSH in to patch packages. That pushes complexity into Kubernetes
manifests, which fits a GitOps workflow.
Everything after the first bootstrap lives in one monorepo: cluster overlays, shared operators, Helm charts,
and application kustomizations. Talos machine config (talconfig) is versioned there too, but applied with
talosctl, not Flux. Drawing that line clearly avoids pretending the entire world is reconciled from Git when
the hypervisor and disk layout are still operator steps.
Stack (what each piece teaches)
| Piece | Learn more |
|---|---|
| Talos | API-driven, immutable nodes — no SSH shell on hosts |
| Flux | GitRepository, Kustomization, HelmRelease |
| Kustomize + Helm | Overlays vs charts — choose per app |
| SOPS + AGE | Encrypted secrets in Git; decrypted at reconcile |
| Vault + External Secrets | Long-lived credentials outside plain Git |
| Cilium | CNI; BGP can advertise service LoadBalancer ranges |
| Gateway API + Envoy Gateway | HTTP and TCP ingress |
| cert-manager | ACME and in-cluster CAs |
| Rook-Ceph | Block, filesystem, and S3-style storage |
| Renovate | Automated bumps for image and chart pins |
Bootstrap, then GitOps
flash Talos (RK1) -> talosctl bootstrap -> flux bootstrap
Git becomes the source of truth
One monorepo holds shared common/ operators and per-cluster overlays. The GitRepository uses an ignore
block so Flux does not clone agent code, docs, or unrelated trees on every reconcile. That keeps sync intervals
reasonable on modest hardware.
How a change rolls out
Git branch (main)
-> GitRepository (poll)
-> common layer (Flux, Cilium, cert-manager, ...)
-> repo definitions (Helm/OCI)
-> app overlays (your workloads)
-> HelmRelease, HTTPRoute, PVC, ExternalSecret, ...
dependsOn orders that graph (storage before apps, for example). postBuild substitution reads
common-config and fills hostnames — this-is-fine.io, this-is-fine.social, this-is-fine.internal,
tif.internal — so the same manifests work on every cluster without per-site forks.
Bootstrap secrets use SOPS; runtime passwords and tokens live in Vault and sync through External Secrets. The split mirrors how often values change: bootstrap keys rotate rarely; database passwords and API tokens churn more often and are easier to audit in Vault.
Renovate watches the same repo and opens bump PRs for container images, Helm charts, and Talos or Flux pins. That closes the loop so the lab does not silently fall behind upstream.
DNS zones (quick map)
this-is-fine.io public internet (ACME, external gateway)
this-is-fine.social fediverse
this-is-fine.internal lab UIs (internal gateway, Vault PKI)
tif.internal Headscale tailnet (MagicDNS)
Takeaway
Talos limits the OS problem; Flux limits the “what is actually deployed?” problem. Together they give a repeatable lab: flash boards, bootstrap once per cluster, then iterate by merge request like any other software project.
More on this setup: ZeroClaw, Envoy Gateway, Cilium BGP, Zot, Pocket ID, backups, tailnet, image signing.