arc: reading key (standalone page), top-to-bottom legend lighting, end-to-end flow blueprint
This commit is contained in:
+55
-9
@@ -6,6 +6,15 @@
|
||||
<p class="scrollcue" aria-hidden="true">scroll<span></span></p>
|
||||
</header>
|
||||
|
||||
<aside class="key" aria-label="reading key">
|
||||
<p class="kt">Reading key · this page stands alone - anything it leans on is listed here</p>
|
||||
<ul>
|
||||
<li><b>C-I</b><span>Docker: an image is a stack of frozen diffs. Referenced by Course VII.</span><i>course lands here soon</i></li>
|
||||
<li><b>C-II</b><span>Kubernetes: a cluster is a promise - the reconciliation loop. Referenced by Courses VI and VIII.</span><i>course lands here soon</i></li>
|
||||
<li><b>BLOG</b><span>Consistency by construction beats consistency by discipline - Course VIII's contexts move, lived on a real fleet.</span><a href="https://www.bztmon.com/blog/one-value-many-enforcers/">read it on bztmon.com</a></li>
|
||||
</ul>
|
||||
</aside>
|
||||
|
||||
<!-- ============ COURSE VI ============ -->
|
||||
<section class="course" id="c6" data-scene="gitops" aria-labelledby="c6h">
|
||||
<header class="chead">
|
||||
@@ -30,7 +39,7 @@
|
||||
</div>
|
||||
<div class="prose">
|
||||
<h3>The loop you already know, one level up</h3>
|
||||
<p>Course II taught the reconciliation loop: desired versus actual, fix the difference, repeat.
|
||||
<p>C-II taught the reconciliation loop: desired versus actual, fix the difference, repeat.
|
||||
ArgoCD is the same habit applied to <b>delivery</b>. An Application names a repo, a path and a
|
||||
revision - watch this branch of this repository - and the controller renders what it finds
|
||||
there, compares it against the live cluster, and syncs the difference. The deploy button is a
|
||||
@@ -44,7 +53,7 @@
|
||||
it back, and what leaves git leaves the cluster. Rollback is <span class="mono">git revert</span>,
|
||||
which is why commit hygiene is an operational skill.</p>
|
||||
<p class="fieldnote"><b>Field note.</b> Fighting the reconciler over SSH is arm-wrestling a
|
||||
machine that does not get tired - Course II's warning, now with a face. The fix is always
|
||||
machine that does not get tired - C-II's warning, now with a face. The fix is always
|
||||
upstream, in git.</p>
|
||||
<h3>The one thing git never holds</h3>
|
||||
<p>Git holds everything except secrets - a secret in git is published, forever, to everyone who
|
||||
@@ -57,7 +66,7 @@
|
||||
<p class="closeline">Delivery stops being an event and becomes a property: the cluster is always
|
||||
converging on what the repository says. "Who deployed this?" becomes "who merged this?" - and
|
||||
that question always has an answer.</p>
|
||||
<p class="reads"><b>Pre-reads:</b> Course II ·
|
||||
<p class="reads"><b>Pre-reads:</b> C-II ·
|
||||
<a href="https://kubernetes.io/docs/concepts/">Kubernetes concepts</a> ·
|
||||
<a href="https://docs.github.com/en/get-started">git + pull requests</a>
|
||||
 <b>Further:</b> <a href="https://argo-cd.readthedocs.io/">Argo CD</a> ·
|
||||
@@ -117,7 +126,7 @@
|
||||
<p class="closeline">Names that can move are convenient exactly until they move. Address content
|
||||
by what it is, and the supply chain stops being a chain of trust and becomes a chain of
|
||||
arithmetic.</p>
|
||||
<p class="reads"><b>Pre-reads:</b> Course I ·
|
||||
<p class="reads"><b>Pre-reads:</b> C-I ·
|
||||
<a href="https://kubernetes.io/docs/concepts/containers/images/">Kubernetes images</a>
|
||||
 <b>Further:</b> <a href="https://zotregistry.dev/">zot</a> ·
|
||||
<a href="https://learn.microsoft.com/azure/container-registry/">Azure Container Registry</a> ·
|
||||
@@ -164,7 +173,7 @@
|
||||
one values file: names, addresses, sizes, flags. The context is deliberately values-only; the
|
||||
moment it 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.</p>
|
||||
the network attachment and two policies renders from one field, so the copies cannot diverge - the lived version is <a href="https://www.bztmon.com/blog/one-value-many-enforcers/">BLOG in the key above</a>.</p>
|
||||
<p class="sayit">The chart owns the shape. The context owns the numbers.</p>
|
||||
<h3>Make the template refuse</h3>
|
||||
<p>A template that renders whatever it is given just moves the failure downstream. The grown-up
|
||||
@@ -176,7 +185,7 @@
|
||||
<p class="closeline">Fleet consistency is not a discipline problem, it is a construction
|
||||
problem. Divergence stops being something you police and becomes something the tooling cannot
|
||||
express.</p>
|
||||
<p class="reads"><b>Pre-reads:</b> Course II ·
|
||||
<p class="reads"><b>Pre-reads:</b> C-II ·
|
||||
<a href="https://kubernetes.io/docs/concepts/overview/working-with-objects/">Kubernetes objects</a>
|
||||
 <b>Further:</b> <a href="https://helm.sh/docs/">Helm docs</a> ·
|
||||
<a href="https://helm.sh/docs/chart_template_guide/">chart template guide</a> ·
|
||||
@@ -245,6 +254,27 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="course" id="flow" aria-labelledby="flowh">
|
||||
<header class="chead">
|
||||
<p class="eyebrow">The whole arc · end to end</p>
|
||||
<h2 id="flowh" class="thesis">One flow, <em>no gaps.</em></h2>
|
||||
<p class="lede">Every course above is one stretch of the same journey. Here is the full run,
|
||||
drawn in the house blueprint style: the change lane, the shape lane, the artefact lane and
|
||||
the secret lane, all converging on one running workload.</p>
|
||||
</header>
|
||||
<figure class="blueprint">
|
||||
<img src="__DIAG_FLOW__"
|
||||
alt="End-to-end delivery flow. Change lane: a commit lands in the GitHub repository, ArgoCD
|
||||
renders and diffs it, and syncs the cluster - the cluster pulls, nothing pushes.
|
||||
Shape lane: the Helm chart plus a per-cluster values context passes the schema gate
|
||||
and renders the manifests ArgoCD applies. Artefact lane: CI builds once, pushes to
|
||||
Azure Container Registry, the zot mirror caches it, and the node pulls by digest.
|
||||
Secret lane: Azure Key Vault holds the values, the External Secrets operator syncs
|
||||
them in - git only ever holds the reference. All four lanes converge on the running
|
||||
workload.">
|
||||
</figure>
|
||||
</section>
|
||||
|
||||
<footer class="outro">
|
||||
<p>The Exploded Cluster · the delivery arc · every scene is one generated hero,
|
||||
sliced and scrubbed - no diagrams were harmed.</p>
|
||||
@@ -275,6 +305,22 @@ b{color:var(--ink)} .mono{font-family:var(--mono);font-size:.9em;color:var(--cya
|
||||
color:var(--dim);margin-top:4.5rem;display:flex;flex-direction:column;align-items:center;gap:.7rem}
|
||||
.scrollcue span{display:block;width:1px;height:46px;background:linear-gradient(var(--cyan),transparent)}
|
||||
|
||||
.key{max-width:760px;margin:0 auto;padding:0 24px 4vh}
|
||||
.key .kt{font-family:var(--mono);font-size:.68rem;letter-spacing:.16em;text-transform:uppercase;
|
||||
color:var(--dim);text-align:center;margin:0 0 1rem}
|
||||
.key ul{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:10px}
|
||||
.key li{display:grid;grid-template-columns:52px 1fr auto;gap:14px;align-items:baseline;
|
||||
border:1px solid var(--line);border-radius:8px;padding:10px 16px;background:#0a1020}
|
||||
.key b{font-family:var(--mono);font-size:.72rem;letter-spacing:.1em;color:var(--cyan)}
|
||||
.key span{font-size:.82rem;line-height:1.5;color:var(--dim)}
|
||||
.key i{font-family:var(--mono);font-size:.62rem;letter-spacing:.1em;text-transform:uppercase;
|
||||
color:var(--amber);font-style:normal;white-space:nowrap}
|
||||
.key a{font-family:var(--mono);font-size:.66rem;letter-spacing:.06em;white-space:nowrap}
|
||||
@media (max-width:700px){.key li{grid-template-columns:44px 1fr}.key i,.key a{grid-column:2}}
|
||||
|
||||
.blueprint{max-width:1220px;margin:2vh auto 4vh;padding:0 24px}
|
||||
.blueprint img{width:100%;height:auto;display:block;border-radius:12px}
|
||||
|
||||
.course{position:relative;padding-top:10vh}
|
||||
.chead{max-width:64ch;margin:0 auto;padding:4vh 24px 2vh;text-align:center}
|
||||
.chead .thesis{font-size:clamp(1.6rem,4vw,2.6rem)}
|
||||
@@ -370,16 +416,16 @@ body:not(.fx) .bench{display:none}
|
||||
return d;
|
||||
});
|
||||
u.flat.style.visibility = "hidden";
|
||||
const dists = u.man.parts.map(p => Math.hypot(p.dx, p.dy));
|
||||
const maxD = Math.max(...dists, 1e-6);
|
||||
const lis = [...u.legend.children];
|
||||
const n = lis.length;
|
||||
u.apply = t => {
|
||||
u.man.parts.forEach((p, i) => {
|
||||
u.slabs[i].style.transform =
|
||||
"translate3d(" + (p.dx * (1 - t)).toFixed(3) + "%," + (p.dy * (1 - t)).toFixed(3) + "%,0)";
|
||||
});
|
||||
u.scene.style.transform = "scale(" + (0.95 + 0.05 * t).toFixed(4) + ")";
|
||||
lis.forEach((li, i) => li.classList.toggle("lit", t >= 0.82 * (dists[i] / maxD)));
|
||||
// the side list lights in reading order, top to bottom, as the scrub advances
|
||||
lis.forEach((li, i) => li.classList.toggle("lit", t >= 0.9 * ((i + 0.5) / n)));
|
||||
};
|
||||
// bench: hand scrub + HUD (pilot instrument - strip for the site ship)
|
||||
const bench = u.sec.querySelector(".bench");
|
||||
|
||||
@@ -31,7 +31,8 @@ const heroes = {
|
||||
__HERO_APPENDIX__: "appendix-dependency-ledger.webp",
|
||||
};
|
||||
for (const [ph, file] of Object.entries(heroes)) body = body.replace(ph, "/assets/" + file);
|
||||
if (body.includes("__HERO_") || app.includes("__MAN_")) throw new Error("unfilled placeholder");
|
||||
body = body.replace("__DIAG_FLOW__", "/assets/delivery-flow.svg");
|
||||
if (body.includes("__HERO_") || body.includes("__DIAG_") || app.includes("__MAN_")) throw new Error("unfilled placeholder");
|
||||
|
||||
const favicon = "data:image/svg+xml," + encodeURIComponent(
|
||||
`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><rect width="32" height="32" fill="#070b14"/><rect x="6" y="4" width="14" height="7" rx="1.5" fill="#3fbaf5"/><rect x="11" y="13" width="14" height="7" rx="1.5" fill="#7dd0f9"/><rect x="6" y="22" width="14" height="7" rx="1.5" fill="#e879f9"/></svg>`);
|
||||
@@ -61,6 +62,7 @@ writeFileSync(join(DIST, "arc.js"), app);
|
||||
copyFileSync(join(ROOT, "gsap.min.js"), join(DIST, "gsap.min.js"));
|
||||
copyFileSync(join(ROOT, "st.min.js"), join(DIST, "st.min.js"));
|
||||
for (const f of Object.values(heroes)) copyFileSync(join(ROOT, "assets/dist", f), join(DIST, "assets", f));
|
||||
copyFileSync(join(ROOT, "assets/dist/delivery-flow.svg"), join(DIST, "assets/delivery-flow.svg"));
|
||||
|
||||
// CSP gate: no inline <script> may survive into the served HTML
|
||||
const inline = (html.match(/<script(?![^>]*src=)[^>]*>/gi) || []).length;
|
||||
|
||||
@@ -22,9 +22,10 @@ out = (ROOT / "pilot/arc.tpl.html").read_text() \
|
||||
.replace("__HERO_GITOPS__", b64("course-VI-gitops.webp")) \
|
||||
.replace("__HERO_SUPPLY__", b64("course-VII-supply-chain.webp")) \
|
||||
.replace("__HERO_HELM__", b64("course-VIII-helm-press.webp")) \
|
||||
.replace("__HERO_APPENDIX__", b64("appendix-dependency-ledger.webp"))
|
||||
.replace("__HERO_APPENDIX__", b64("appendix-dependency-ledger.webp")) \
|
||||
.replace("__DIAG_FLOW__", "data:image/svg+xml;base64," + base64.b64encode((ROOT / "assets/dist/delivery-flow.svg").read_bytes()).decode())
|
||||
|
||||
assert "__MAN_" not in out and "__HERO_" not in out, "unfilled placeholder"
|
||||
assert "__MAN_" not in out and "__HERO_" not in out and "__DIAG_" not in out, "unfilled placeholder"
|
||||
|
||||
out = (f"<script>{(ROOT / 'gsap.min.js').read_text()}</script>\n"
|
||||
f"<script>{(ROOT / 'st.min.js').read_text()}</script>\n" + out)
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
{
|
||||
"name": "image",
|
||||
"title": "The image",
|
||||
"blurb": "Course I's layers, shipped as one unit - the thing whose name we must say precisely.",
|
||||
"blurb": "C-I's layers, shipped as one unit - the thing whose name we must say precisely.",
|
||||
"z": 0,
|
||||
"points": [
|
||||
[
|
||||
|
||||
Reference in New Issue
Block a user