Files
home-network-k3s-impl/clusters/base/platform.yaml
T
jakman85andClaude Opus 5 22174186ff
gate / gate (push) Has been cancelled
gate / conformance (push) Has been cancelled
chore(flux): restore platform prune:true — MERGE 2 of 2 (Cilium split cleanup)
Closes the transition opened in merge 1 (63f98aa). `prune: true` is restored on the
`platform` Kustomization now that the ownership transfer is VERIFIED on the live cluster,
not merely expected:

  13/13 Kustomizations Ready, `cilium` among them, at main@sha1:23aa2854
  Namespace/kube-system          label kustomize.toolkit.fluxcd.io/name = cilium
  HelmRelease/cilium             label ... = cilium
  HelmRepository/cilium          label ... = cilium
  platform  inventory: 0 entries matching kube-system__Namespace | kube-system_cilium_*
  cilium    inventory: exactly those three objects
  Cilium pods UNCHANGED from the pre-merge baseline —
    cilium-2f8h8 r=0 2026-09-01T05:55:27Z
    cilium-425m8 r=1 2026-08-30T13:25:10Z
    cilium-54cww r=0 2026-09-01T05:55:26Z
  HelmRelease still v11

So the relabel deterministically preceded any prune, exactly as the revision-gated
dependsOn edge predicted, and the ownership move cost zero pod restarts.

The in-file comment now records the lesson rather than the temporary state: before moving
ANY platform/* component in future, check whether it is the sole declarer of a shared
Namespace. platform/cilium/namespace.yaml was the only declaration of Namespace/kube-system
under ./platform, which would have turned a component-scoped prune into
`delete namespace kube-system` — taking coredns, metrics-server, local-path and Cilium.

L0 substitution gate: 103 assertions, 0 hazards.

Serves: R-PLAT-01, R-GITOPS-01.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-09-01 18:39:20 -05:00

78 lines
4.6 KiB
YAML

---
# 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
# Cilium was moved OUT of this tier into its own Kustomization (clusters/base/cilium.yaml)
# on 2026-09-01. `prune: true` is restored here now that the ownership transfer is VERIFIED
# live: Namespace/kube-system, the Cilium HelmRelease and the HelmRepository all carry
# `kustomize.toolkit.fluxcd.io/name=cilium`, this Kustomization's inventory no longer lists
# any of the three, and the `cilium` Kustomization's inventory holds exactly those three.
#
# LESSON WORTH KEEPING: `platform/cilium/namespace.yaml` was the ONLY declaration of
# Namespace/kube-system under ./platform. Moving that path out of a prune:true Kustomization
# made the stale set `delete namespace kube-system` — coredns, metrics-server, local-path AND
# Cilium. Before moving ANY platform/* component in future, check whether it is the sole
# declarer of a shared Namespace; that turns a component-scoped prune into a cluster-scoped one.
prune: true
wait: true # block `apps` until platform is healthy
# ORDERING FIX (2026-09-01 incident: a substitution race that failed OPEN broke Cilium).
#
# `cluster-vars` — the ConfigMap every substituting Kustomization reads — is APPLIED by the root
# `flux-system` Kustomization (clusters/<env>/sync.yaml), not by this one. Without an edge here,
# `platform` could render a manifest from revision N against the revision N-1 `cluster-vars`, so a
# NEWLY ADDED knob was undefined and (non-strict substitution) silently became the EMPTY STRING.
# That is how `k8sServiceHost: ""` reached the Cilium HelmRelease.
#
# `dependsOn` is REVISION-gated, not merely Ready-gated (verified against
# kustomize-controller v1.4.0 `kustomization_controller.go :: checkDependencies`, our version):
# when the dependency shares a GitRepository with the dependent, the dependent cannot reconcile
# revision N until the dependency has APPLIED revision N. Applying revision N is exactly what
# writes a newly-added `cluster-vars` knob — so this one edge closes the race.
#
# `platform` is the ONLY Kustomization in the graph with no `dependsOn`; every other substituting
# consumer (platform-config, apps-wave-0/1/2, apps-vms, oauth2-proxy, headlamp, homepage, crafty,
# velero) chains transitively through it. One edge therefore protects the whole graph.
#
# TRADE-OFF — READ THIS BEFORE YOU CURSE IT: the root is now a GATE. A malformed manifest
# ANYWHERE under the root's path (clusters/<env>, which includes clusters/base) fails the root
# Kustomization and therefore stops `platform` and EVERYTHING downstream, where before this edge
# the rest of the graph would have kept reconciling. That is deliberate and fail-closed: a broken
# entrypoint should stop the line, not let consumers render against a half-applied variable set.
# No deadlock risk — the root runs `wait: false`, so it reaches Ready on APPLY success and never
# health-gates its own children (see clusters/dev/sync.yaml).
dependsOn:
- name: flux-system # the ROOT Kustomization (sync.yaml) that applies cluster-vars
# THE CNI GATES THE TIER. Cilium was split out of ./platform into its own Kustomization
# (clusters/base/cilium.yaml, wait:true) so its health has its own Ready condition and its own
# suspend valve. This edge preserves the ordering that co-tenancy used to provide implicitly:
# nothing in `platform` — and therefore nothing anywhere downstream — reconciles until the CNI
# is healthy. It is also revision-gated, which is what makes the prune-safety argument above
# deterministic rather than a race.
- name: cilium
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.