The Problem
Most CKA/CKS practice labs run kind or k3s, which don't replicate the real exam environment. kind runs nodes as containers inside a single Docker daemon—no systemctl, no kubelet config files, no crictl. k3s omits kubeadm-specific workflows like cluster init, etcd backup, and static pod manifests. Candidates train on abstractions and hit unfamiliar tooling on exam day.
What This Does
K16S provisions a real kubeadm cluster using Incus LXC containers as worker nodes, each with its own init, systemd, containerd, and kubelet. It ships 5 mock exams (2 CKA, 3 CKS) with 18 questions each, covering the 2026 curricula: troubleshooting NotReady nodes, etcd backup/restore, RBAC, NetworkPolicy, seccomp, AppArmor, and PKI workflows.
Each question lives in exams/<exam>/<name>.yaml (the question spec) paired with scripts/<name>/setup.sh and validate.sh. The setup.sh breaks something on the cluster; validate.sh grades the fix. A Go backend in server/main.go serves a browser-based terminal with timed exam sessions.
How It Is Wired
Execution starts at server/main.go, the single Go entry point. It serves the frontend (a Svelte + Tailwind app in server/frontend/) and exposes API endpoints that trigger the shell scripts. The control flow is: browser terminal → Go HTTP handler → setup.sh or validate.sh on the cluster → kubectl/ssh commands against the Incus containers.
The exam scripts are the payload. Each setup.sh mutates the cluster—stopping kubelet, corrupting etcd, applying broken manifests. Each validate.sh runs checks and returns pass/fail. The exams/ directory contains 261 files; the shell scripts are the core logic. The server layer is thin—4 Go files total—and the frontend is minimal (2 Svelte files).
The dependency graph is flat: server/main.go calls into exam scripts, which call kubectl, crictl, systemctl, and incus commands. No shared library, no internal API between exam modules. That keeps each question self-contained but means changes to validation logic are scattered across ~90 script pairs.
The wiring for the provisioning path (provision/, 20 files) and the local/ and lightweight/ variants has not been mapped in detail for this repository.
How To Use It
Setup: Clone and run the installer. The README documents a one-command provision but the exact command is not visible in the file listing. The provision/ directory contains the provisioning scripts.
git clone https://github.com/moses-y/k16s-exam-simulator
cd k16s-exam-simulator
# Run the installer script from provision/ (exact command in README)
Requirements: Debian 13 or Ubuntu 22.04+ with 4 vCPUs/8 GB RAM for VPS mode, or macOS/Linux with 16 GB RAM and Lima for laptop mode.
Running: Start the server from server/ using the Makefile targets. The frontend builds via npm (see server/frontend/package.json).
Real-World Use
A team preparing for CKA runs this on a spare VPS. Each candidate gets browser access, works through timed mock exams, and the validation scripts grade automatically. The Incus-based workers let candidates practice systemctl restart kubelet, edit static pod manifests under /etc/kubernetes/manifests, and back up etcd—tasks impossible on kind.
Code Health & Issues
- Med - No CI/CD pipeline - no
.github/or CI config detected; no automated build or test gate for the Go server or exam scripts. - Low - Minimal test coverage - 3 test files across 314 total; the validation scripts are the de facto tests but aren't wired into an automated runner.
- Low - Documentation is thin - 2 doc files for a project with this much operational surface area; the README covers setup but not the script API contract.
The Bottom Line
K16S solves a real gap: exam-accurate practice environments that kind and k3s can't provide. The exam content is substantial (90 questions across 5 mocks) and the per-question setup/validate pattern is sound. The server layer is minimal and the project lacks CI, but for individual exam prep or small training cohorts, it's a credible tool. Teams should verify the provisioning scripts work on their target OS before committing.