KubeKosh Logo

KubeKosh

Self-hosted Kubernetes Lab for Hands-on Learning

Docker Hub License Platforms

--- KubeKosh runs a real [K3s](https://k3s.io/) 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. ## Screenshots | | | | |---|---|---| | ![Scenario browser with live terminal](screenshots/1.png) | ![Task scenario with problem statement](screenshots/2.png) | ![Contextual hints with copy-ready commands](screenshots/3.png) | | ![Automated validation — all checks passed](screenshots/4.png) | ![Exam mode — start with custom duration and scenario count](screenshots/5.png) | ![Exam mode — live exam with timer](screenshots/6.png) | | ![Exam MCQ — selecting an answer](screenshots/7.png) | ![Exam MCQ — correct answer with explanation](screenshots/8.png) | ![Exam history with per-scenario score report](screenshots/9.png) | --- ## Quick Start **Prerequisite:** [Docker](https://docs.docker.com/get-docker/) ```bash docker run -itd --name kubekosh --privileged -p 7554:80 zeborg/kubekosh:latest ``` Open **http://localhost:7554** — wait ~30 seconds for the *Cluster Ready* indicator to turn green. > `--privileged` is 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. ### Persist Progress ```bash docker run -itd --name kubekosh --privileged -p 7554:80 \ -v :/data zeborg/kubekosh:latest ``` Progress is stored in SQLite at `/data/progress.db` inside the container. Mount a local directory to `/data` to keep progress across container restarts. ### Build From Source ```bash docker build -t kubekosh . # multi-platform docker buildx build --platform linux/amd64,linux/arm64 -t kubekosh . ``` --- ## What's Inside | Bundle | Focus | Exam Mode | |---|---|---| | 🌱 Kubernetes Basics | Core concepts | 60 min | | 🧑‍✈️ Kubernetes Administrator | 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. ### Shell Aliases 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 ` | `kubectl config set-context --current --namespace=` | | `kctx ` | `kubectl config use-context ` | --- ## Architecture | 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`. --- ## Repository Layout ``` scenarios/ ├── data/ # One JSON file per scenario -> .json ├── bundles/ # One JSON file per bundle -> .json └── SCHEMA.md # Full 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 ``` --- ## Contributing 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. **Thank you for taking the time!** ### Adding Scenarios 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`](scenarios/SCHEMA.md) for the full schema. **Task checklist:** - `validation.commands` — idempotent `kubectl` commands only - `setup_commands` / `teardown_commands` — `kubectl` or native Ubuntu commands only **MCQ checklist:** - `correct_option` must match one of the `options[].id` values - Always include an `explanation` ### In-Memory Cache & Hot Reloading To ensure high performance and zero disk-I/O bottlenecking, scenarios and bundles are cached in memory on backend startup. When developing or updating scenarios, you can hot-reload the definitions without rebuilding the image or restarting the container: 1. **Mount Scenarios Directory:** Run the container with the local `scenarios/` directory mounted to `/app/scenarios`: ```bash docker run --rm -itd --privileged -p 7554:80 --name kubekosh -v :/app/scenarios zeborg/kubekosh:latest ``` 2. **Reload Cache:** Click the **Reload Scenario Cache** (↻) button in the top right corner of the header in the web user interface, or send an API request: ```bash curl -X POST http://localhost:7554/api/cache/reload ``` > **NOTE:** > The content in `` should be the path to the local `scenarios/` directory of the cloned repository with your updates, i.e., it should contain the updated `scenarios/data` and `scenarios/bundles` directories. ### Workflow ```bash # 1. Fork the repo on GitHub, then clone your fork git clone https://github.com//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-scenario ``` Open a Pull Request from your fork's branch against `main`. --- ## License Apache 2.0 License — see [LICENSE](LICENSE).