84 lines
5.3 KiB
Markdown
84 lines
5.3 KiB
Markdown
# 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, CORRECTED 2026-08-17): ArgoCD renders with `helm template` rather than
|
|
running `helm install`, so the lifecycle differs. `lookup` comes back empty (no live cluster at
|
|
render). Hooks are NOT dead: Argo maps Helm hooks onto its sync phases (pre-install/pre-upgrade
|
|
-> PreSync, post-install/post-upgrade -> PostSync); rollback and test hooks have no equivalent.
|
|
Render the way your deployer renders and check where hooks land.
|
|
|
|
## 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.
|
|
|
|
## Page footer - pre-reads + further reading (site convention: every course carries this)
|
|
Pre-reads: Course II (desired state - a chart renders it); working with Kubernetes
|
|
objects (https://kubernetes.io/docs/concepts/overview/working-with-objects/).
|
|
Further reading: Helm docs (https://helm.sh/docs/) and the chart template guide
|
|
(https://helm.sh/docs/chart_template_guide/); Go text/template
|
|
(https://pkg.go.dev/text/template); Helm on OpenShift (via
|
|
https://docs.redhat.com/en/documentation/openshift_container_platform).
|