ced4568 777efd168d docs(phase5c): enrollment communications documentation + Google Workspace runbook
- PHASE5C_ENROLLMENT_COMMUNICATIONS.md: the full design doc.
- RUNBOOK_GOOGLE_WORKSPACE_EMAIL.md: every REQUIRES GOOGLE WORKSPACE ADMIN ACTION step
  (mailbox, service account, domain-wide delegation scoped to gmail.send only, SPF/DKIM/DMARC),
  environment variables, testing procedure, production secret handling, rotation, revocation,
  troubleshooting, quotas.
- RUNBOOK_STUDENT_ACTIVATION.md: day-to-day operation of the pipeline from /admin.
- WEBSITE_ENROLLMENT_INTEGRATION.md: explicit website-vs-RootNode responsibility boundary,
  the new contact_email field, and closes the 'RootNode doesn't send activation email yet'
  known limitation this doc previously documented.
- RUNBOOK_SELF_PACED_ENROLLMENT.md, RUNBOOK_STUDENT_ACCOUNT_LIFECYCLE.md: point at the new
  automatic-email behavior and the Resend activation control.
- REMOTE_AND_SELF_PACED_ARCHITECTURE.md, ENGINEERING_SOP.md: close the enrollment-
  communication gap; new ENGINEERING_SOP §16.
- PRODUCTION_VALIDATION_CHECKLIST.md, README.md, platform/README.md: cross-references and a
  Phase 5C production-validation section.
2026-08-25 14:45:18 -05:00
2026-05-26 20:18:08 +05:30

KubeKosh

KubeKosh — RootNode Academy Edition

A browser-based Kubernetes lab for hands-on learners. Real K3s. Real kubectl. Instant validation. No cloud account, no local cluster.

License Platforms Kubernetes Docker Maintained by ced4568


Attribution. This is a branded, modified fork of the excellent zeborg/kubekosh, licensed under Apache 2.0. RootNode Academy adds custom scenarios, branding, and multi-student deployment tooling on top of the upstream project. Original copyright and license notices are preserved in LICENSE. Modified files are marked per Apache 2.0 §4. Full credit to the original author for the core platform.


What It Is

KubeKosh runs a real single-node K3s cluster inside one Docker container and pairs it with a browser terminal and automated scenario validation. A learner opens a tab, gets a live cluster, runs real kubectl, and clicks Validate to check their work against actual cluster state.

In the RootNode Academy curriculum this is the capstone rung — the Kubernetes & DevOps track that sits on top of the Linux / Git / Docker foundations. It is aimed at the advanced learner (roughly 14+), not the absolute beginner.


Quick Start

Prerequisite: Docker

docker run -itd --name kubekosh --privileged -p 7554:80 ced4568/kubekosh:latest

Open http://localhost:7554 and wait ~30s for the Cluster Ready indicator to turn green.

--privileged is required — K3s needs kernel namespaces and cgroups. Do not expose this container directly to the public internet. It is a teaching sandbox. Multi-student exposure is handled by the deployment layer below, not by publishing the raw container.

Persist Progress

docker run -itd --name kubekosh --privileged -p 7554:80 \
  -v <host_dir>:/data ced4568/kubekosh:latest

Progress is stored in SQLite at /data/progress.db. Mount a host directory to /data to keep progress across restarts — one volume per student.

Build From Source

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; Validate auto-checks cluster state.
  • MCQ — multiple choice with a detailed explanation on submission.

Custom RootNode Academy scenarios live alongside upstream ones in scenarios/data/ and are grouped into bundles in scenarios/bundles/. See scenarios/SCHEMA.md.


Architecture

flowchart TD
    subgraph Container["Single Docker Image (--privileged)"]
        NGINX["nginx :80 — reverse proxy"]
        FE["Frontend<br/>React + Vite + xterm.js"]
        BE["Backend<br/>Node / Express + node-pty (WebSocket PTY)"]
        K3S["K3s<br/>single-node in-container cluster"]
        DB[("SQLite<br/>/data/progress.db")]

        NGINX --> FE
        NGINX --> BE
        BE -->|kubectl / PTY| K3S
        BE --> DB
    end

    Student["Learner browser"] -->|:7554| NGINX
Component Technology
Frontend React + Vite, xterm.js
Backend Node.js / Express, node-pty WebSocket PTY
Cluster K3s (single-node, in-container)
Proxy nginx on port 80, mapped to host 7554
Storage SQLite (better-sqlite3) at /data/progress.db

Everything runs inside one image managed by scripts/entrypoint.sh.


Multi-Student Deployment (RootNode Academy addition)

The upstream project assumes one learner, one container — this image is still exactly that. Its backend/entrypoint/Dockerfile are unmodified except for a node-pty build fix (see docs/PHASE2A_GATEWAY_AND_STUDENT_FLOW.md §1); its frontend bundle gained progressive-hint controls and an assessment-mode indicator in Phase 3B (docs/PHASE3B_LEARNING_AND_ASSESSMENT.md §10–11) — additive UI, not a rewrite of the Lab experience. RootNode Academy multiplies the image into a real platform via separate provisioning and gateway layers rather than changing its core:

  • platform/provisioner/ — Postgres-backed environment registry, per-student Docker networking, firewall-enforced egress, idle reaper (docs/PHASE1_PLATFORM_FOUNDATION.md).
  • platform/api/ — lightweight Platform API: students, cohorts, curriculum, progress, detailed scenario attempt telemetry, progressive hints, assessment/capstone engine, achievements, persistent student/instructor sessions, per-instructor accounts (RBAC: owner/admin/ instructor), audit log, instructor/admin control plane. No k3s, no --privileged (docs/PHASE2B_ADMIN_AND_PLATFORM_DATA.md, docs/PHASE3A_IDENTITY_AND_INSTRUCTOR_ACCESS.md, docs/PHASE3B_LEARNING_AND_ASSESSMENT.md).
  • platform/gateway/ — the only student-facing path to a Lab: resolves identity from a server-controlled, persistent session cookie (not a client-suppliable header/param), proxies HTTP/WebSocket into that one student's container, never a raw container IP/port, and server-gates progressive hint reveal by stripping the Lab's own hint payload before it reaches the browser (docs/PHASE2A_GATEWAY_AND_STUDENT_FLOW.md, session model in docs/PHASE3A_IDENTITY_AND_INSTRUCTOR_ACCESS.md §3, hint gating in docs/PHASE3B_LEARNING_AND_ASSESSMENT.md §3).
  • The student flow (real login (email or instructor-assigned login ID) or legacy pilot roster entry → curriculum dashboard → Launch Lab → practice/assessments/capstone → achievements → live classroom → profile) lives in frontend/src/platform/; the instructor/admin portal (per-instructor login, cohorts, students with credential/CSV-import management, a remote classroom control center, instructor accounts, audit log, environment controls, learning analytics, assessment/capstone management) lives in frontend/src/admin/ at the /admin route — both additions alongside the existing Lab UI, not a rewrite of it.
  • Students authenticate with real credentials as of Phase 5A (email+password or login-identifier+password, first-login/reset via a single-use token an instructor relays) — see docs/PHASE5A_STUDENT_IDENTITY_REMOTE_CLASSROOM.md. Instructors run live, remote-capable classes from /admin (presence, Lab/learning status, help-request queue, announcements, guidance-only current-activity) — RootNode owns identity/coordination, an external service (Meet/Zoom/Teams/etc.) owns the actual video/voice.
  • Students can now be enrolled in a self-paced program (as of Phase 5B) — "My Programs" on the student dashboard, entitlement enforced server-side (pending/future/expired/cancelled enrollments cannot launch a Lab no matter what the browser sends), completion server-derived from the existing capstone rules. /admin gained a Programs area (program authoring, manual enrollment, activate/cancel). A separate, provider-neutral POST /api/integrations/enrollments boundary — server-to-server only, no browser session involved — is what the future public rootnodeacademy.com website/checkout will call to create these enrollments; see docs/PHASE5B_SELF_PACED_ENROLLMENT.md and docs/WEBSITE_ENROLLMENT_INTEGRATION.md.
  • As of Phase 5C, RootNode actually tells students what's happening — real activation, enrollment-confirmation, and password-reset email, delivered asynchronously through a provider-neutral notification worker (Google Workspace via the Gmail API in production, a deterministic dev provider everywhere else — no test/dev run ever emails a real person). See docs/PHASE5C_ENROLLMENT_COMMUNICATIONS.md and docs/RUNBOOK_GOOGLE_WORKSPACE_EMAIL.md.

Never publish the raw privileged container — front it with isolation (that's what the Gateway is). The one-container docker run --privileged -p 7554:80 ... command above stays supported for local development and scenario authoring; it is not how this gets deployed to real students.

Key properties of the platform (not this image):

  • One container per student, its own Docker network, its own firewall chain — never a shared cluster between learners. Verified with two simultaneous students: separate clusters, separate progress, no cross-access.
  • Progress/identity live outside the disposable container, in the Platform API's own PostgreSQL (authoritative as of Phase 2B) — destroying or recreating a student's Lab never loses their academic record. Verified with a full class-sized (3-student) cohort workflow: provision, complete different scenarios, reset one student's Lab, destroy all Labs after class — progress survives every step.
  • Instructors sign in with their own account (no shared password) and manage cohorts, students, curriculum assignment, and classroom Lab prep (provision an entire cohort before class, verify readiness, destroy Labs after) from /admin — no manual database, Docker, or Kubernetes access needed. Owners manage instructor accounts and roles; every instructor/admin action is recorded in an audit log.
  • Sessions (student and instructor) are Postgres-backed and survive a Platform API restart — verified by actually restarting it mid-session and confirming access still works.
  • Every validation attempt, hint reveal, curriculum stage completion, exam, and Capstone attempt is recorded in Postgres, not the disposable Lab — a Lab reset or recreate never loses attempt telemetry, hint progress, or an in-progress assessment's timer. Verified live: reset a Lab mid-assessment, timer and drawn scenario set were unchanged afterward.
  • Exams and the RootNode Capstone use a server-authoritative timer and a server-drawn, server-stored scenario set — nothing the browser sends can change either.
  • CPU/memory/PID/storage limits are enforced per container, config-driven.
  • Egress is restricted to an allowlisted proxy at the firewall layer, not left open.
  • Idle/abandoned environments are automatically cleaned up, and a student can launch a fresh one and keep going without losing progress.

Production topology and what's built vs. not yet: docs/LAB_ARCHITECTURE.md, docs/PHASE1_PLATFORM_FOUNDATION.md, docs/PHASE2A_GATEWAY_AND_STUDENT_FLOW.md, docs/PHASE3A_IDENTITY_AND_INSTRUCTOR_ACCESS.md, docs/PHASE3B_LEARNING_AND_ASSESSMENT.md, docs/PHASE5A_STUDENT_IDENTITY_REMOTE_CLASSROOM.md, docs/PHASE5B_SELF_PACED_ENROLLMENT.md, docs/PHASE5C_ENROLLMENT_COMMUNICATIONS.md.

The production infrastructure package (Proxmox/Ansible/Terraform/firewall/monitoring/backup/CI) that runs all of this on real hardware lives in infra/ — see docs/PHASE4_PRODUCTION_INFRASTRUCTURE.md and docs/PHASE4_1_PREPRODUCTION_HARDENING.md (the Gateway-to-Lab cross-VM routing fix, plus application hardening — real pagination, abandonment handling, a Postgres-backed rate limiter, a structured assessment editor, admission control). Built and locally validated now; deployment is pending purchase of the target Hetzner dedicated server.


Repository Layout

scenarios/
├── data/         # one JSON file per scenario  -> <scenario-id>.json
├── bundles/      # one JSON file per bundle     -> <bundle-id>.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

Authoring Scenarios

Each scenario is one JSON file in scenarios/data/; each bundle is one JSON file in scenarios/bundles/. See scenarios/SCHEMA.md for the full schema.

Task checklist

  • validation.commands — idempotent kubectl only
  • setup_commands / teardown_commands — kubectl or native Ubuntu only

MCQ checklist

  • correct_option must match an options[].id
  • always include an explanation

Hot-reload while authoring (no rebuild):

docker run --rm -itd --privileged -p 7554:80 --name kubekosh \
  -v $PWD/scenarios:/app/scenarios ced4568/kubekosh:latest
curl -X POST http://localhost:7554/api/cache/reload

License

Apache 2.0 — see LICENSE. Original work © the zeborg/kubekosh authors. Modifications © RootNode Academy / Chase Dumphord (ced4568).

S
Description
No description provided
Readme Apache-2.0
12 MiB
Languages
JavaScript 88.2%
Shell 5.5%
CSS 4.6%
Jinja 0.8%
Dockerfile 0.6%
Other 0.3%