Add lessons: untimed guided labs, one per curriculum objective, on a host of their own, in the browser and in the terminal. Each step has a check, a hint and its commands; a lesson writes no history or scores, only a done mark on its objective. CKAD 2.1-2.4 (24 steps) and all 27 CKA objectives (135 steps) have one, and `./ksim lesson audit` proves that every step fails, is done by its own commands, then passes. Add CKA tasks 132-147 (cka/bank_course.py) on what a full CKA course teaches beyond the bank: a real upgrade from v1.36, a drain under a PodDisruptionBudget, QoS and eviction, in-place resize, kube-proxy's chains, encryption at rest, an operator, and CSI expansion, snapshots and clones (ensure_csi_hostpath). Move CKA and CKS to Kubernetes v1.37 and rebuild the hosts on Ubuntu 24.04, with kubelet, kubeadm and kubectl as held packages from pkgs.k8s.io; the desktop runs Ubuntu too. Hosts gain man pages, hexdump and xxd. Fix CKS Q4, which gave 3 of 12 points untouched, and CKA Q4 and Q49, whose solutions raced their new CRD. Audited on v1.37: CKA 147/147, CKAD 105/105, CKS 109/110 (Q103, a Falco task, failed to seed once and awaits a re-audit); lessons: 135 of 135 CKA steps and 24 of 24 CKAD steps. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
97 lines
5.4 KiB
Bash
97 lines
5.4 KiB
Bash
#!/bin/bash
|
|
# Build-time provisioning of the VM exam host. Runs once, inside the VM, as the first-boot script of
|
|
# the Ubuntu cloud image (cloud-init user-data), and powers the machine off when it is through; what
|
|
# is on the disk then is the base disk every VM exam host starts from.
|
|
#
|
|
# The result: Ubuntu with containerd, kubeadm, kubelet and kubectl as apt packages (held), the
|
|
# control-plane images pulled, Falco with the modern eBPF probe, the AppArmor tools, and `candidate`
|
|
# with passwordless sudo. No cluster yet: every host makes its own on its first boot
|
|
# (guest/firstboot.sh), under its own name.
|
|
exec > >(tee -a /var/log/ksim-provision.log /dev/ttyS0) 2>&1
|
|
set -euxo pipefail
|
|
trap 'echo KSIM-PROVISION-FAILED line $LINENO; sync; poweroff -f' ERR
|
|
export DEBIAN_FRONTEND=noninteractive
|
|
|
|
modprobe 9p; modprobe 9pnet_virtio
|
|
mkdir -p /mnt/build && mount -t 9p -o trans=virtio,version=9p2000.L,ro build /mnt/build
|
|
. /mnt/build/env # K8S_VERSION=1.37.0 K8S_MINOR=v1.37
|
|
|
|
# --- nothing that works behind the candidate's back
|
|
systemctl disable --now unattended-upgrades.service apt-daily.timer apt-daily-upgrade.timer 2>/dev/null || true
|
|
apt-get purge -y snapd unattended-upgrades >/dev/null 2>&1 || true
|
|
|
|
# --- kernel settings Kubernetes wants, and the modules the host needs at every boot
|
|
printf 'overlay\nbr_netfilter\n9p\n9pnet_virtio\n' > /etc/modules-load.d/ksim.conf
|
|
modprobe overlay; modprobe br_netfilter
|
|
printf 'net.bridge.bridge-nf-call-iptables = 1\nnet.bridge.bridge-nf-call-ip6tables = 1\nnet.ipv4.ip_forward = 1\n' > /etc/sysctl.d/99-kubernetes.conf
|
|
sysctl --system >/dev/null
|
|
swapoff -a; sed -i '/\sswap\s/d' /etc/fstab
|
|
|
|
# --- packages: Kubernetes and Falco from their own repositories
|
|
mkdir -p /etc/apt/keyrings
|
|
curl -fsSL "https://pkgs.k8s.io/core:/stable:/$K8S_MINOR/deb/Release.key" | gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
|
|
echo "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/$K8S_MINOR/deb/ /" > /etc/apt/sources.list.d/kubernetes.list
|
|
curl -fsSL https://falco.org/repo/falcosecurity-packages.asc | gpg --dearmor -o /usr/share/keyrings/falco-archive-keyring.gpg
|
|
echo "deb [signed-by=/usr/share/keyrings/falco-archive-keyring.gpg] https://download.falco.org/packages/deb stable main" > /etc/apt/sources.list.d/falcosecurity.list
|
|
apt-get update
|
|
apt-get install -y --no-install-recommends containerd apparmor-utils jq vim tmux bash-completion conntrack socat strace \
|
|
"kubelet=$K8S_VERSION-*" "kubeadm=$K8S_VERSION-*" "kubectl=$K8S_VERSION-*"
|
|
apt-mark hold kubelet kubeadm kubectl
|
|
curl -fsSL -o /usr/local/bin/yq "https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64" && chmod 755 /usr/local/bin/yq
|
|
|
|
# --- containerd: systemd cgroups, and Docker Hub through the simulator's cache
|
|
mkdir -p /etc/containerd/certs.d/docker.io
|
|
containerd config default > /etc/containerd/config.toml
|
|
# (containerd 1.x writes the empty registry path as "", 2.x as '' - the first one is the CRI's)
|
|
sed -i "s/SystemdCgroup = false/SystemdCgroup = true/; 0,/config_path = \\(\"\"\\|''\\)/s##config_path = \"\/etc\/containerd\/certs.d\"#" /etc/containerd/config.toml
|
|
grep -q 'SystemdCgroup = true' /etc/containerd/config.toml && grep -q 'config_path = "/etc/containerd/certs.d"' /etc/containerd/config.toml
|
|
install -m644 /mnt/build/hosts.toml /etc/containerd/certs.d/docker.io/hosts.toml
|
|
systemctl restart containerd
|
|
printf 'runtime-endpoint: unix:///run/containerd/containerd.sock\nimage-endpoint: unix:///run/containerd/containerd.sock\n' > /etc/crictl.yaml
|
|
kubeadm config images pull --kubernetes-version "v$K8S_VERSION"
|
|
for i in busybox:1.36 nginx:1.27; do crictl pull docker.io/library/$i || true; done
|
|
|
|
# --- Falco, with the modern eBPF probe (no kernel module, no compiler)
|
|
FALCO_FRONTEND=noninteractive FALCO_DRIVER_CHOICE=modern_ebpf apt-get install -y --no-install-recommends falco
|
|
systemctl enable falco-modern-bpf.service
|
|
falco --version | head -1
|
|
|
|
# --- the candidate, as on an exam host
|
|
userdel -r ubuntu 2>/dev/null || true
|
|
useradd -m -s /bin/bash -u 1000 candidate
|
|
echo 'candidate ALL=(ALL) NOPASSWD:ALL' > /etc/sudoers.d/candidate && chmod 440 /etc/sudoers.d/candidate
|
|
install -m644 /mnt/build/exam.bashrc /etc/exam.bashrc && echo '. /etc/exam.bashrc' >> /etc/bash.bashrc
|
|
for h in /etc/skel /root /home/candidate; do install -m644 /mnt/build/vimrc $h/.vimrc; touch $h/.hushlogin; done
|
|
chown candidate:candidate /home/candidate/.vimrc /home/candidate/.hushlogin
|
|
printf 'PasswordAuthentication no\nPermitRootLogin prohibit-password\nUseDNS no\nPrintMotd no\n' > /etc/ssh/sshd_config.d/00-exam.conf
|
|
chmod -x /etc/update-motd.d/* 2>/dev/null || true
|
|
|
|
# --- what every boot does: name, keys, /opt/course, and on the first one the cluster
|
|
install -m755 /mnt/build/firstboot.sh /usr/local/sbin/ksim-firstboot
|
|
cat > /etc/systemd/system/ksim-firstboot.service <<'EOF'
|
|
[Unit]
|
|
Description=ksim exam host: name, keys, /opt/course and the cluster
|
|
After=network-online.target containerd.service
|
|
Wants=network-online.target
|
|
|
|
[Service]
|
|
Type=oneshot
|
|
RemainAfterExit=yes
|
|
ExecStart=/usr/local/sbin/ksim-firstboot
|
|
TimeoutStartSec=600
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
EOF
|
|
systemctl enable ksim-firstboot.service
|
|
mkdir -p /opt/course
|
|
|
|
# --- the image is done: cloud-init must not run again, and the disk should be small
|
|
touch /etc/cloud/cloud-init.disabled
|
|
apt-get clean
|
|
umount /mnt/build || true
|
|
fstrim -av || true
|
|
echo KSIM-PROVISION-OK
|
|
sync
|
|
poweroff
|