KubeKosh runs a real K3s Kubernetes cluster inside a single Docker container and pairs it with a browser-based terminal and automated scenario validation β no cloud account or local cluster required.
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
Prerequisite: Docker
docker run -itd --name kubekosh --privileged -p 7554:80 zeborg/kubekosh:latestOpen http://localhost:7554 β wait ~30 seconds for the Cluster Ready indicator to turn green.
--privilegedis required β K3s needs access to kernel namespaces and cgroups.
Security Warning: Do not expose this container publicly. Use it only on your local machine as it is meant for educational purposes only.
docker run -itd --name kubekosh --privileged -p 7554:80 \
-v <your_custom_directory>:/data zeborg/kubekosh:latestProgress is stored in SQLite at /data/progress.db inside the container. Mount a local directory to /data to keep progress across container restarts.
docker build -t kubekosh .
# multi-platform
docker buildx build --platform linux/amd64,linux/arm64 -t kubekosh .| Bundle | Focus | Exam Mode |
|---|---|---|
| π± Kubernetes Basics | Core concepts | 60 min |
| π§β |
CKA | 120 min |
| π οΈ Kubernetes Developer | CKAD | 120 min |
| π‘οΈ Kubernetes Security | CKS | 120 min |
Scenario types:
- Task β Hands-on challenge in the live terminal. Click Validate for automated cluster-state checking.
- MCQ β Multiple-choice question with a detailed explanation on submission.
The terminal comes pre-configured with:
| Alias | Expands to |
|---|---|
k |
kubectl |
kg |
kubectl get |
kd |
kubectl describe |
krm |
kubectl delete |
kgp |
kubectl get pods |
kga |
kubectl get pods --all-namespaces |
kgd |
kubectl get deployments |
kgs |
kubectl get services |
kgn |
kubectl get nodes |
kgns |
kubectl get namespaces |
kdp |
kubectl describe pod |
kaf |
kubectl apply -f |
kdf |
kubectl delete -f |
kex |
kubectl exec -it |
klogs |
kubectl logs |
kns <ns> |
kubectl config set-context --current --namespace=<ns> |
kctx <ctx> |
kubectl config use-context <ctx> |
Beyond practice scenarios, KubeKosh ships an Add-ons catalog β one-click install of popular Kubernetes tooling straight into the lab. Open it from the π§© button in the header.
Add-ons come in two flavours:
- OS β a CLI binary placed on the terminal
PATH(under/data/addons/bin), e.g.helm,kustomize. - Cluster β workloads deployed into the K3s cluster via Helm /
kubectl, e.g. ingress controllers and observability stacks.
Each install streams live logs, resolves dependencies automatically (installing OpenCost, for example, pulls in Helm and kube-prometheus-stack first), and can be queued, cancelled (partial changes are rolled back), upgraded, or removed from the same panel.
| Add-on | Type | What it does |
|---|---|---|
| β Helm | OS | Kubernetes package manager |
| π§± Kustomize | OS | Template-free manifest customization |
| π‘οΈ Kyverno | Cluster | Policy engine (validate / mutate / generate) |
| π cert-manager | Cluster | Automated TLS certificate management |
| πͺ Gateway API | Cluster | Next-generation ingress / routing CRDs |
| π HAProxy Ingress | Cluster | HAProxy-based ingress controller |
| π¦ Traefik | Cluster | Ingress controller with a built-in dashboard |
| β΅ Istio | Cluster | Service mesh |
| π kube-prometheus-stack | Cluster | Prometheus, Grafana, Alertmanager, exporters |
| πͺ΅ Loki | Cluster | Log aggregation with Promtail |
| π Thanos | Cluster | Global / HA Prometheus query layer |
| π° OpenCost | Cluster | Real-time Kubernetes cost monitoring |
Some add-ons expose a web UI through the same 7554 port (no extra ports to publish):
| Dashboard | URL | Notes |
|---|---|---|
| Grafana | http://localhost:7554/grafana | from kube-prometheus-stack; login admin / prom-operator |
| OpenCost | http://localhost:7554/opencost | cost explorer (uses Prometheus from kube-prometheus-stack) |
| Traefik | http://localhost:7554/traefik | routers, services & middlewares dashboard |
| Component | Technology |
|---|---|
| Frontend | React + Vite, xterm.js |
| Backend | Node.js / Express, node-pty WebSocket PTY |
| Cluster | K3s (single-node, in-container) |
| Proxy | nginx on container port 80, mapped to host port 7554 |
| Storage | SQLite (better-sqlite3) at /data/progress.db |
Everything runs inside a single Docker image managed by scripts/entrypoint.sh.
scenarios/
βββ data/ # One JSON file per scenario -> <scenario-id>.json
βββ bundles/ # One JSON file per bundle -> <bundle-id>.json
βββ SCHEMA.md # Full schema reference
addons/
βββ <addon-id>/ # One folder per add-on, each with an addon.json manifest
βββ SCHEMA.md # Full manifest schema reference
backend/
βββ server.js # Express API + WebSocket PTY
frontend/
βββ src/ # React + Vite SPA
scripts/
βββ entrypoint.sh # Container startup (k3s -> API -> nginx)
βββ nginx.conf # Reverse-proxy config
Contributions are what make open-source projects like this one grow β and every contribution counts, big or small. Whether you're fixing a typo, polishing a scenario description, or building a completely new exercise from scratch, you're helping the next person learn Kubernetes in the best way possible.
Please read our Contributing Guidelines to learn how to:
- Set up a local development environment.
- Create and hot-reload scenario definitions.
- Submit bug reports, enhancements, and pull requests.
We also expect all participants to adhere to our Code of Conduct.
You can find the list of core project maintainers in the Maintainers' List.
Each scenario is a single JSON file in scenarios/data directory; each bundle is a single JSON file in scenarios/bundles directory. See scenarios/SCHEMA.md for the full schema.
Task checklist:
validation.commandsβ idempotentkubectlcommands onlysetup_commands/teardown_commandsβkubectlor native Ubuntu commands only
MCQ checklist:
correct_optionmust match one of theoptions[].idvalues- Always include an
explanation
Each add-on is a folder under addons/ containing a single addon.json manifest. See addons/SCHEMA.md for the full schema, field reference, runtime variables, and worked examples β its id must match the folder name.
To ensure high performance and zero disk-I/O bottlenecking, scenarios, bundles, and add-on manifests are cached in memory on backend startup. When developing or updating them, you can hot-reload the definitions without rebuilding the image or restarting the container:
- Mount the Directory: Run the container with the local
scenarios/directory mounted to/app/scenarios(and/oraddons/to/app/addonsfor add-on work):docker run --rm -itd --privileged -p 7554:80 --name kubekosh \ -v <path_to_scenarios_directory>:/app/scenarios \ -v <path_to_addons_directory>:/app/addons zeborg/kubekosh:latest
- Reload Cache: Click the Reload Cache (β») button in the top right corner of the header in the web user interface, or send an API request:
curl -X POST http://localhost:7554/api/cache/reload
NOTE: The content in
<path_to_scenarios_directory>should be the path to the localscenarios/directory of the cloned repository with your updates, i.e., it should contain the updatedscenarios/dataandscenarios/bundlesdirectories.
# 1. Fork the repo on GitHub, then clone your fork
git clone https://github.com/<your-username>/kubekosh.git
cd kubekosh
# 2. Create a branch
git checkout -b feat/my-scenario
# 3. Add a new scenario file (copy an existing scenario as a template or create a new one)
cp scenarios/data/deploy-nginx.json scenarios/data/my-new-scenario.json
vim scenarios/data/my-new-scenario.json # edit the new scenario as per [SCHEMA.md](scenarios/SCHEMA.md)
# 4. Add the scenario ID to the relevant bundle
vim scenarios/bundles/k8s-basics.json # edit the bundle to include the new scenario ID
# 5. Build and test locally
# Run the built container directly:
docker build -t kubekosh . && docker run --rm -itd --privileged -p 7554:80 --name kubekosh kubekosh
# Or mount the scenarios folder for hot-reloading:
docker run --rm -itd --privileged -p 7554:80 -v $PWD/scenarios:/app/scenarios --name kubekosh zeborg/kubekosh:dev
# 6. Commit and push to your fork (example for adding `my-new-scenario` to `k8s-basics` bundle)
git add scenarios/data/my-new-scenario.json scenarios/bundles/k8s-basics.json
git commit -m "feat: add my-new-scenario to k8s-basics bundle"
git push -u origin feat/my-new-scenarioOpen a Pull Request from your fork's branch against main.
Apache 2.0 License β see LICENSE.








