Initial commit

This commit is contained in:
Abhinav Sinha
2026-05-26 20:18:08 +05:30
committed by GitHub
commit c26c0122ce
34 changed files with 8866 additions and 0 deletions
+211
View File
@@ -0,0 +1,211 @@
# KubeKosh Configuration Schema Reference
KubeKosh uses two primary JSON files to define its curriculum, learning paths, and exam configurations:
1. **Bundles (`scenarios/bundles.json`)**: Defines the high-level study bundles (e.g., CKA, CKAD, CKS), active highlights, durations for exams, and lists of included scenarios.
2. **Scenarios (`scenarios/scenarios.json`)**: Defines individual exercises, hands-on tasks, multiple-choice questions (MCQs), environment preparations, and automated validation scripts.
---
## 1. Bundles Schema (`scenarios/bundles.json`)
Bundles are defined as a JSON array of objects. Each bundle organizes a learning track or mock exam.
### Schema Fields
* **`id`** *(string, required)*: A unique, kebab-case identifier for the bundle (e.g., `k8s-basics`).
* **`name`** *(string, required)*: The human-readable name of the bundle shown in navigation (e.g., `Kubernetes Basics`).
* **`icon`** *(string, required)*: An emoji or glyph representing the bundle (e.g., `🌱`).
* **`tagline`** *(string, required)*: A short summary of the bundle's objectives.
* **`color`** *(string, required)*: Hex color code representing the bundle's UI identity/accent color (e.g., `#3fb950`).
* **`colorDim`** *(string, required)*: Translucent RGBA color matching the accent color at low opacity, used for UI row highlighting (e.g., `rgba(63,185,80,0.12)`).
* **`exam_minutes`** *(number, required)*: The time limit allocated for the mock exam in minutes (e.g., `60`).
* **`scenario_ids`** *(array of strings, required)*: List of scenario IDs belonging to this bundle in the order they should appear.
### Example Bundle
```json
{
"id": "k8s-basics",
"name": "Kubernetes Basics",
"icon": "🌱",
"tagline": "Core concepts for beginners",
"color": "#3fb950",
"colorDim": "rgba(63,185,80,0.12)",
"exam_minutes": 60,
"scenario_ids": [
"pod-basics-mcq",
"kubectl-essentials-mcq",
"namespaces-basics",
"deploy-nginx"
]
}
```
---
## 2. Scenarios Schema (`scenarios/scenarios.json`)
Scenarios are defined as a JSON array of objects. A scenario can be either a hands-on console challenge (`"task"`) or a multiple-choice question (`"mcq"`).
### Common Fields (All Types)
```jsonc
{
"id": "unique-kebab-case-id", // string — unique scenario identifier
"title": "Human-readable Title", // string — shown in sidebar list
"category": "Workloads", // string — groups scenarios in sidebar accordion
"difficulty": "Easy", // "Easy" | "Medium" | "Hard"
"type": "task", // "task" | "mcq"
"weight": 7, // number — points value (used for final grade scoring)
"description": "## Markdown...", // string — problem statement supporting GitHub-flavored Markdown
"hints": [...], // array — see Hints schema below
"setup_commands": [...], // array<object> — commands run on environment preparation
"teardown_commands": [...], // array<object> — optional — cleanup commands run after scenario completes
"default_namespace": "default" // string — optional — default active namespace for the terminal
}
```
---
### Hints Schema
Each hint is rendered as a collapsible card inside the Hints tab of the UI:
```jsonc
{
"title": "Short title for the hint card",
"body": "Explanation text (plain text, no markdown format).",
"command": "kubectl run nginx --image=nginx" // optional — renders a copyable code block
}
```
---
### Setup & Teardown Commands
* **`setup_commands`**: Executed sequentially on the Kubernetes cluster when the user starts a scenario or clicks **"Prepare Environment"**. Useful for pre-deploying resources or injecting bugs.
* **`teardown_commands`**: Optional cleanup commands run when moving away from or resetting a scenario.
* Commands must be **objects** with a `command` key:
```jsonc
"setup_commands": [
{ "command": "kubectl create namespace debug" },
{ "command": "kubectl create deployment broken-app --image=nginx:1.25 -n debug" }
]
```
* *Note:* Non-zero exit codes are tolerated (e.g., "namespace already exists" errors won't halt the pipeline). All commands execute as `root`.
---
### Type: `"task"` — Hands-On Scenario
Requires the user to run shell commands in the interactive terminal. The system runs an automated validation sequence to check the cluster state.
```jsonc
{
"type": "task",
"validation": {
"description": "Check that deployment has been correctly configured",
"commands": [
{
"description": "Checks the running pods count",
"command": "kubectl get deploy nginx -o jsonpath='{.status.readyReplicas}'",
"expected_output": "3",
"match": "exact" // "exact" | "contains" | "regex"
}
]
}
}
```
#### Match Modes
| Mode | Behaviour |
| :--- | :--- |
| `exact` | Trimmed stdout must exactly equal `expected_output`. |
| `contains` | stdout must contain `expected_output` as a substring. |
| `not_contains` | stdout must **not** contain `expected_output` as a substring. |
| `regex` | stdout must match the regular expression in `expected_output`. |
---
### Type: `"mcq"` — Multiple Choice Question
Renders a questionnaire block. No terminal is shown. The user answers by selecting an option.
```jsonc
{
"type": "mcq",
"options": [
{ "id": "a", "text": "Option A explanation" },
{ "id": "b", "text": "Option B explanation" },
{ "id": "c", "text": "Option C explanation" },
{ "id": "d", "text": "Option D explanation" }
],
"correct_option": "c", // must match one of the option IDs
"explanation": "Detailed explanation of why C is the correct answer." // shown after submitting
}
```
---
## 3. Full Examples
### Full Example — Hands-On Task Scenario
```json
{
"id": "scale-deployment",
"title": "Scale a Deployment",
"category": "Workloads",
"difficulty": "Easy",
"type": "task",
"weight": 4,
"description": "## Scale the Deployment\n\nA deployment named `myapp` exists in the `default` namespace.\n\n**Scale it to 5 replicas.**",
"hints": [
{
"title": "Using kubectl scale",
"body": "The scale subcommand lets you change the replica count imperatively.",
"command": "kubectl scale deployment myapp --replicas=5"
}
],
"setup_commands": [
{ "command": "kubectl create deployment myapp --image=nginx:1.25 --replicas=1" }
],
"teardown_commands": [
{ "command": "kubectl delete deployment myapp --ignore-not-found" }
],
"default_namespace": "default",
"validation": {
"description": "Checks that myapp has 5 ready replicas.",
"commands": [
{
"description": "myapp has 5 ready replicas",
"command": "kubectl get deployment myapp -o jsonpath='{.status.readyReplicas}'",
"expected_output": "5",
"match": "exact"
}
]
}
}
```
### Full Example — MCQ Scenario
```json
{
"id": "service-types-mcq",
"title": "Kubernetes Service Types",
"category": "Networking",
"difficulty": "Easy",
"type": "mcq",
"weight": 3,
"description": "## Kubernetes Service Types\n\nWhich `kubectl` command creates a ClusterIP service named `my-svc` exposing port 80 for a deployment named `my-app`?",
"options": [
{ "id": "a", "text": "kubectl expose deployment my-app --name=my-svc --port=80 --type=ClusterIP" },
{ "id": "b", "text": "kubectl create service my-svc --port=80" },
{ "id": "c", "text": "kubectl apply service my-app --port=80" },
{ "id": "d", "text": "kubectl expose pod my-app --name=my-svc --port=80 --type=NodePort" }
],
"correct_option": "a",
"explanation": "`kubectl expose deployment` is the correct imperative command. It creates a Service targeting the deployment's pods. `--type=ClusterIP` is the default but explicit here for clarity.",
"hints": [
{
"title": "kubectl expose syntax",
"body": "Use kubectl expose to create a Service from an existing resource. Specify the resource type, name, port, and service type.",
"command": "kubectl expose deployment my-app --name=my-svc --port=80 --type=ClusterIP"
}
],
"setup_commands": [],
"teardown_commands": [],
"default_namespace": "default"
}
```
+146
View File
@@ -0,0 +1,146 @@
[
{
"id": "k8s-basics",
"name": "Kubernetes Basics",
"icon": "\ud83c\udf31",
"tagline": "Core concepts for beginners",
"color": "#3fb950",
"colorDim": "rgba(63,185,80,0.12)",
"exam_minutes": 60,
"scenario_ids": [
"pod-basics-mcq",
"kubectl-essentials-mcq",
"labels-selectors-mcq",
"init-containers-mcq",
"namespaces-basics",
"deploy-nginx",
"scale-deployment",
"rolling-update-task",
"liveness-probe-task",
"jobs-cronjobs-mcq",
"daemonset-mcq",
"configmap-volume",
"resource-limits-task",
"env-vars-configmap",
"secrets-basics",
"services-mcq",
"multi-container-pod-basics",
"expose-service-basics",
"pod-labeling-basics",
"extract-logs-basics",
"edit-deployment-basics",
"jsonpath-basics",
"dry-run-manifest-basics",
"delete-by-label-basics",
"kubectl-cp-basics",
"exec-command-basics"
]
},
{
"id": "k8s-admin",
"name": "Kubernetes Administrator",
"icon": "\ud83e\uddd1\u200d\u2708\ufe0f",
"tagline": "CKA exam \u2014 cluster administration",
"color": "#58a6ff",
"colorDim": "rgba(88,166,255,0.12)",
"exam_minutes": 120,
"scenario_ids": [
"rbac-role",
"rbac-clusterrole",
"serviceaccount-pod",
"node-label-selector",
"node-taint-toleration",
"resource-quota-ns",
"limitrange-task",
"etcd-backup-mcq",
"cluster-upgrade-mcq",
"deployment-rollback",
"cronjob-task",
"job-task",
"readiness-probe-task",
"pod-affinity-mcq",
"nodeport-task",
"ingress-task",
"dns-resolution-mcq",
"endpoint-fix-task",
"networkpolicy-egress",
"network-policy",
"storageclass-mcq",
"pvc-dynamic-task",
"emptydir-pod",
"pv-pvc-mount",
"pod-security-context",
"broken-deployment",
"crashloop-fix",
"container-logging-mcq"
]
},
{
"id": "k8s-appdev",
"name": "Kubernetes Developer",
"icon": "\ud83d\udee0\ufe0f",
"tagline": "CKAD exam \u2014 application development",
"color": "#bc8cff",
"colorDim": "rgba(188,140,255,0.12)",
"exam_minutes": 120,
"scenario_ids": [
"pod-basics-mcq",
"kubectl-essentials-mcq",
"namespaces-basics",
"labels-selectors-mcq",
"deploy-nginx",
"scale-deployment",
"rolling-update-task",
"deployment-rollback",
"liveness-probe-task",
"readiness-probe-task",
"configmap-volume",
"env-vars-configmap",
"secrets-basics",
"resource-limits-task",
"cronjob-task",
"job-task",
"emptydir-pod",
"pvc-dynamic-task",
"services-mcq",
"nodeport-task",
"ingress-task",
"rbac-role",
"pod-security-context",
"crashloop-fix",
"container-logging-mcq"
]
},
{
"id": "k8s-security",
"name": "Kubernetes Security",
"icon": "\ud83d\udee1",
"tagline": "CKS exam \u2014 hardening and threats",
"color": "#f97316",
"colorDim": "rgba(249,115,22,0.12)",
"exam_minutes": 120,
"scenario_ids": [
"cks-network-policy",
"cks-pod-security-context",
"cks-rbac-least-privilege",
"cks-seccomp-profile",
"cks-immutable-secret",
"cks-apparmor-profile",
"cks-automount-token",
"cks-network-policy-metadata",
"cks-rbac-clusterrole",
"cks-psa-namespace",
"cks-mcq-runtime-security",
"cks-mcq-api-server",
"cks-mcq-image-footprint",
"cks-mcq-psp-replacement",
"cks-mcq-kubelet-auth",
"cks-readonly-filesystem",
"cks-drop-capabilities",
"cks-tls-ingress",
"cks-image-pull-secret",
"cks-mcq-sandboxing",
"cks-mcq-audit-policy"
]
}
]
File diff suppressed because it is too large Load Diff