T-0.1 Flux GitOps layout + dev/prod overlays + platform component skeletons (R-GITOPS-01/03, R-ENV-02, R-PLAT-01)
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This commit is contained in:
1 parent
bd8de96456
commit
af4f6c07ae
75 files changed
+1638
-4
No files matched your search
+77
-2
@@ -1,3 +1,78 @@
|
||||
# clusters
|
||||
# clusters/
|
||||
|
||||
_Placeholder — populated in Phase 0. See ../home-network-k3s (read-only spec)._
|
||||
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`).
|
||||
</content>
|
||||
@@ -0,0 +1,26 @@
|
||||
---
|
||||
# Flux Kustomization: APPLICATION workloads. Reconciles ./apps AFTER platform is healthy.
|
||||
# Phase 0 STUB. apps/ is owned by WS-APPS; this entrypoint is the GitOps contract that renders it.
|
||||
apiVersion: kustomize.toolkit.fluxcd.io/v1
|
||||
kind: Kustomization
|
||||
metadata:
|
||||
name: apps
|
||||
namespace: flux-system
|
||||
spec:
|
||||
interval: 10m
|
||||
retryInterval: 2m
|
||||
timeout: 5m
|
||||
prune: true
|
||||
wait: true
|
||||
# Ordering: platform (CNI, storage, TLS, DNS, gateway, identity) must be healthy first.
|
||||
dependsOn:
|
||||
- name: platform
|
||||
sourceRef:
|
||||
kind: GitRepository
|
||||
name: flux-system
|
||||
path: ./apps
|
||||
postBuild:
|
||||
substituteFrom:
|
||||
- kind: ConfigMap
|
||||
name: cluster-vars
|
||||
# TODO(WS-SEC, Phase 1): enable SOPS decryption (ADR-0007) — reference age secret by name only.
|
||||
@@ -0,0 +1,41 @@
|
||||
---
|
||||
# cluster-vars — the overlay knob surface (R-ENV-02).
|
||||
#
|
||||
# This ConfigMap holds BASE DEFAULTS. Flux `postBuild.substituteFrom` injects these into every
|
||||
# `${TOKEN}` in platform/ and apps/ manifests at reconcile time. dev/ and prod/ overlays STRATEGIC-
|
||||
# MERGE PATCH this single ConfigMap — that patch is the *entire* difference between environments.
|
||||
#
|
||||
# Add a knob here (with a base default) before referencing `${KNOB}` in a component manifest, then
|
||||
# give each overlay its env-scoped value. Never fork a base manifest to differ per environment.
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: cluster-vars
|
||||
namespace: flux-system
|
||||
data:
|
||||
# --- identity of the environment ---
|
||||
cluster_env: "base" # dev | prod (overlays set this)
|
||||
|
||||
# --- DNS / TLS ---
|
||||
base_domain: "home.keithjackson.dev" # same in both envs (split-horizon per docs/09)
|
||||
acme_cluster_issuer: "letsencrypt-staging" # dev: staging | prod: letsencrypt-prod (ADR-0006)
|
||||
|
||||
# --- storage (ADR-0003) ---
|
||||
longhorn_default_replica_count: "3" # default StorageClass replica count (3 on 3 nodes)
|
||||
|
||||
# --- observability sizing (docs/10) ---
|
||||
monitoring_prometheus_retention: "7d" # dev short | prod long
|
||||
monitoring_prometheus_pvc_size: "10Gi"
|
||||
monitoring_loki_pvc_size: "10Gi"
|
||||
|
||||
# --- identity / auth (ADR-0014) ---
|
||||
keycloak_replicas: "1" # dev 1 | prod 2 (HA)
|
||||
oauth2_proxy_replicas: "1" # dev 1 | prod 2 (HA)
|
||||
|
||||
# --- backup / DR (ADR-0003, R-STATE-03) ---
|
||||
velero_backup_schedule: "0 3 * * *" # cron; overlays may differ
|
||||
velero_retention: "168h" # dev short | prod long
|
||||
|
||||
# --- placement ---
|
||||
platform_node_selector_key: "kubernetes.io/os" # base no-op selector; prod may pin roles
|
||||
platform_node_selector_value: "linux"
|
||||
@@ -0,0 +1,25 @@
|
||||
---
|
||||
# GitRepository — the single source of truth Flux reconciles from (R-GITOPS-01).
|
||||
# Phase 0 STUB: not applied until Flux is bootstrapped in Phase 1 (WS-INFRA).
|
||||
#
|
||||
# Bootstrapping sequence (spec docs/05 "Source-of-truth", CONTRIBUTING.md):
|
||||
# 1. Initially points at the BOOTSTRAP SOURCE (this local repo / out-of-band).
|
||||
# 2. Gitea is onboarded early (roadmap Phase 6).
|
||||
# 3. TODO(WS-GITOPS, Phase 6): repoint spec.url -> https://gitea.home.keithjackson.dev/<org>/home-network-k3s-impl
|
||||
# and keep an off-cluster mirror so a source-of-truth outlives the cluster.
|
||||
apiVersion: source.toolkit.fluxcd.io/v1
|
||||
kind: GitRepository
|
||||
metadata:
|
||||
name: flux-system
|
||||
namespace: flux-system
|
||||
spec:
|
||||
interval: 1m
|
||||
# TODO(WS-INFRA/WS-GITOPS): set to the bootstrap source URL at Phase-1 bootstrap.
|
||||
url: https://REPLACE-ME.invalid/home-network-k3s-impl.git
|
||||
ref:
|
||||
# Reconcile the tracked branch. Overlay may patch this if dev/prod track different branches;
|
||||
# the default model tracks a single branch and differentiates by clusters/<env> path.
|
||||
branch: main
|
||||
# TODO(WS-SEC, Phase 1): reference the SOPS/age or deploy-key secret BY NAME only (no plaintext).
|
||||
# secretRef:
|
||||
# name: flux-system # created by `flux bootstrap`
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
# Base Flux entrypoint set. Shared by BOTH environment overlays (clusters/dev, clusters/prod).
|
||||
# Overlays reference this base and patch ONLY the cluster-vars ConfigMap (R-ENV-02).
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- flux-system.yaml # GitRepository (reconciliation source)
|
||||
- platform.yaml # Flux Kustomization -> ./platform
|
||||
- apps.yaml # Flux Kustomization -> ./apps (dependsOn platform)
|
||||
- cluster-vars.yaml # overlay knob surface (base defaults)
|
||||
@@ -0,0 +1,32 @@
|
||||
---
|
||||
# Flux Kustomization: PLATFORM services (cluster-wide). Reconciles ./platform.
|
||||
# Phase 0 STUB. Realizes R-GITOPS-01/03 (pull-based reconcile + drift correction) and
|
||||
# R-ENV-02 (env differences supplied ONLY via substituteFrom cluster-vars).
|
||||
apiVersion: kustomize.toolkit.fluxcd.io/v1
|
||||
kind: Kustomization
|
||||
metadata:
|
||||
name: platform
|
||||
namespace: flux-system
|
||||
spec:
|
||||
interval: 10m
|
||||
retryInterval: 2m
|
||||
timeout: 5m
|
||||
prune: true # drift correction: delete resources removed from git (R-GITOPS-03)
|
||||
wait: true # block `apps` until platform is healthy
|
||||
sourceRef:
|
||||
kind: GitRepository
|
||||
name: flux-system
|
||||
path: ./platform
|
||||
# R-ENV-02: the ONLY place environment differences enter platform manifests.
|
||||
# dev/prod overlays patch the cluster-vars ConfigMap; the base manifests are never forked.
|
||||
postBuild:
|
||||
substituteFrom:
|
||||
- kind: ConfigMap
|
||||
name: cluster-vars
|
||||
# TODO(WS-SEC, Phase 1): enable SOPS decryption once the age key exists (ADR-0007).
|
||||
# decryption:
|
||||
# provider: sops
|
||||
# secretRef:
|
||||
# name: sops-age
|
||||
# TODO(PM): the top-level ./platform/kustomization.yaml must include platform/kyverno/
|
||||
# (owned by the policy engineer, WS-TEST). See platform/README.md integration TODO.
|
||||
@@ -0,0 +1,46 @@
|
||||
---
|
||||
# clusters/dev — the ACTIVE build target overlay.
|
||||
#
|
||||
# `flux bootstrap ... --path=clusters/dev` points the dev cluster's Flux here.
|
||||
# This overlay adds NO resources of its own. Its ONLY job is to patch the shared cluster-vars
|
||||
# ConfigMap with dev-scoped values (R-ENV-02). The base reconciliation graph is reused verbatim.
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- ../base
|
||||
patches:
|
||||
- target:
|
||||
kind: ConfigMap
|
||||
name: cluster-vars
|
||||
patch: |-
|
||||
- op: replace
|
||||
path: /data/cluster_env
|
||||
value: "dev"
|
||||
# DNS-01 against LE staging while iterating (avoids prod rate limits) — ADR-0006.
|
||||
- op: replace
|
||||
path: /data/acme_cluster_issuer
|
||||
value: "letsencrypt-staging"
|
||||
# dev mirrors prod's 3-node topology, so the replicated tier keeps 3 replicas.
|
||||
- op: replace
|
||||
path: /data/longhorn_default_replica_count
|
||||
value: "3"
|
||||
# smaller retention / volumes to keep the dev workstation footprint light.
|
||||
- op: replace
|
||||
path: /data/monitoring_prometheus_retention
|
||||
value: "3d"
|
||||
- op: replace
|
||||
path: /data/monitoring_prometheus_pvc_size
|
||||
value: "5Gi"
|
||||
- op: replace
|
||||
path: /data/monitoring_loki_pvc_size
|
||||
value: "5Gi"
|
||||
# single-replica control-plane addons in dev (no HA needed to iterate).
|
||||
- op: replace
|
||||
path: /data/keycloak_replicas
|
||||
value: "1"
|
||||
- op: replace
|
||||
path: /data/oauth2_proxy_replicas
|
||||
value: "1"
|
||||
- op: replace
|
||||
path: /data/velero_retention
|
||||
value: "72h"
|
||||
@@ -0,0 +1,47 @@
|
||||
---
|
||||
# clusters/prod — DESIGN-ONLY overlay. NOT a build target until roadmap Phase 7 opens prod
|
||||
# (spec roadmap/phases.md, AGENTS.md §6: "Never build directly on production").
|
||||
#
|
||||
# When Phase 7 is opened, `flux bootstrap ... --path=clusters/prod` points the prod cluster's Flux
|
||||
# here. Like dev, this overlay adds NO resources — it ONLY patches cluster-vars with prod-scoped
|
||||
# values (R-ENV-02). Promotion to prod is a change to THESE variables, never a base edit.
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- ../base
|
||||
patches:
|
||||
- target:
|
||||
kind: ConfigMap
|
||||
name: cluster-vars
|
||||
patch: |-
|
||||
- op: replace
|
||||
path: /data/cluster_env
|
||||
value: "prod"
|
||||
# trusted, rate-limited real certs in prod — ADR-0006.
|
||||
- op: replace
|
||||
path: /data/acme_cluster_issuer
|
||||
value: "letsencrypt-prod"
|
||||
- op: replace
|
||||
path: /data/longhorn_default_replica_count
|
||||
value: "3"
|
||||
# longer retention / larger volumes on prod NVMe.
|
||||
- op: replace
|
||||
path: /data/monitoring_prometheus_retention
|
||||
value: "30d"
|
||||
- op: replace
|
||||
path: /data/monitoring_prometheus_pvc_size
|
||||
value: "50Gi"
|
||||
- op: replace
|
||||
path: /data/monitoring_loki_pvc_size
|
||||
value: "50Gi"
|
||||
# HA control-plane addons in prod.
|
||||
- op: replace
|
||||
path: /data/keycloak_replicas
|
||||
value: "2"
|
||||
- op: replace
|
||||
path: /data/oauth2_proxy_replicas
|
||||
value: "2"
|
||||
- op: replace
|
||||
path: /data/velero_retention
|
||||
value: "720h"
|
||||
# TODO(WS-INFRA, Phase 7): pin prod node placement once the bare-metal role labels exist.
|
||||
Reference in new issue
Block a user