Both checks ran `nslookup kubernetes.default` inside a busybox:1.36 pod and
required it to succeed. busybox's nslookup does not apply the pod's resolv.conf
`search` list - it queries the name literally - so that lookup returns NXDOMAIN
no matter how correctly CoreDNS is configured. Verified in-cluster: from a pod
with a correct `search default.svc.cluster.local svc.cluster.local cluster.local`
and a healthy Corefile, `kubernetes`, `kubernetes.default` and
`kubernetes.default.svc` all return NXDOMAIN while the full
`kubernetes.default.svc.cluster.local` resolves to 10.96.0.1.
The result was a task that could never score more than 3/6: the local drill
history shows this check failing on 4 of 4 attempts with the Corefile fully
repaired.
Use the FQDN in both checks, and say so in the task text so the candidate
verifies the same way the grader does. Q216 in bank_sim_a already used an FQDN;
these two were the outliers.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fqcio9TXkEXH35UHebTgoL
Three fixes from an audit of the repo:
1. setup_contexts() deleted all three k8s-c?-? contexts and recreated none
unless the session was started with --hard. But './exam drill <ids>' and
'./exam drill weak' don't filter by difficulty, so hard tasks land in
hard=False sessions - and 24 of them open with "kubectl config use-context
...", which then fails outright. Q121 was unpassable that way: it says to
deploy into the context's namespace without -n, and its check requires that
namespace, so the context was the only way to learn the name. Contexts are
now created whenever a task in the session references one.
Also fixes how k8s-c2-AC's namespace was chosen: it took the first ns in the
whole session, which is arbitrary when several tasks share a context. A
context has one default namespace, so it belongs to the task that actually
reads it - Q121, now marked "ctx_ns": True.
2. restore_baseline() cleared taint keys dedicated/workload/team, but Q107
draws from pool/lane and Q307 pins maintenance=inprogress, and nothing
uncordoned a node. A leaked cordon or taint silently fails every later task
that counts pods per node (Q26/Q211 DaemonSet coverage, Q212's spread) -
W1 had been cordoned and tainted across sessions for two days. Clears all
six keys now and uncordons all three workers.
3. ttyd was launched with -W (writable) and no interface binding, so it listened
on 0.0.0.0 while the API server correctly bound localhost. That exposed an
unauthenticated root-equivalent shell with the cluster kubeconfig to the whole
network. Pinned to loopback, overridable via CKA_TTYD_INTERFACE.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fqcio9TXkEXH35UHebTgoL
tracks/cka/solutions.py had drifted out of sync with the actual current
task text for several questions (Q06, 11, 12, 13, 14, 22, 32, 40, 109,
110, 120, 122) - wrong namespaces/resource names, missing required steps,
or output files that were never actually written. Rewrote each to match
its task's real requirements.
tracks/cka/bank_extra.py's Q33 grading check queried
`.spec.aggregationRule` on a ClusterRole, but ClusterRole has no `.spec`
field - `aggregationRule` and `rules` are top-level. Fixed the jsonpath
so a correct answer actually passes.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fqcio9TXkEXH35UHebTgoL
Close two of the four CKA-relevant gaps identified against Killercoda's
scenario catalog:
- Q123 (TSHOOT, hard): kube-apiserver itself crash-loops on a static-pod
manifest typo, same pattern as the existing scheduler/controller-manager
failures (Q20/Q118) but with the added twist that kubectl is completely
unusable until it's fixed, forcing node-level diagnosis (crictl,
journalctl).
- Q124 (ARCH, hard): produce a real node-join handoff file by
independently computing the CA discovery hash kubeadm join verifies
against, and finding the API server's actual in-cluster address rather
than the local kubeconfig's port-forwarded one.
Cluster-upgrade and operator-authoring remain unimplemented and are
documented as genuine infrastructure gaps in CKA_SOLUTIONS_EXPLAINED.md
(kind's node images have no apt-installable multi-version kubelet/kubeadm,
and operator authoring needs a real built/pushed image) rather than faked.
Also updates the Killercoda cross-reference table with the gaps closed,
and logs an ended drill session to history-cka.jsonl/weak-spots-cka.md.
Co-Authored-By: Claude Sonnet 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>