--- # 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) # Cilium (the CNI) — its OWN Kustomization, split OUT of `platform` (2026-09-01). The mirror image # of the oauth2-proxy/headlamp splits: those are leaves that must never gate a tier (wait:false); # Cilium is the one component that legitimately SHOULD gate everything, so it keeps wait:true and # `platform` dependsOn it. Splitting it out buys a per-CNI Ready condition, CNI-appropriate # interval/timeout, and `flux suspend kustomization cilium` as an emergency valve that does not # freeze the other eleven platform components. See clusters/base/cilium.yaml. - cilium.yaml # Flux Kustomization -> ./platform/cilium (dependsOn flux-system, wait:true) - platform.yaml # Flux Kustomization -> ./platform (CONTROLLERS: HelmReleases / CRDs) - platform-config.yaml # Flux Kustomization -> ./platform-config (CONFIGS: CRs; dependsOn platform) # SECOND-ORDER CDI configs — CRs whose CRD is created by a controller AT RUNTIME, not by any # manifest in git. cdi-operator.yaml registers only `cdis.cdi.kubevirt.io`; `storageprofiles` (and # datavolumes, datasources, …) appear only after cdi-operator reconciles the `CDI` CR that # platform-config applies. Because Flux dry-runs every object in a pass before applying any of them, # keeping the StorageProfiles in platform-config was a TRUE DEADLOCK (unknown kind -> pass aborts -> # CR never applied -> CRD never created -> tier never converges), invisible on dev and fatal on any # cold cluster — observed on prod 2026-09-05. This tier is the durable fix; `standup.sh crds` stays # as the belt-and-braces repair for clusters already wedged. See clusters/base/platform-config-cdi.yaml. - platform-config-cdi.yaml # Flux Kustomization -> ./platform-config-cdi (dependsOn platform-config) # App tier, split into dependency-ordered WAVES (was the single ./apps `apps` Kustomization). # Each apps-wave- dependsOn wave N-1 (wave 0 dependsOn platform-config) and health-gates # (wait:true) ONLY its own wave, so a crashloop in a later wave can't stall an earlier one. # GENERATED by `catalog/render.py --emit-waves`; add a line here only when a NEW deepest wave # is introduced (a service deeper than any existing wave). See DESIGN-waves.md. - apps-wave-0.yaml # Flux Kustomization -> ./apps/wave-0 (dependsOn platform-config) - apps-wave-1.yaml # Flux Kustomization -> ./apps/wave-1 (dependsOn apps-wave-0) - apps-wave-2.yaml # Flux Kustomization -> ./apps/wave-2 (dependsOn apps-wave-1) # VM tier (KubeVirt) — non-gating (wait:false), separate lifecycle from the app waves. - apps-vms.yaml # Flux Kustomization -> ./apps/vms (dependsOn platform-config) - conformance.yaml # Flux Kustomization -> ./conformance/incluster (non-gating; R-SEC-02 trigger identity) # oauth2-proxy forward-auth — POST-platform tier (dependsOn platform-config, wait:false). A leaf # service that needs Keycloak + trusted TLS + split-horizon DNS must NOT sit in the gating # `platform` tier, where it self-gated its own dependencies into a cold-start deadlock (twice). - oauth2-proxy.yaml # Flux Kustomization -> ./platform/oauth2-proxy (dependsOn platform-config) # headlamp dashboard — POST-platform tier (dependsOn platform-config, wait:false). A leaf UI whose # HelmRelease can crashloop (upstream headlamp-0.40.1 `-session-ttl` chart/image desync) must NOT # sit in the gating `platform` tier, where its unhealth stalled platform-config + oauth2-proxy + # every apps wave/vm on "dependency not ready" (DECISIONS-LOG: "Headlamp gating stall"). - headlamp.yaml # Flux Kustomization -> ./platform/headlamp (dependsOn platform-config) # Homepage apex landing dashboard — POST-platform tier (dependsOn platform-config, wait:false). # A leaf UI at home.keithjackson.dev; same non-gating rationale as headlamp/oauth2-proxy (a UI must # never gate the platform chain). Carries no SOPS secret, so clusters/dev adds no decryption patch. - homepage.yaml # Flux Kustomization -> ./platform/homepage (dependsOn platform-config) # Crafty Controller — Minecraft management UI, web UI Keycloak-gated by a per-pod oauth2-proxy # reverse-proxy sidecar (Option B). POST-platform tier (dependsOn platform-config, wait:false); same # non-gating leaf-UI rationale as headlamp/homepage/oauth2-proxy (a UI must never gate the platform). - crafty.yaml # Flux Kustomization -> ./platform/crafty (dependsOn platform-config) # Alert runbooks — POST-platform tier (dependsOn platform-config, wait:false). Serves the 34 # runbooks the alert rules' `runbook_url` annotations point at, at /runbooks/; before # this tier existed that path was a 404 and every alert handed the operator a dead link. Same # non-gating leaf rationale as headlamp/homepage/crafty. Carries NO postBuild substitution on # purpose — it renders documentation containing `${...}` shell examples that envsubst would empty; # see clusters/base/runbooks.yaml. - runbooks.yaml # Flux Kustomization -> ./runbooks (dependsOn platform-config) # Velero backup controller — POST-platform tier (dependsOn platform-config, wait:false). A backup # controller must NEVER gate the platform chain; same non-gating rationale as headlamp/oauth2-proxy. # Carries velero-cloud.sops.yaml, so clusters/dev adds a SOPS decryption patch for it (by name). - backup.yaml # Flux Kustomization -> ./platform/velero (dependsOn platform-config) - cluster-vars.yaml # overlay knob surface (base defaults)