kubestronaut-sim runs each exam task on a host of its own - a kind (kubeadm) cluster in rootless podman, or a QEMU/KVM Ubuntu VM for the CKS tasks that need their own kernel (Falco, AppArmor) - and puts a browser desktop in front of them, the way killer.sh and sailor.sh do. - ksim, sim/: the engine (sessions, drills, study mode, grading, coverage, audit), host and VM lifecycle, the desktop - images/: exam host images (common, CKS variant with its tools, VM guest) - cka/ (131 tasks), ckad/ (105), cks/ (110): task banks, curricula with study notes, reference solutions and scripted solutions Every domain of every track has at least 17 pool tasks. `./ksim audit` proves a task three ways: it seeds cleanly on its own host, scores nothing before anyone has worked on it, and reaches full marks when its scripted solution is run on the host as `candidate`. All 346 tasks pass (CKA audited 2026-10-13, CKAD and CKS 2026-10-12). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JZPd3GGWyxTgAkL6a4gAJz
41 lines
2.5 KiB
Docker
41 lines
2.5 KiB
Docker
# Exam host: a kind node (kubeadm, kubelet, containerd, static-pod control plane) that you reach
|
|
# with `ssh <host>` as `candidate`, carrying the tools the real exam hosts have. Built once per
|
|
# Kubernetes minor by `./ksim build`; every question gets its own cluster from this image.
|
|
ARG BASE
|
|
ARG ETCD_IMAGE
|
|
FROM ${ETCD_IMAGE} AS etcd
|
|
|
|
FROM ${BASE}
|
|
# etcdctl/etcdutl at exactly the version of the cluster's etcd (the etcd image itself is distroless)
|
|
COPY --from=etcd /usr/local/bin/etcdctl /usr/local/bin/etcdutl /usr/local/bin/
|
|
RUN apt-get update \
|
|
&& DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
|
|
openssh-server dbus sudo vim nano less jq tmux bash-completion curl wget ca-certificates \
|
|
iputils-ping dnsutils netcat-openbsd psmisc tree openssl git \
|
|
podman netavark aardvark-dns \
|
|
&& rm -rf /var/lib/apt/lists/* \
|
|
# Debian's podman ships a CNI config. The kubelet would take it for the cluster's pod network
|
|
# until kindnet has written its own, and the first Pods would land on podman's bridge.
|
|
&& rm -f /etc/cni/net.d/87-podman-bridge.conflist \
|
|
&& touch /etc/containers/nodocker
|
|
ARG HELM_VERSION
|
|
RUN arch="$(dpkg --print-architecture)" \
|
|
&& curl -fsSL "https://get.helm.sh/helm-${HELM_VERSION}-linux-${arch}.tar.gz" \
|
|
| tar -xz -C /usr/local/bin --strip-components=1 "linux-${arch}/helm" \
|
|
&& curl -fsSL -o /usr/local/bin/yq "https://github.com/mikefarah/yq/releases/latest/download/yq_linux_${arch}" \
|
|
&& chmod +x /usr/local/bin/yq
|
|
COPY rootfs/ /
|
|
# uid 1000, passwordless sudo: the exam gives you `candidate` and expects `sudo -i` for node work
|
|
RUN useradd -m -s /bin/bash -u 1000 candidate \
|
|
&& echo 'candidate ALL=(ALL) NOPASSWD:ALL' > /etc/sudoers.d/candidate && chmod 440 /etc/sudoers.d/candidate \
|
|
&& cp /etc/skel/.vimrc /root/.vimrc \
|
|
&& echo '. /etc/exam.bashrc' >> /etc/bash.bashrc \
|
|
&& systemctl enable ssh \
|
|
# registry mirrors are read from /etc/containerd/certs.d (see docker.io/hosts.toml there)
|
|
&& printf '\n[plugins."io.containerd.grpc.v1.cri".registry]\n config_path = "/etc/containerd/certs.d"\n' >> /etc/containerd/config.toml \
|
|
# Installing dbus stamps the image with a D-Bus machine id, and systemd-machine-id-setup (run by
|
|
# kind's entrypoint on every boot) copies that into /etc/machine-id instead of making a new one:
|
|
# every node would share one machine id, derive the same eth0 MAC from it, and be unreachable from
|
|
# its neighbours. Point it at /etc/machine-id, as a stock Debian does, so each node gets its own.
|
|
&& rm -f /var/lib/dbus/machine-id && ln -s /etc/machine-id /var/lib/dbus/machine-id
|