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]>
78 lines
4.6 KiB
YAML
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.
|