delivery arc VI-VIII: course briefs (GitOps, supply chain, Helm contexts) + NB2 scene prompts 09-11

This commit is contained in:
2026-08-17 12:44:44 +10:00
parent 5cce8c5cd3
commit 7caa9d5342
6 changed files with 391 additions and 0 deletions
+68
View File
@@ -0,0 +1,68 @@
# Course VI - GitOps: ArgoCD, the GitHub linkage, and the one thing git never holds
**Series position:** first course of the delivery arc (VI-VIII). The main menu taught the
machine; this arc teaches how software REACHES it.
**Safety gate:** public site, real name - technologies only, zero employer/industry framing.
Claims source from [[argocd-stacks]], [[gitops-iac-rigor]], [[eso-infisical-secrets]]
(generalised to the Azure Key Vault worked example), [[authentik-oidc]] not needed here.
## Title (thesis)
**Nobody deploys anything. The cluster syncs itself.**
## Hook - the uncomfortable default
The mental model everyone arrives with: a person (or a pipeline) with credentials pushes
manifests at the cluster. Deploy = an action someone performs, kubectl apply = the verb.
The inversion: in GitOps nothing is pushed. A repository holds the desired state, an agent
inside the cluster watches it, and the cluster pulls its own future from git. kubectl is
for looking, git is for changing.
## Move 1 - The loop you already know, one level up
Course II taught the reconciliation loop: desired vs actual, fix the difference, repeat.
ArgoCD is the same habit applied to DELIVERY. An Application names a repo + path + revision
(the GitHub linkage: watch this branch of this repository); the controller renders what it
finds there, compares it against the live cluster, and shows the diff. Sync = make actual
match desired. The deploy button is a git commit; the audit log is git log; code review IS
change control.
Say it like you mean it: **kubectl apply is for archaeology, not for change.**
## Move 2 - Pull, not push - the security inversion
The load-bearing detail everyone misses: the cluster PULLS. No CI system, no laptop, no
GitHub Action holds a credential that can touch the cluster. The agent inside the cluster
holds a read-only deploy key to the repo - the trust arrow points OUT. Compromise the build
system and you can propose a change (a commit, which is visible); you cannot reach into
production. Drift works the same way: hand-edit a live object and the controller flags it
OutOfSync - with selfHeal on, it puts it back; with prune on, what leaves git leaves the
cluster. Rollback is `git revert`, which is why commit hygiene is an operational skill.
FIELD NOTE (amber): fighting the reconciler by SSH/kubectl is arm-wrestling a machine that
does not get tired (Course II's note, now with a face). The fix is always upstream, in git.
## Move 3 - The one thing git never holds
Git holds everything - manifests, charts, config, the whole desired state - except secrets.
A secret in git is published, forever, to everyone who ever clones. So the pattern splits
the reference from the value: git carries an ExternalSecret manifest naming a LOGICAL key
("this app needs db-password from the vault"); a vault - Azure Key Vault as the worked
example, any ESO-supported store works - holds the value; an operator inside the cluster
exchanges the reference for the value at runtime and keeps it synced. Rotation happens in
the vault, never as a commit.
Say it like you mean it: **git holds the shape of the secret, the vault holds the secret.**
FIELD NOTE: the day a real credential lands in a commit, it is spent - history rewrites do
not un-publish it. Rotate first, tidy git second.
## Close
Delivery stops being an event and becomes a property: the cluster is always converging on
what the repository says. The question "who deployed this?" becomes "who merged this?" -
and that question always has an answer.
## Legend terms (DOM layer)
Application (repo + path + revision) / desired vs actual / sync / drift / selfHeal /
prune / pull model / deploy key / ExternalSecret / vault reference / rotation
## Scene concept (hero + slices, the v3 mechanism)
Exploded chain, upper-left to lower-right: a faceted crystal SLAB etched with branching
lattice (the repository) -> a compare-loop ENGINE with two counter-rotating ring motifs
(ArgoCD: desired vs actual) -> a stack of thin rendered SHEETS (manifests) -> the cluster
CORE (Course II's command slab, familiar silhouette) -> off-axis, drifting away dimmed: a
small GHOST SHARD (the hand-edit being reverted). Separate armoured VAULT BOX floating
above the chain, apart from everything (the secret store - deliberately not in line).
6 parts, no connectors. Slice plan: collapse packs chain into the engine; vault stays
apart even collapsed (it is never absorbed into the pipeline - the visual argument).
+75
View File
@@ -0,0 +1,75 @@
# Course VII - The image supply chain: registries, mirrors, tags and digests
**Series position:** second course of the delivery arc. Course I taught what an image IS;
this course teaches how one travels - and how to say its name precisely.
**Safety gate:** public site - technologies only. Claims source from [[zot-registry]],
[[homelab-pull-through-registry]], [[work-container-image-tagging]] (generalised: the
calendar-rev pattern taught as "a human tag scheme", no corp framing), Azure Container
Registry as the generic managed-registry example, OpenShift IDMS behaviour from public
Red Hat docs.
## Title (thesis)
**A tag is a promise. A digest is a fact.**
## Hook - the uncomfortable default
`myapp:latest` feels like a name. It is not - it is a sticky note. A tag is a mutable
pointer anyone with push rights can peel off one image and press onto another, and
nothing anywhere records that it moved. The digest - sha256 of the content - is the
image's actual name: same bytes, same digest, forever. Most outages in this territory
begin with two machines both holding "the same tag" and running different code.
## Move 1 - Say the name properly
Three ways to name an image, in rising order of honesty: `:latest` (a moving target),
`:1.4.2` (a promise somebody keeps, until they re-push it), `name:1.4.2@sha256:...`
(a fact - the tag stays for human eyes, the digest does the pulling). Content-addressing
is the same idea git uses for commits: the name IS the bytes. Pin by digest and "what is
running?" has exactly one answer.
Say it like you mean it: **the tag is for reading, the digest is for pulling.**
FIELD NOTE (amber): `:latest` is how two nodes run different code from one manifest -
the second node pulled an hour later, after a re-push. Nobody changed the YAML.
## Move 2 - Why a fleet pulls once
Between the build and the node sits the registry chain. Upstream, a managed registry
(Azure Container Registry as the worked example) holds what CI built. In front of the
cluster sits a MIRROR - a pull-through cache like zot: the fleet asks the mirror, the
mirror asks upstream once, everything after is local. Three reasons this exists: rate
limits and egress cost (a hundred nodes should not make a hundred internet pulls),
availability (the fleet boots even when upstream is down or the site is disconnected),
and control (one place to gate, scan and audit what enters). OpenShift formalises the
re-route with image mirror rules - and carries a sharp edge: its digest-mirror rules
rewrite DIGEST pulls only, so a by-tag pull silently skips the mirror. The pinning habit
from Move 1 is what makes the mirror actually catch the traffic.
FIELD NOTE: a mirror can also serve a STALE tag->digest mapping while upstream moved the
tag. Pin by digest and the whole chain becomes content-addressed - the mirror cannot be
wrong about a hash.
## Move 3 - Build once, promote by copy
The anti-pattern: rebuild the image for each environment ("the prod build"). Every
rebuild is a different artefact - different digest, different bytes, untested by the
stages before it. The discipline: build ONCE, then PROMOTE the same digest through
environments by copying (skopeo copy, registry to registry) - dev proves the exact bytes
prod will run. Human-readable tags ride along (a calendar-plus-revision scheme reads well:
month, year, revision), but the digest is the through-line; promotion never changes it.
Say it like you mean it: **if the digest changed, it is not a promotion - it is a new
candidate.**
## Close
Everything in this course is one idea wearing three coats: names that can move are
convenient exactly until they move. Address content by what it IS, let humans keep their
readable labels, and the supply chain stops being a chain of trust and becomes a chain
of arithmetic.
## Legend terms (DOM layer)
tag / digest / content-addressing / pull-through mirror / disconnected pull / rate limit /
image mirror rule (digest-only rewrite) / build-once / promotion / skopeo copy
## Scene concept (hero + slices, the v3 mechanism)
Exploded left-to-right journey: the layered image CUBE from Course I (familiar - four
thin slabs, tight formation, reads as one unit now) -> upstream registry TOWER (tall
managed vault, cool white-cyan) -> the mirror WAY-STATION (squat wide cache block, warm
cyan, visibly closer to the cluster side) -> the node/cluster CORE. Floating above the
journey, two seal plates apart from each other: a GHOST RIBBON plate (the tag - faint,
translucent, edges blurring) and an ENGRAVED SEAL plate (the digest - dense, crisp,
crystalline). 6 parts, generous void, no connectors. Slice plan: collapse draws the
journey into the mirror block (everything local); the two seals collapse toward each
other but never merge - ghost stays ghost.
+74
View File
@@ -0,0 +1,74 @@
# 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.
+58
View File
@@ -0,0 +1,58 @@
# Scene prompt - Course VI: GitOps (repo -> reconciler -> cluster, vault apart)
Delivery arc scene A. Six parts; the vault deliberately floats APART from the chain -
that separation is the teaching point, keep it in curation.
Generate ~4 at 16:9, curate with the reject checklist, save to disk for pickup.
---
Dark technical exploded-view illustration in a cinematic sci-fi engineering style.
Solid near-black deep void background, hex #070b14 - completely clean: no stars, no grid,
no texture, no particles behind or around the objects. Matte dark metal-and-glass surfaces
with glowing neon edge lighting: primary cyan #3fbaf5, secondary magenta #e879f9 accents,
cool white rim highlights. Camera: fixed 30-degree isometric angle, subject perfectly
centered with generous empty margins on all sides. Even studio lighting, no vignette,
no lens flare, no depth-of-field blur. ABSOLUTELY NO text, no letters, no numbers, no
words, no code, no glyphs, no labels, no arrows, no callout lines, no UI elements
anywhere in the image - every surface marking must be an abstract geometric pattern
only. Every component is fully separated from its neighbours by generous gaps of pure
void - nothing touching, nothing overlapping, and no beams, cables, or connectors
spanning between the separated parts.
The subject: a descending diagonal chain of machines from upper left to lower right,
each floating alone in void, plus one outlier above.
First, upper left: a large faceted crystal slab of dark glass, its surface etched with
a fine branching lattice pattern glowing soft cyan, like frozen forks of a river - a
monument of recorded history.
Second: a compact engine block with two counter-rotating rings recessed into its face,
one ring glowing cyan and the other magenta, caught mid-comparison - the busiest, most
mechanical object in the scene.
Third: a neat stack of three thin rigid rectangular sheets with faint cyan edge seams,
crisp and freshly minted, hovering in perfect alignment.
Fourth, lower right: a wide commanding slab of dark brushed metal with a strong cyan
glowing seam around its edge - the authority the chain serves.
Fifth, drifting below and away from the fourth slab, tilted and dim: a small broken
shard with a weak grey-magenta ember glow, clearly falling out of the composition.
Sixth, floating high above the whole chain and clearly apart from it: a small heavily
armoured vault cube - layered dark plates, one thin amber-white glowing seam - sealed,
dense, deliberately distant from everything else.
---
## Build-side notes (not part of the prompt)
- **Slice plan:** 6 polygons - repo crystal, reconciler engine, rendered-sheet stack,
cluster slab, drift shard, secret vault. Collapse packs the chain into the engine;
the VAULT keeps its distance even collapsed (never absorbed into the pipeline - the
Move 3 visual argument). Drift shard exits as the legend hits selfHeal. Clamp at hero.
- **Legend mapping:** repo "desired state - the deploy button is a commit" / engine
"ArgoCD: compare, diff, sync" / sheets "rendered manifests" / slab "actual state -
Course II's cluster" / shard "drift - reverted by selfHeal" / vault "the one thing
git never holds - logical reference in git, value in the vault".
- **Watermark:** Gemini sparkle bottom-right - strip before slicing (ffmpeg delogo).
+58
View File
@@ -0,0 +1,58 @@
# Scene prompt - Course VII: the image supply chain (registry -> mirror -> node; tag vs digest)
Delivery arc scene B. Six parts; the two seal plates must read as GHOST vs ENGRAVED -
that contrast carries the whole thesis. The image cube is Course I's stack in tight
formation (visual callback).
Generate ~4 at 16:9, curate with the reject checklist, save to disk for pickup.
---
Dark technical exploded-view illustration in a cinematic sci-fi engineering style.
Solid near-black deep void background, hex #070b14 - completely clean: no stars, no grid,
no texture, no particles behind or around the objects. Matte dark metal-and-glass surfaces
with glowing neon edge lighting: primary cyan #3fbaf5, secondary magenta #e879f9 accents,
cool white rim highlights. Camera: fixed 30-degree isometric angle, subject perfectly
centered with generous empty margins on all sides. Even studio lighting, no vignette,
no lens flare, no depth-of-field blur. ABSOLUTELY NO text, no letters, no numbers, no
words, no code, no glyphs, no labels, no arrows, no callout lines, no UI elements
anywhere in the image - every surface marking must be an abstract geometric pattern
only. Every component is fully separated from its neighbours by generous gaps of pure
void - nothing touching, nothing overlapping, and no beams, cables, or connectors
spanning between the separated parts.
The subject: a left-to-right journey of four machines floating alone in void, with two
contrasting plates floating above the journey.
First, far left: a compact stack of four thin square slabs in tight vertical formation
with narrow void gaps - dark metal, cyan edge seams, one faint magenta accent slab -
reading as one shipped unit.
Second: a tall slender registry tower - dark metal with vertical ranks of small
recessed cells, each cell holding a faint cool white-cyan glow, an archive of many
sealed compartments.
Third: a squat wide way-station block - heavy, low, cache-like, with a broad warm cyan
glowing intake recess on its upstream face and thick armoured sides.
Fourth, far right: a dark cluster core - a compact commanding block with a strong cyan
glowing seam, the destination of the journey.
Above the journey, two flat plates floating side by side with clear void between them:
the left plate a GHOST - semi-transparent frosted glass, edges softly dissolving, a
faint magenta ribbon motif barely visible on its face; the right plate ENGRAVED - dense
dark crystal, crisp hard edges, a deep precise geometric seal pattern cut into its face
glowing steady cyan.
---
## Build-side notes (not part of the prompt)
- **Slice plan:** 6 polygons - image stack, registry tower, mirror way-station, cluster
core, ghost plate (tag), engraved plate (digest). Collapse draws the journey into the
mirror block (everything local); the two plates collapse toward each other but never
merge. Clamp at hero.
- **Legend mapping:** image stack "Course I's layers, shipped" / tower "upstream managed
registry (ACR as the worked example)" / way-station "the pull-through mirror (zot) -
the fleet pulls once" / core "the node pulls local" / ghost plate "tag - a promise
that can move" / engraved plate "digest - a fact that cannot".
- **Watermark:** Gemini sparkle bottom-right - strip before slicing (ffmpeg delogo).
+58
View File
@@ -0,0 +1,58 @@
# Scene prompt - Course VIII: the Helm press (chart + contexts -> renders, schema gate)
Delivery arc scene C. Seven parts; the rejected sheet stopped BEHIND the gate is the
Move 3 argument - curate hard for it. The press face must show clearly EMPTY voids
(the "holes" a template leaves for values).
Generate ~4 at 16:9, curate with the reject checklist, save to disk for pickup.
---
Dark technical exploded-view illustration in a cinematic sci-fi engineering style.
Solid near-black deep void background, hex #070b14 - completely clean: no stars, no grid,
no texture, no particles behind or around the objects. Matte dark metal-and-glass surfaces
with glowing neon edge lighting: primary cyan #3fbaf5, secondary magenta #e879f9 accents,
cool white rim highlights. Camera: fixed 30-degree isometric angle, subject perfectly
centered with generous empty margins on all sides. Even studio lighting, no vignette,
no lens flare, no depth-of-field blur. ABSOLUTELY NO text, no letters, no numbers, no
words, no code, no glyphs, no labels, no arrows, no callout lines, no UI elements
anywhere in the image - every surface marking must be an abstract geometric pattern
only. Every component is fully separated from its neighbours by generous gaps of pure
void - nothing touching, nothing overlapping, and no beams, cables, or connectors
spanning between the separated parts.
The subject: an exploded pressing-works arranged around one central machine, every
piece floating alone in void.
Centre: a large engraved press plate - a thick dark slab held at the isometric angle,
its upper face carrying an elegant abstract lattice of rectangular RECESSED VOIDS,
clearly empty sockets waiting to be filled, their inner walls glowing faint cyan.
Feeding in from the left, in a loose arc: three compact faceted crystals of glowing
cyan glass - small, dense, jewel-like, one subtly larger than the other two, each
floating alone.
Fanned out to the right: three thin rigid rendered sheets, identical in outline and
framework pattern, but each carrying a different small accent motif glowing a different
hue (one cyan, one white, one magenta) - same shape, different filling.
Below the press, off-centre: a low chamfered gate wedge of dark metal with a single
amber-white glowing edge, calm and final.
Behind the gate wedge, stopped short of it, tilted and dim: one more sheet - grey,
unlit, visibly incomplete, its framework pattern broken by dark gaps.
---
## Build-side notes (not part of the prompt)
- **Slice plan:** 7 polygons - press plate, three values crystals, rendered-sheet fan
(three sheets as ONE slice if cuts get tight - judge at slicing), schema gate wedge,
rejected sheet. Collapse draws crystals + sheets into the press (one machine at
rest); the rejected sheet collapses BEHIND the gate and never crosses it. Clamp at
hero.
- **Legend mapping:** press "the chart - a function with holes" / crystals "per-cluster
values contexts - the cluster's voice" / sheets "renders: same shape, different
numbers - review the render, not just the template" / gate "values.schema.json +
required - absence fails at render time" / rejected sheet "the render that refuses -
the failure you want".
- **Watermark:** Gemini sparkle bottom-right - strip before slicing (ffmpeg delogo).