From 7caa9d5342ed11995926b05428149dc5fecca4ed Mon Sep 17 00:00:00 2001 From: jwright Date: Mon, 17 Aug 2026 12:44:44 +1000 Subject: [PATCH] delivery arc VI-VIII: course briefs (GitOps, supply chain, Helm contexts) + NB2 scene prompts 09-11 --- content/course-VI-gitops.md | 68 ++++++++++++++++++++++++ content/course-VII-supply-chain.md | 75 +++++++++++++++++++++++++++ content/course-VIII-helm-contexts.md | 74 ++++++++++++++++++++++++++ prompts/09-course-VI-gitops.md | 58 +++++++++++++++++++++ prompts/10-course-VII-supply-chain.md | 58 +++++++++++++++++++++ prompts/11-course-VIII-helm-press.md | 58 +++++++++++++++++++++ 6 files changed, 391 insertions(+) create mode 100644 content/course-VI-gitops.md create mode 100644 content/course-VII-supply-chain.md create mode 100644 content/course-VIII-helm-contexts.md create mode 100644 prompts/09-course-VI-gitops.md create mode 100644 prompts/10-course-VII-supply-chain.md create mode 100644 prompts/11-course-VIII-helm-press.md diff --git a/content/course-VI-gitops.md b/content/course-VI-gitops.md new file mode 100644 index 0000000..54f567f --- /dev/null +++ b/content/course-VI-gitops.md @@ -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). diff --git a/content/course-VII-supply-chain.md b/content/course-VII-supply-chain.md new file mode 100644 index 0000000..eb8f87a --- /dev/null +++ b/content/course-VII-supply-chain.md @@ -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. diff --git a/content/course-VIII-helm-contexts.md b/content/course-VIII-helm-contexts.md new file mode 100644 index 0000000..3ca5f80 --- /dev/null +++ b/content/course-VIII-helm-contexts.md @@ -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. diff --git a/prompts/09-course-VI-gitops.md b/prompts/09-course-VI-gitops.md new file mode 100644 index 0000000..93cdfc8 --- /dev/null +++ b/prompts/09-course-VI-gitops.md @@ -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). diff --git a/prompts/10-course-VII-supply-chain.md b/prompts/10-course-VII-supply-chain.md new file mode 100644 index 0000000..870df5c --- /dev/null +++ b/prompts/10-course-VII-supply-chain.md @@ -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). diff --git a/prompts/11-course-VIII-helm-press.md b/prompts/11-course-VIII-helm-press.md new file mode 100644 index 0000000..0556569 --- /dev/null +++ b/prompts/11-course-VIII-helm-press.md @@ -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).