A fixed CKAD set (ids 38-57, 140 points, 120 minutes), run with
`./exam sim a`. It is kept out of the random pool, so reruns are
comparable. The scenarios are original - a fictional river-freight company,
one Namespace per river - and practise the techniques the killer.sh CKAD
environment is known for without reusing its questions: exact names and
file outputs, commands written to scripts, several steps per task.
It covers what the pool never asks: debugging a container with no shell
through an ephemeral container (the value lives only in the process's
environment), a Kustomize patch with a hashed configMapGenerator, a Helm
release stuck in `failed`, a CronJob run by hand while suspended, fsGroup
on a shared volume, RBAC proven by the app's own log, Pods rejected by a
LimitRange, and the two-source NetworkPolicy trap (enforced by kindnet).
Verified on a throwaway cluster: every task scores 0 untouched and 7/7 when
solved, and a full sitting (baseline, seed all 20, solve, grade at the end)
scored 140/140 twice on the final code.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VchE1CFkJqwYhXSMTPZUtD
The CKAD track was a 12-task starter bank whose quota (3/3/2/2/2) drew the
whole bank, so every mock was the same 12 tasks reshuffled, and about half
of the curriculum had no task at all.
Tasks 13-37 (tracks/ckad/bank_extra.py) give every missing competency at
least one task: build and export an image with podman (OCI archive), Job
completions and parallelism, a DaemonSet on every node, a native sidecar
that lets a Job finish, a PVC and an in-memory emptyDir, a canary by replica
ratio, rolling-update limits, a Kustomize overlay, a Helm values file and an
upgrade that keeps values, manifests on removed APIs, kubectl top, logs of a
crashing container, two stacked faults, OOMKilled, a custom resource, RBAC
for a ServiceAccount, Pod Security admission, ResourceQuota with LimitRange
defaults, Guaranteed QoS, ConfigMaps, Secrets, ServiceAccount tokens, an
egress NetworkPolicy tested with real traffic, a Service with two faults and
an Ingress with TLS.
A mock now draws 16 tasks weighted like the exam (DESIGN 3, DEPLOY 3, OBS 3,
ENV 4, NET 3) from a pool of 8/7/7/10/5. New ensure_metrics_server helper so
`kubectl top` works on a freshly built cluster. Starter tasks now delete
their Pods with --wait=true, so a re-seed cannot apply onto a Pod that is
still terminating, and setups that create bare Pods fail loudly if one is
missing. README gains a CKAD section.
Verified on a throwaway cluster: all 12 starter and 25 new tasks score 0
untouched and full when solved; four full 16-task mocks that together
include all 37 tasks scored 122/122, 118/118, 124/124 and 119/119.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mhxm4rsUfuE5HoytYbu2YW
Task ids used to jump 1-43 / 101-124 / 401-418 / 501-517. They now run
contiguously in the same order:
1-43 unchanged (base and extra)
44-67 hard pool (was 101-124)
68-85 Simulator Set C (was 401-418)
86-102 Simulator Set D (was 501-517)
Every reference moved with its task: ids, solution keys, workspace paths
({WS}/qNN and the graders' hidden .qNN-* files), temp paths, the one
hardcoded id in code (Q56's derived canary weight), and Q-number
cross-references in the harness, README and the explainer. Each task's
paths were checked to carry only its own new number. History entries and
the local session state were remapped so past attempts stay attached to the
same tasks; retired set A/B ids keep their old numbers and match nothing.
weak-spots is regenerated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mhxm4rsUfuE5HoytYbu2YW
Removes tracks/cka/bank_sim_a.py and bank_sim_b.py (34 tasks, ids 201-217 and
301-317). The previous commit holds their last versions, with every fix from
the audit applied and both sets verified end to end - restore with
`git show HEAD~1:tracks/cka/bank_sim_a.py` if one is ever wanted back.
The baseline keeps repairing what those sets could leave on a cluster that
ran them (the maintenance taint, cordons, Q317's controller flag, Q314's static
pod) - only its comments changed. `breaks` keys that existed solely to keep
pool tasks apart from set A/B tasks are gone. History keeps its raw entries;
weak-spots is regenerated without the retired tasks. A mistyped drill argument
now gets a usage message instead of a traceback.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every changed task was seeded, graded untouched, solved and re-graded on a
separate kind cluster. The four sim sets were rehearsed as full sittings (real
baseline, seed everything, solve in order, grade at the end): A 150/150,
B 176/176, C 163/163, D 122/122. Every random-pool task was either passed in a
real session or cycled the same way.
Graders that could never pass, or passed for free:
Q306 (local-path cannot resize; now graded as an in-place resize), Q314 (GNU
grep prefixed file names), Q305 (plain `get events` has no SOURCE column and
events expire; now managedFields), Q410 (kindnet DOES enforce NetworkPolicy;
the expected answer is now derived from the CNI), Q35, Q212 (missing `]`),
Q101 (`can-i create pods/exec` asks about a pod NAMED exec; multi-type get),
Q109 (an emptyDir over nginx's /var/log crash-loops it), Q40 (TTL was
measured at grading time), Q121, Q106, Q104, Q41, Q26, Q403, Q409, Q417,
Q113, Q22, Q24/Q108 (flaky right after a rollout), and free points on
untouched Q24/Q102/Q108/Q119/Q122.
Reference solutions: S[43], S[107], S[121], S[106] rewritten; S[116] (a
Completed Job pod still pins its PVC), S[119] (a pods quota equal to replicas
deadlocks the rollout); DNS checks use FQDNs; the explainer and exam guide
are corrected (etcd restore is etcdutl's job on 3.6+).
Cross-session leaks: the pre-session baseline now also repairs Q114 (the
kube-system NetworkPolicy and CoreDNS replicas), Q117/Q39 kubelet CA paths,
Q317, kubelet drop-in binary paths, a moved scheduler manifest, leftover
static pods and the default StorageClass. Q115 releases its fixed PVs from
claims left by earlier sessions.
Conflicts: `breaks` may be a list and `solo` keeps Q102's etcd restore out of
mixed sessions. Q118, Q5/Q103, Q26 vs the W1 taints, set A 203/204/208/212 and
set B 305/309 no longer sabotage each other. Q317 now disables only CSR
signing (the old break killed the whole controller-manager). Q110/Q311 no
longer compare against the whole cluster at submit time. Two delete/recreate
races in setups are fixed.
Harness: the weak list clears after two clean passes in a row, weak entries
show the latest attempt's failures, domain scores use the exam's own tasks,
history entries can be marked synthetic (entry 11 is), the web UI lists
every sim set, `./exam grade` refuses mid-exam (--force), preflight checks W1.
Set D (`./exam sim d`): 17 original killer.sh-style tasks, ids 501-517,
122 points - control-plane inventory, event forensics with crictl, a broken
kubelet unit, kubelet certificates, manual scheduling with the scheduler
stopped, Helm housekeeping with a stuck release, an enforced AND-vs-OR
NetworkPolicy, dnsPolicy and access-mode troubleshooting, and more.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Q02/Q102 seeds tried to copy etcdctl out of the running etcd pod with
`kubectl exec -- cat`, which cannot work: registry.k8s.io/etcd is distroless
(no cat, no sh, no tar). The copy failed, stderr went to /dev/null and seeding
still printed a green tick, so the snapshot task had no etcdctl on the node.
Q102 was worse: it also ran `exec -- sh -c 'etcdctl ... snapshot save'` inside
that container, so its /opt/cka/backup.db was never created at all.
- etcd-tools.sh installs both binaries on the control-plane node, taking them
from the etcd image already in the node's containerd (offline, exactly the
server version), falling back to the upstream release tarball, then apt.
- setup.sh runs it at bootstrap; ensure_etcd_tools in the exam prelude installs
them through CKA_NODE_ACCESS when a task is seeded, so ssh/vagrant clusters
get them too, and both etcd setups now fail with a reason instead of hiding it.
- Q102 takes its snapshot with the node's etcdctl; Q02 no longer documents a
kubectl cp fallback that cannot work on a distroless image.
Co-authored-by: Junie <junie@jetbrains.com>