# clusters/ Flux entrypoints and the environment-overlay model (**R-ENV-02**, **R-GITOPS-01/02/03**). Governing spec: [`docs/05-gitops-and-delivery.md`](../../home-network-k3s/docs/05-gitops-and-delivery.md), [`docs/02-environments-and-provisioning.md`](../../home-network-k3s/docs/02-environments-and-provisioning.md), [ADR-0004 (Flux)](../../home-network-k3s/decisions/adr-0004-gitops-flux.md). > Phase 0 scaffolding only. These are structurally-correct stubs. **No cluster exists** — nothing > here reconciles until WS-INFRA delivers a cluster and bootstraps Flux (roadmap Phase 1). ## Layout — base + overlay (never fork the base) ``` clusters/ base/ shared Flux objects (one authoring, both environments) flux-system.yaml GitRepository — the reconciliation source (bootstrap → Gitea) platform.yaml Flux Kustomization → ./platform (reconciles first) apps.yaml Flux Kustomization → ./apps (dependsOn platform) cluster-vars.yaml ConfigMap of overlay knobs (BASE defaults) kustomization.yaml dev/ ACTIVE build target — patches cluster-vars with dev values only kustomization.yaml prod/ DESIGN-ONLY until roadmap Phase 7 — patches cluster-vars with prod values only kustomization.yaml ``` ## How the overlay model satisfies R-ENV-02 The base authors the reconciliation graph **once**. `platform.yaml` and `apps.yaml` (Flux `Kustomization`s) both declare `postBuild.substituteFrom` the `cluster-vars` ConfigMap. Platform and app manifests use `${TOKEN}` placeholders for every value that legitimately differs between environments (issuer, replica counts, storage sizes, retention, node placement). **`clusters/dev` and `clusters/prod` differ ONLY by the values they patch into `cluster-vars`** — they add no resources of their own and never copy/fork a base manifest. Promotion to prod ([`docs/02`](../../home-network-k3s/docs/02-environments-and-provisioning.md)) is a change to the prod overlay's variables, nothing else. ## How Flux is pointed at an environment `flux bootstrap` (run by WS-INFRA in Phase 1) targets one environment's path per cluster: ``` # dev cluster flux bootstrap ... --path=clusters/dev # prod cluster (Phase 7 only — design-only until then) flux bootstrap ... --path=clusters/prod ``` Bootstrap materializes the `flux-system` `Kustomization` that renders the chosen overlay, which pulls in `base/` and applies the env-scoped `cluster-vars`. ## Reconciliation order ``` GitRepository (flux-system) │ ▼ Kustomization: platform (./platform, substituteFrom cluster-vars) │ healthy ▼ Kustomization: apps (./apps, dependsOn platform, substituteFrom cluster-vars) ``` `apps` `dependsOn` `platform` so CNI/storage/TLS/DNS/gateway exist before any workload reconciles. ## TODOs (later phases — do not action in Phase 0) - **Source cutover (WS-GITOPS, Phase 6):** `base/flux-system.yaml` currently points at the bootstrap source. After Gitea is onboarded, repoint `spec.url` to `gitea.home.keithjackson.dev` and keep an off-cluster mirror (spec `docs/05` "Source-of-truth", `CONTRIBUTING.md`). - **SOPS decryption (WS-SEC, Phase 1):** add `spec.decryption.provider: sops` (age secret name only, never plaintext) to the platform/apps Kustomizations once the age key is bootstrapped ([ADR-0007](../../home-network-k3s/decisions/adr-0007-secrets-sops-age.md)). - **Split ordered Flux Kustomizations** if intra-platform ordering needs to be explicit (e.g. a separate `cilium`/`longhorn` Kustomization others `dependsOn`).