105 of the 147 CKA reference solutions had you type what nobody types in the exam: heredoc manifests, sed, JSON patches, kubectl wait, loops, command substitution, jsonpath into files. Each is rewritten as the lessons are: a generator and the lines to add in vim, a manifest pasted from the docs page it names, kubectl edit, ssh NODE and sudo -i, or a value read off the screen and echoed. The other 42 were commands typed as they stand already. A solution can now be parts (sim/bank.py cmd, hand) as a lesson step's show is. The page and ./ksim solution N render it as Markdown, each thing to type a block of its own that a click copies, with the edit beneath it. A solution in parts is its own audit script: load_track runs its parts, and for each edit by hand the script beside it, so the solution you read is the one proven. Their separate scripts in cka/solve.py are dropped, and a task that has both is refused. ./ksim solution lint [N|DOMAIN..] reads what the solutions have you type against TYPING_TRAPS: the CKA bank is clean. Q49's params gain the plural stem and shortName the solution spells out (no new draws); Q103, ported from CKAD Q23, takes a solution of its own. Audited from a copy with renamed hosts: Q3-Q67 (52 tasks) all solved by their parts, after two waits were added to the audit scripts (Q43's DNS record, Q53's Pods); Q68-Q147 still running. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BNSZLLsGXTMBsw17kDunkQ
269 lines
15 KiB
Markdown
269 lines
15 KiB
Markdown
# Changelog
|
||
|
||
Notable changes to kubestronaut-sim, newest first. A version is the `VERSION` string in `ksim`
|
||
(year.month.day.n); `./ksim help` and the top bar of the web page show the one you are running.
|
||
Every entry names the commit it came in.
|
||
|
||
## Unreleased
|
||
|
||
### Changed
|
||
|
||
- **Every CKA reference solution shows the exam way**, as the lessons do: a generator and the few
|
||
lines to add in `vim`, a manifest pasted from the docs page it names, `kubectl edit`, `ssh NODE`,
|
||
or a value you read and `echo` - no heredocs, `sed`, JSON patches, `kubectl wait` or loops. 105
|
||
of the 147 were rewritten; the other 42 were commands you type already. The page and `./ksim
|
||
solution N` show each thing to type as a block of its own, which a click copies.
|
||
- A solution in parts (`cmd`, `hand`) is its own audit script: `./ksim audit` runs what it shows,
|
||
and for each edit by hand the script beside it, so the solution you read is the one proven. Their
|
||
separate scripts in `cka/solve.py` are gone.
|
||
|
||
### Added
|
||
|
||
- `./ksim solution lint [N|DOMAIN..]`: what the reference solutions have you type, against the
|
||
list `./ksim lesson lint` uses.
|
||
|
||
## 2026.10.26.4 — 2026-10-26
|
||
|
||
Everything below came in `226ef19`.
|
||
|
||
### Changed
|
||
|
||
- **Every CKA lesson step shows the exam way** (*Show me how*, `./ksim lesson show`): `k`, a
|
||
generator and the few lines to add in `vim`, a manifest pasted from the docs page it names,
|
||
`kubectl edit`, `ssh NODE` and `sudo -i`, or a value you read and `echo` - never a script. Each
|
||
command is a block of its own, which a click copies. The scripts the audit needs (`yq`, `sed`,
|
||
waits) are kept out of sight, one per part done by hand, so `./ksim lesson audit` still proves
|
||
every step: 135 of 135 on v1.37.
|
||
|
||
### Added
|
||
|
||
- `./ksim lesson lint`: what each step has you type, against what you would not type in the exam
|
||
(`sed`, `awk`, `yq`, heredocs, loops, `kubectl wait`, `--overrides`, JSON patches, `jsonpath`
|
||
into a file, `kubectl` in full). The lesson audit runs it first.
|
||
- A task's or a lesson's host whose setup failed when the session started is marked: the page
|
||
says so above it, with **Rebuild this host**, and `./ksim lesson` names `./ksim reset N`. Before,
|
||
only the log of the preparing window said so.
|
||
|
||
### Fixed
|
||
|
||
- The page shows `*italics*` in lessons and tasks instead of the stars.
|
||
|
||
## 2026.10.26.3 — 2026-10-26
|
||
|
||
Everything below came in `95f9d1b`.
|
||
|
||
### Fixed
|
||
|
||
- Choosing *Teach a domain* could start a full exam. `./ksim web` reads `web/index.html` afresh on
|
||
every request but keeps running the code it started with, so a server from before the update
|
||
read the new request as its default, a full exam. The server now reports when its code has
|
||
changed on disk since it started (a server from before this check counts as changed). The
|
||
lobby then asks you to restart it and starts nothing until you do.
|
||
|
||
## 2026.10.26.2 — 2026-10-26
|
||
|
||
Everything below came in `e852419`.
|
||
|
||
### Added
|
||
|
||
- **Teach a domain**: a domain's lessons you have not done, back to back in one session without
|
||
a clock - `./ksim lesson ARCH`, the lobby's *Teach a domain* card, or the *Teach a domain*
|
||
session in the Start exam dialog (`--all`, or a domain whose lessons are all done, brings every
|
||
one). Every lesson's host is made before the run starts, so there is no waiting between
|
||
lessons. A lesson's wrap-up leads to the next, the list at the top of a lesson goes to any lesson
|
||
of the run, and in a terminal `./ksim lesson next` and `./ksim lesson 4.3` do the same.
|
||
Finishing the run sends you to the domain's timed drill.
|
||
|
||
### Changed
|
||
|
||
- A lesson counts as done the moment its last step is checked, not when you finish it, so
|
||
terminating a lesson or a run keeps the lessons it completed.
|
||
|
||
## 2026.10.26.1 — 2026-10-26
|
||
|
||
Everything below came in `cf4f5be`.
|
||
|
||
### Fixed
|
||
|
||
- The desktop could fail as it started - "noVNC encountered an error: Cannot read properties of
|
||
null (reading 'addEventListener')" - in a browser that had cached the Debian desktop's noVNC
|
||
1.6: its page ran the Ubuntu image's 1.3 `ui.js`. websockify now sends `Cache-Control:
|
||
no-store`, and noVNC moved to `/novnc/`, past what browsers hold at the old paths. Rebuild the
|
||
desktop (`./ksim build`) and restart `./ksim web`.
|
||
|
||
## 2026.10.19.1 — 2026-10-21
|
||
|
||
Merged into `main` from `feat/lessons`. Everything below came in `0e5f768`, except the CKS Q103
|
||
fix (`f54395f`).
|
||
|
||
### Changed
|
||
|
||
- **CKA and CKS run Kubernetes v1.37** (CKAD already did). CKA follows the real exam; CKS runs
|
||
ahead of it - the Linux Foundation still listed v1.35 for CKS on 2026-10-19. The CKA curriculum
|
||
is unchanged (`CKA_Curriculum_v1.37.pdf` is the v1.35 document). Tasks and notes that named
|
||
1.35/1.36 now name 1.37 and 1.38, and the etcd ones etcd 3.7.
|
||
- CKS Q37 and Q39 hold their worker back on **v1.36** - the v1.37 repository has nothing older
|
||
than the cluster's 1.37.0 - so upgrading it is a minor upgrade: the repository line first.
|
||
- **Exam hosts and the desktop are Ubuntu 24.04**, not Debian. The host image is kind's node
|
||
rebuilt on `ubuntu:24.04`: kind's packages and systemd setup, and its containerd, runc, crictl,
|
||
CNI plugins and preloaded images copied from the pinned kind image. The desktop gets Firefox ESR
|
||
from Mozilla's APT repository (Ubuntu's own `firefox` is a snap).
|
||
- **Every host has Kubernetes as held apt packages** from pkgs.k8s.io, with the repository line of
|
||
its minor, as an exam node has - before, only CKS hosts did. The `kubeadm upgrade` wrapper moved
|
||
into the common image. Hosts also gained man pages, `hexdump` (bsdextrautils) and `xxd`.
|
||
- A task or lesson may name a Kubernetes minor (`"k8s"`) or host flavour (`"image"`) of its own;
|
||
`./ksim build` builds what any of them names. v1.36 is pinned for the upgrade task and lesson.
|
||
- `./ksim build --vm` builds VM disks only for the tracks that have VM tasks.
|
||
|
||
### Added
|
||
|
||
- **CKA lessons for all 27 objectives** (`cka/lessons_storage.py`, `_tshoot`, `_work`, `_arch`,
|
||
`_net`; 135 steps). Besides each competency, they cover what a full CKA course teaches under it
|
||
- checked against the outline of KubeDojo's CKA course, written from scratch: projected volumes,
|
||
volume expansion, snapshots and restores, eviction thresholds, debug containers, kube-proxy's
|
||
chains, encryption at rest, in-place resize,
|
||
PodDisruptionBudgets, QoS classes, ServiceAccount tokens, a real upgrade from v1.36 to v1.37 after
|
||
an etcd backup and restore, an HA join, EndpointSlices, an operator. `./ksim lesson audit`: 135
|
||
of 135 steps proven.
|
||
- **CKA tasks 132-145** (`cka/bank_course.py`) on the same topics: a real cluster upgrade to
|
||
v1.37.1, a drain under a PodDisruptionBudget, a container without a shell, ServiceAccount tokens
|
||
and automounting, a projected volume, QoS classes, in-place resize, eviction thresholds,
|
||
kube-proxy's chains, a Service backed by a hand-written EndpointSlice, encryption at rest,
|
||
required anti-affinity (and the rollout it blocks), a StatefulSet canary by partition, an
|
||
operator whose RBAC lacks `backups/status`, and (146-147) growing a claim in use, snapshot,
|
||
restore and clone on `csi-hostpath-sc`. CKA now has 147 tasks, 112 of them in the pool.
|
||
- `ensure_csi_hostpath` for setups: the CSI hostpath driver (v1.18.0) with external-snapshotter's
|
||
CRDs and controller, its `csi-hostpath-snapclass`, and StorageClass `csi-hostpath-sc` with
|
||
`allowVolumeExpansion: true` - the class the real CKA's storage tasks use.
|
||
|
||
- **Lessons**: guided labs, one per curriculum objective, on a host of their own and with no
|
||
clock. A lesson is an introduction, steps you do in the desktop's terminal (each with a
|
||
**Check step** button, a hint and **Show me the commands**), and a wrap-up that sends you to the
|
||
objective's timed drill. Steps count in order. A lesson writes nothing to the history or the
|
||
scores; one whose every step was checked is marked done on its objective.
|
||
- The pilot covers CKAD's Application Deployment domain: 2.1 blue/green and canary, 2.2
|
||
rolling updates and rollbacks, 2.3 Helm, 2.4 Kustomize (`ckad/lessons.py`).
|
||
- Browser: a lesson screen in the exam screen's frame (Introduction, Step N of M, Wrap-up), a
|
||
**Lesson** button and a `lesson ✓` mark on objectives, **Lesson first** on the path card, a
|
||
*Take a lesson* session in the Start exam dialog, and a summary page after a lesson.
|
||
- Terminal: `./ksim lesson [OBJ]`, `./ksim lesson step | check | hint | show [N]`, `./ksim end`.
|
||
- `./ksim lesson audit [OBJ..]` proves lessons on real clusters: every step must fail its check,
|
||
be done by its own commands as `candidate`, then pass. CKAD 2.1–2.4: 24 of 24 steps proven.
|
||
- Engine: lessons are sessions of mode `lesson` (hosts `ckad9201`.., ids 9000 + objective),
|
||
`POST /api/lesson/check`, done stamps under `lessons` in `study-<track>.json`, and `step()`
|
||
in `sim/bank.py` for writing them.
|
||
- Tasks and lessons render fenced code blocks (kept as written, a click copies them) and
|
||
paragraphs of `- ` lines as lists.
|
||
|
||
### Fixed
|
||
|
||
- CKA Q4 and Q49: their solutions wait for the new CRD to be `Established` before creating an
|
||
object of its kind (on v1.37 it lost that race: "no matches for kind").
|
||
- CKS Q4 gave 3 of its 12 points untouched: its token check took any Pod of the Deployment, and
|
||
an untouched Deployment's Pods run as `default`, with a token mounted. It now takes a Pod that
|
||
runs as `<deployment>-sa`.
|
||
- CKS Q103 failed to seed once, six hosts at a time: a minute passed without a Falco alert naming
|
||
the Pod. Its setup now tries a new Pod - a container Falco's container plugin looks up afresh -
|
||
before it gives up.
|
||
- Building a host image for a kind image not pulled yet: podman's pull progress was read as the
|
||
etcd image's name.
|
||
- A solution or lesson step that prints binary data (an etcd value) no longer stops the audit.
|
||
|
||
## 2026.10.15.3 — 2026-10-15
|
||
|
||
### Added
|
||
|
||
- **Browser UI in the style of [CK-X](https://github.com/sailor-sh/CK-X)** (`bab85d1`), itself
|
||
modelled on the Linux Foundation exam UI. Written from scratch, with nothing loaded from the
|
||
network.
|
||
- **Landing page.** The track switch sits in the top bar. **Start exam** opens a dialog to pick
|
||
the session: the next step on the path, an objective, a domain, the next domain, the whole bank,
|
||
tasks of your choice, a simulator set or a full exam, with or without hard mode. The full exam
|
||
warns while a domain has not been drilled yet. Below the dialog button come the path, a card per
|
||
domain, and every objective with its notes and skip links. While a session is prepared, an
|
||
overlay shows the clusters' progress and log; it comes back if the page is reloaded meanwhile.
|
||
- **Exam screen.** A dark top bar holds the clock and three menus: *Exam Interface* (fullscreen,
|
||
panel sizes, reconnect the desktop), *Exam Controls* (submit, pause, restart the clock,
|
||
terminate the session) and *Exam Information* (exam instructions, Kubernetes docs, history).
|
||
The light question panel has `< Question N of M >`, with flags and grades marked. Each task is
|
||
headed *Solve this question on instance: `ssh host`*, and ends with **Flag for review**,
|
||
**Satisfied with answer →** and, in drills, **Check this task**. The remote desktop sits beside
|
||
it, with reconnect and fullscreen buttons and a divider you can drag.
|
||
- **Results page.** Points, pass or fail, bars per domain, every task's checks and reference
|
||
solution, *View answers*, *Drill what I missed*, *Review tasks* and *History*.
|
||
- A session started in the browser opens a "Ready to begin" dialog, and its **Start** puts the
|
||
full time on the clock.
|
||
- **Terminate session** and **Delete the hosts** (`bab85d1`), backed by `POST /api/terminate`. An
|
||
open session ends ungraded and nothing is recorded, as with `./ksim abort`; a finished session
|
||
only loses its hosts. Either way, only that session's hosts are deleted. The session payload now
|
||
says whether a session was aborted.
|
||
- **Dark mode** (`db2575b`): ◐ Auto (your system's setting, the default), ☀ Light or ☾ Dark. The
|
||
switch is in the landing page's top bar, the *Exam Interface* menu and on the results page. The
|
||
browser keeps the choice and applies it before the page draws. This came without a version bump.
|
||
|
||
### Changed
|
||
|
||
- The landing page, exam screen and results page replace the lobby overlay, the number rail with
|
||
its task pane, and the old results overlay. The browser remembers hard mode and the width of the
|
||
question panel.
|
||
|
||
## 2026.10.15.2 — 2026-10-15
|
||
|
||
### Added
|
||
|
||
- **`./ksim restart` and a Restart clock button** (`c244bd9`). The session's full time goes back on
|
||
the clock and starts running; the hosts, the work on them, results, flags and notes stay. Like
|
||
pause, it is recorded nowhere: the attempt's time used counts from the restart. A submitted
|
||
session refuses it. The button is backed by `POST /api/restart`.
|
||
|
||
## 2026.10.15.1 — 2026-10-15
|
||
|
||
### Removed
|
||
|
||
- **Study mode** (`c266eeb`): there are no more untimed sessions with the reference solutions open
|
||
from the start, and `./ksim study` is gone. Every session runs against the clock.
|
||
|
||
### Changed
|
||
|
||
- The path is objective drills against the clock, then a mock, then the fixed simulator sets. An
|
||
objective is done when every task passed on its latest timed attempt; the "studied" stage and its
|
||
`~` mark are gone. `./ksim next` always drills, and the lobby's "Study mode" became "Drill an
|
||
objective".
|
||
- `study-<track>.json` keeps your focus, the domains you marked known and when each objective was
|
||
done. Results of old study sessions stay in it, read by nothing.
|
||
|
||
### Added
|
||
|
||
Work from 2026-10-13, first committed here:
|
||
|
||
- **`./ksim skip` / `unskip`**, and the lobby's "I know this — skip it" links. They mark a domain or
|
||
an objective as known, so the path, the drill with no argument and `drill all` leave it out. A
|
||
mock still draws from every domain.
|
||
- **`DOMAIN:N`** picks N tasks of a domain spread over its objectives: `./ksim drill OBS:3`, or
|
||
`./ksim next OBS:3` to add them to the next step.
|
||
- A command with neither `--track` nor `KSIM_TRACK` is for the track whose session is under way.
|
||
`./ksim show` says where a task's host resolves.
|
||
|
||
### Fixed
|
||
|
||
- CKAD Q60: its check now says which file holds which run's output.
|
||
|
||
## 2026.10.12.1 — 2026-10-13
|
||
|
||
The first release (`f3d0e53`), grown out of `cka-sim`.
|
||
|
||
- **One host per task.** Each task gets a kind (kubeadm) cluster in rootless podman, with real etcd,
|
||
a static-pod control plane and a systemd kubelet. You reach it with `ssh <host>` from a remote
|
||
desktop in the browser (XFCE, a terminal, Firefox limited to the documentation the exam allows).
|
||
- **CKS hosts** carry kube-bench, trivy, kubesec, kube-linter, bom, cosign, istioctl, gVisor and
|
||
Kubernetes from apt packages. The Falco and AppArmor tasks run on QEMU/KVM Ubuntu VMs.
|
||
- **A pull-through image cache** (`ksim-registry`) keeps sessions under Docker Hub's pull limit.
|
||
- **Task banks:** CKA 131, CKAD 105 and CKS 110 tasks, with at least 17 pool tasks in every domain.
|
||
Each track comes with its curriculum, study notes, reference solutions and scripted solutions.
|
||
- Drills, full mocks with hard mode, the fixed simulator sets (CKA C and D, CKAD A), a curriculum
|
||
path with study mode, attempt history and weak spots.
|
||
- `./ksim coverage` and `./ksim audit`. All 346 tasks pass the audit: each seeds cleanly, scores
|
||
nothing untouched and reaches full marks with its scripted solution.
|
||
|
||
The repository's initial commit (`3d7605c`) holds the licence and a stub README.
|