--- # Controller-level customization of the Flux CONTROLLERS themselves (the `flux-system` Deployments). # # WHY THIS DIRECTORY EXISTS # ========================= # This repo does NOT use `flux bootstrap` (see ../README.md "Why `flux install` + apply"): the # reconciliation graph is authored by hand in clusters/base, and the controllers are installed # imperatively by `flux install`. Consequence, verified on the live dev cluster 2026-09-01: # # kubectl -n flux-system get deploy kustomize-controller -o jsonpath='{.metadata.labels}' # -> NO kustomize.toolkit.fluxcd.io/name label, deployment.kubernetes.io/revision: 1 # # i.e. **the controllers are not managed by Flux and are not in git.** There was therefore no # existing mechanism to customize them, and no amount of editing under clusters/** can reach them. # # This is the mechanism Flux documents for exactly that situation ("Customize Flux manifests" — # https://fluxcd.io/flux/installation/#customize-flux-manifests): export the component manifests # with `flux install --export`, overlay them with kustomize `patches:`, and apply the result. # `../bootstrap.sh` step 1 does that render — it copies THIS file next to a freshly exported # `gotk-components.yaml` in a temp dir and runs `kubectl apply -k`. Nothing is generated into the # repo, so the manifests can never drift from the pinned FLUX_VERSION # (infra/devcontainer/versions.env) the way a vendored copy would. # # Every future controller customization (vertical scaling, tolerations, extra feature gates, # --concurrent) belongs HERE, as another entry under `patches:`. apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: # Written by `bootstrap.sh` from `flux install --export ...` at render time. NOT checked in. - gotk-components.yaml patches: # ------------------------------------------------------------------------------------------- # StrictPostBuildSubstitutions — make postBuild substitution FAIL CLOSED. # # Default behaviour is fail-OPEN: a `${VAR}` that is not defined in `cluster-vars` renders as the # EMPTY STRING, silently. On 2026-09-01 that shipped `k8sServiceHost: ""` into the Cilium # HelmRelease and put 2 of 3 agents into Init:Error (DECISIONS-LOG, INCIDENT entry). With this # gate the undefined variable FAILS the Kustomization instead, and Flux keeps the last-good state. # # PROVEN SAFE before enabling: every one of the 11 substituted paths was rendered with # `kubectl kustomize --load-restrictor LoadRestrictionsNone | flux envsubst --strict` and # exited 0, with a negative control reproducing the incident. The permanent guard that keeps it # true is the L0 gate conformance/tests/l0-static/flux-postbuild-substitution/. # # NOTE the gate does NOT catch default-providing forms (`${VAR:-d}`, `${VAR:?msg}`, `${VAR:=v}`) — # Flux exempts them by design. That class is what the L0 gate covers; the two are complementary. # # This also pre-pays for the Flux 2.4.0 -> 2.9.x upgrade: strict substitution became DEFAULT-ON in # kustomize-controller v1.9.0, so the upgrade flips this behaviour whether or not we opt in. # # JSON-6902 `add ... /args/-` (append), NOT a strategic merge: a container's `args` is an atomic # list, so a strategic-merge patch would REPLACE every arg `flux install` generates # (--events-addr, --watch-all-namespaces, --log-level, --log-encoding, --enable-leader-election) # and silently drop any the CLI adds in a future version. - target: group: apps version: v1 kind: Deployment name: kustomize-controller namespace: flux-system patch: |- - op: add path: /spec/template/spec/containers/0/args/- value: --feature-gates=StrictPostBuildSubstitutions=true