diff --git a/assets/dist/course-II-cluster.webp b/assets/dist/course-II-cluster.webp new file mode 100644 index 0000000..f234021 Binary files /dev/null and b/assets/dist/course-II-cluster.webp differ diff --git a/assets/raw/course-II-cluster.jpeg b/assets/raw/course-II-cluster.jpeg new file mode 100755 index 0000000..91d69d2 Binary files /dev/null and b/assets/raw/course-II-cluster.jpeg differ diff --git a/build.sh b/build.sh index 5df0a4f..3a03402 100755 --- a/build.sh +++ b/build.sh @@ -10,11 +10,13 @@ trap 'printf "build failed at line %s\n" "$LINENO" >&2' ERR here="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" cd -- "$here" -for f in pilot/arc.tpl.html pilot/manifest-gitops.json pilot/manifest-supply.json \ +for f in pilot/arc.tpl.html pilot/manifest-docker.json pilot/manifest-cluster.json \ + pilot/manifest-gitops.json pilot/manifest-supply.json \ pilot/manifest-helm.json gsap.min.js st.min.js \ assets/dist/course-VI-gitops.webp assets/dist/course-VII-supply-chain.webp \ assets/dist/course-VIII-helm-press.webp assets/dist/appendix-dependency-ledger.webp \ - assets/dist/delivery-flow.svg; do + assets/dist/delivery-flow.svg assets/dist/docker-layers.webp \ + assets/dist/course-II-cluster.webp; do [[ -f "$f" ]] || { printf 'missing source: %s\n' "$f" >&2; exit 1; } done diff --git a/pilot/arc.tpl.html b/pilot/arc.tpl.html index 6eefc8e..d6bf469 100644 --- a/pilot/arc.tpl.html +++ b/pilot/arc.tpl.html @@ -1,20 +1,114 @@

The Exploded Cluster · The Delivery Arc

The machine was the easy part.
Now watch how software reaches it.

-

Three courses on the toolchain around the cluster: how change travels, how images - are named, and how one definition serves a fleet. Scroll, and each machine comes apart.

+

The foundations first - what an image is, what a cluster is - then the toolchain + that delivers to them: how change travels, how images are named, and how one definition serves + a fleet. Scroll, and each machine comes apart.

+ +
+
+

Course I · Docker

+

An image is not a box.
It is a stack of frozen diffs.

+

Scroll, and the thing you keep calling "a container image" comes apart in your + hands. Four layers. Each one only stores what changed from the layer under it - and here they + rise one at a time, bottom up.

+
+
+
+
+ An exploded isometric view of a container image: four stacked slabs floating
+                  apart - a heavy metal base, a circuit-etched dependency layer, a magenta-traced
+                  code layer, and a thin frosted-glass writable layer on top. +
+
    +
    +
    +
    +
    +

    A stack of diffs wearing a name

    +

    An image is not a copy of a machine. It is a stack of read-only layers, each recording only + what changed from the one beneath. The base OS is pulled once and shared by every image on + the host; your dependencies sit on it; your code - usually the smallest layer, always the + most volatile - sits above that; and the writable layer is created fresh per container and + thrown away when it dies. Nothing you write there survives.

    +

    Change a layer and every layer above it must be rebuilt.

    +

    The order is a caching decision

    +

    The builder caches layer by layer, and a cached layer survives only while everything + beneath it is unchanged. Put COPY . . above your dependency + install and you have told the builder to throw the dependency cache away every time one + line of code changes. Dependencies first, code last - a Dockerfile is a cache policy that + happens to build software.

    +

    Field note. A rebuild that takes twenty minutes and one that + takes twenty seconds are usually the same Dockerfile with the lines swapped.

    +

    This stack explains the whole ecosystem above it: sharing explains why + pulls are fast, immutability explains why a digest can name the exact bytes (Course VII), + and the throwaway top layer explains why state needs volumes. One idea - frozen diffs - + all the way down.

    +

    Pre-reads: none - start here +  Further: Docker get-started · + Docker build + layers

    +
    +
    + + +
    +
    +

    Course II · Kubernetes

    +

    A cluster is a promise,
    not a place.

    +

    You never tell Kubernetes how to run your app. You describe what you + want - declarative intent - and the cluster works, forever, to make it true. Scroll, and + the formation splits: the half that decides rises, the halves that run spread below.

    +
    +
    +
    +
    + A small fleet mid-explosion: one wide command slab with a strong cyan seam
+                  hovering above a row of three identical worker blocks, all floating apart in
+                  the void. +
    +
      +
      +
      +
      +
      +

      Desired against actual, forever

      +

      The habit underneath everything: the reconciliation loop - compare desired state + against actual state, fix the difference, repeat. That kubectl apply + didn't launch anything; it filed paperwork. The machine took it from there, and it never + stops taking it from there: kill a pod and it returns, not because something noticed the + crash but because the loop noticed the difference.

      +

      Kubernetes doesn't run your app - it reconciles it.

      +

      One half decides, one half runs

      +

      The split in the scene is the split that makes everything else possible: a control + plane that decides - holds the truth, schedules, reconciles - and worker nodes + that run pods. The workers are deliberately interchangeable: identical, replaceable, cattle + from day one. Authority does not live where the work happens.

      +

      Field note. If you are SSHing into nodes to "fix" things, you + are arm-wrestling the reconciler - and it does not get tired. Change the desired state + instead.

      +

      Everything the delivery arc teaches from Course VI onward is this loop + wearing bigger clothes - git as the desired state, whole fleets as reconciled objects. + Learn the promise once; it repeats all the way up.

      +

      Pre-reads: C-I +  Further: Kubernetes overview · + cluster architecture

      +
      +
      +
      @@ -55,6 +149,15 @@

      Field note. Fighting the reconciler over SSH is arm-wrestling a machine that does not get tired - C-II's warning, now with a face. The fix is always upstream, in git.

      +

      At fleet scale, the label is the deploy button

      +

      Run many OpenShift clusters under a hub - RHACM, with edge clusters arriving through + zero-touch provisioning - and nobody applies apps to clusters by hand. Each app carries a + Placement that selects cluster labels; the hub matches placements against the + labels a cluster wears, and the chosen cluster pulls its assignment. Labelling the cluster + is the deploy action: attach the label and the app follows, remove it and the app + leaves. The same pull model as above, one level bigger - a cluster's labels are its + entitlements, reconciled like everything else.

      +

      Label the cluster; the app follows.

      The one thing git never holds

      Git holds everything 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 @@ -275,6 +378,40 @@

      +
      +
      +

      The library

      +

      Go to the sources.

      +

      Every technology this site teaches, one sentence each, official documentation + only.

      +
      + +
      +