Files
exploded-cluster/content/course-VIII-helm-contexts.md
T

4.7 KiB

Course VIII - Helm: Go templates, values contexts, one chart for a fleet

Series position: third course of the delivery arc. VI taught how change travels, VII how images are named; this course teaches how ONE definition serves MANY clusters. Safety gate: public site - technologies only. Claims source from helm-charts, yaml-manifest-style, kustomize-inflate-helm (the ArgoCD render caveat), the one-value-many-enforcers post (live on the blog - cross-link it), Helm/Go public docs.

Title (thesis)

A chart is a function. The values file is the cluster speaking.

Hook - the uncomfortable default

The default way to run one app on five clusters is five copies of the YAML, and the default result is five slightly different apps - each copy drifting on its own schedule, each "quick fix" applied to some of them. The inversion: stop copying outputs and ship the FUNCTION instead. A Helm chart is a template with holes; each cluster supplies one small values file that fills them; the rendered manifests are build artefacts nobody hand-edits, ever.

Move 1 - It's Go under the braces

Helm templates are Go text/template: {{ .Values.camera.address }} is a pipeline walking a values object, _helpers.tpl holds named template functions (labels, names) every manifest calls, and include/toYaml/default compose them. The mental shift: you are not writing YAML, you are writing a program whose OUTPUT is YAML - so render locally (helm template), read the output, and lint what came out, not what went in. Say it like you mean it: review the render, not just the template. FIELD NOTE (amber): ArgoCD deploys charts by running helm template - a pure render. Anything that needs a live cluster or an install lifecycle (lookup, hooks) is silently dead there. A chart that works under helm install can behave differently under GitOps - render the way your deployer renders.

Move 2 - Contexts: the cluster's whole voice is one small file

The fleet pattern: the chart owns EVERYTHING structural - resources, probes, security contexts, policy - and each cluster owns one values file (its context): names, addresses, sizes, feature flags. The context is deliberately values-only; the moment a context carries its own manifests, there are two owners for one object and they will disagree. One value can feed many rendered artefacts - an address appearing in the app config, the network attachment and two policies renders from ONE field, so the copies cannot diverge (the blog post "Consistency by construction beats consistency by discipline" is this move, lived). Say it like you mean it: the chart owns the shape; the context owns the numbers.

Move 3 - Make the template refuse

A template that renders whatever it is given just moves the failure downstream. The grown-up chart carries a values.schema.json: required fields, types, enums - and a cluster whose context omits a required value FAILS AT RENDER TIME with a message naming the field, in the pipeline, before anything ships. Same discipline inside the template: required "camera.address is required" .Values.camera.address beats a silent empty string that becomes a policy pointed at nothing. FIELD NOTE: the failure you want is the render that refuses - it costs a red pipeline. The failure you get otherwise is enforcement aimed at an address nothing lives at, months later, reporting healthy the whole time.

Close

Fleet consistency is not a discipline problem, it is a construction problem. Ship one function, let each cluster speak one small file of facts, and make the function refuse to run on missing facts. Divergence stops being something you police and becomes something the tooling cannot express.

Legend terms (DOM layer)

chart / template / Go text-template / pipeline / _helpers.tpl / values / context / values.schema.json / required / render (helm template) / one source many renders

Scene concept (hero + slices, the v3 mechanism)

Exploded press-works, centre-out: an engraved PRESS PLATE (the chart - dark slab, its face carrying an abstract lattice of rectangular voids, the "holes" clearly empty) -> three small VALUES CRYSTALS (per-cluster contexts - compact faceted gems, cyan, one subtly larger) feeding toward it from the left -> on the right, three thin RENDERED SHEETS fanned apart, identical framework but each carrying a different accent pattern (same shape, different numbers) -> below, a GATE WEDGE (the schema - amber-white edge, Course III's gatekeeper silhouette re-used) with one dim REJECTED SHEET stopped at it. 7 parts, generous void, no connectors. Slice plan: collapse draws crystals + sheets into the press (one machine at rest); the rejected sheet collapses BEHIND the gate, never past it - the visual argument for Move 3.