feat(curriculum): add RootNode learning path, student roster, and scenario isolation metadata
Pre-Phase-1 platform work, approved and tested earlier but not yet committed: - Terminal banner: "RootNode Academy Lab — node: k8s-lab", upstream KubeKosh attribution left untouched in footer/README/LICENSE. - RootNode curriculum mode: scenarios/rootnode-path.json (Foundation -> Workloads -> Networking -> Configuration -> Troubleshooting -> Real Ops -> Capstone), built from existing scenario content grouped by category, no new scenarios invented. New GET /api/curriculum/path endpoint. - Student roster + per-student progress: instructor-roster, pick-your-name login (no password), students/environments-adjacent progress table migrated to a (student_id, scenario_id) composite key so practice progress and exam sessions are isolated per student instead of one global bucket. New /api/roster, /api/login endpoints. - scenarios/data/*.json: added isolation_type metadata (shared_namespace vs ephemeral_cluster) from an audit of which scenarios execute cluster-scoped or node-level commands. This was Tier-1-isolation groundwork that got superseded same-day by the full-ephemeral-per-student architecture (see docs/LAB_ARCHITECTURE.md) — the field is kept as descriptive metadata only, per the note now in scenarios/SCHEMA.md. Not wasted: it's an accurate audit of which scenarios touch cluster-scoped resources, useful independent of isolation model. - .gitignore added (node_modules/, frontend/dist/, *.db, /data/, .env) — none existed before; without it, npm installs during testing would have landed in a commit. Known limitation still open: no frontend UI for any of this yet (login screen, roster-add form, curriculum view) — API-only. No auth on the roster-add endpoint. Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
"id": "annotate-resource-basics",
|
||||
"title": "Annotating Kubernetes Resources",
|
||||
"category": "Core Concepts",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Easy",
|
||||
"type": "task",
|
||||
"weight": 3,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "broken-deployment",
|
||||
"title": "Debug a Failing Deployment",
|
||||
"category": "Troubleshooting",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Medium",
|
||||
"type": "task",
|
||||
"weight": 8,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "cks-apparmor-profile",
|
||||
"title": "AppArmor Profiles",
|
||||
"category": "Workload Security",
|
||||
"isolation_type": "ephemeral_cluster",
|
||||
"difficulty": "Hard",
|
||||
"type": "task",
|
||||
"weight": 5,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "cks-audit-policy",
|
||||
"title": "Write a Kubernetes Audit Policy",
|
||||
"category": "Cluster Setup",
|
||||
"isolation_type": "ephemeral_cluster",
|
||||
"difficulty": "Hard",
|
||||
"type": "task",
|
||||
"weight": 7,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "cks-automount-token",
|
||||
"title": "Disable ServiceAccount Token",
|
||||
"category": "Workload Security",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Easy",
|
||||
"type": "task",
|
||||
"weight": 3,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "cks-drop-capabilities",
|
||||
"title": "Drop Linux Capabilities",
|
||||
"category": "Workload Security",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Medium",
|
||||
"type": "task",
|
||||
"weight": 5,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "cks-egress-namespace",
|
||||
"title": "Restrict Egress to Namespace",
|
||||
"category": "Network Security",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Hard",
|
||||
"type": "task",
|
||||
"weight": 6,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "cks-image-pull-secret",
|
||||
"title": "Private Registry Image Pull Secret",
|
||||
"category": "Supply Chain Security",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Easy",
|
||||
"type": "task",
|
||||
"weight": 4,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "cks-immutable-secret",
|
||||
"title": "Immutable Secrets",
|
||||
"category": "Cluster Security",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Easy",
|
||||
"type": "task",
|
||||
"weight": 3,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "cks-mcq-api-server",
|
||||
"title": "API Server Authentication",
|
||||
"category": "Cluster Setup",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Easy",
|
||||
"type": "mcq",
|
||||
"weight": 2,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "cks-mcq-audit-policy",
|
||||
"title": "Kubernetes Audit Logging Levels",
|
||||
"category": "Cluster Setup",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Medium",
|
||||
"type": "mcq",
|
||||
"weight": 3,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "cks-mcq-image-footprint",
|
||||
"title": "Minimizing Image Footprint",
|
||||
"category": "Supply Chain Security",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Easy",
|
||||
"type": "mcq",
|
||||
"weight": 2,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "cks-mcq-kubelet-auth",
|
||||
"title": "Securing the Kubelet",
|
||||
"category": "Cluster Setup",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Medium",
|
||||
"type": "mcq",
|
||||
"weight": 2,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "cks-mcq-psp-replacement",
|
||||
"title": "Pod Security Evolution",
|
||||
"category": "Cluster Security",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Easy",
|
||||
"type": "mcq",
|
||||
"weight": 2,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "cks-mcq-runtime-security",
|
||||
"title": "Runtime Security Tools",
|
||||
"category": "System Hardening",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Medium",
|
||||
"type": "mcq",
|
||||
"weight": 2,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "cks-mcq-sandboxing",
|
||||
"title": "Container Runtime Sandboxing",
|
||||
"category": "System Hardening",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Hard",
|
||||
"type": "mcq",
|
||||
"weight": 3,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "cks-network-policy-metadata",
|
||||
"title": "Block Cloud Metadata",
|
||||
"category": "Network Security",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Hard",
|
||||
"type": "task",
|
||||
"weight": 6,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "cks-network-policy",
|
||||
"title": "Default Deny Network Policy",
|
||||
"category": "Network Security",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Medium",
|
||||
"type": "task",
|
||||
"weight": 5,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "cks-non-root-enforce",
|
||||
"title": "Enforce Non-Root Container",
|
||||
"category": "Workload Security",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Medium",
|
||||
"type": "task",
|
||||
"weight": 5,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "cks-pod-security-context",
|
||||
"title": "Pod Security Context",
|
||||
"category": "Workload Security",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Medium",
|
||||
"type": "task",
|
||||
"weight": 5,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "cks-psa-namespace",
|
||||
"title": "Pod Security Admission",
|
||||
"category": "Cluster Security",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Easy",
|
||||
"type": "task",
|
||||
"weight": 4,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "cks-rbac-clusterrole",
|
||||
"title": "Cluster-Level RBAC",
|
||||
"category": "Cluster Security",
|
||||
"isolation_type": "ephemeral_cluster",
|
||||
"difficulty": "Medium",
|
||||
"type": "task",
|
||||
"weight": 5,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "cks-rbac-least-privilege",
|
||||
"title": "RBAC Least Privilege",
|
||||
"category": "Cluster Security",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Medium",
|
||||
"type": "task",
|
||||
"weight": 4,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "cks-readonly-filesystem",
|
||||
"title": "Read-Only Root Filesystem",
|
||||
"category": "Workload Security",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Easy",
|
||||
"type": "task",
|
||||
"weight": 4,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "cks-runtime-class",
|
||||
"title": "RuntimeClass for Sandboxed Workloads",
|
||||
"category": "System Hardening",
|
||||
"isolation_type": "ephemeral_cluster",
|
||||
"difficulty": "Medium",
|
||||
"type": "task",
|
||||
"weight": 5,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "cks-seccomp-profile",
|
||||
"title": "Seccomp Profiles",
|
||||
"category": "Workload Security",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Hard",
|
||||
"type": "task",
|
||||
"weight": 6,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "cks-tls-ingress",
|
||||
"title": "Secure Ingress with TLS",
|
||||
"category": "Network Security",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Hard",
|
||||
"type": "task",
|
||||
"weight": 7,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "cluster-upgrade-mcq",
|
||||
"title": "Cluster Upgrade Order",
|
||||
"category": "Cluster Administration",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Hard",
|
||||
"type": "mcq",
|
||||
"weight": 5,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "configmap-volume",
|
||||
"title": "Mount ConfigMap as Volume",
|
||||
"category": "Configuration",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Medium",
|
||||
"type": "task",
|
||||
"weight": 7,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "container-logging-mcq",
|
||||
"title": "Container Logging and Monitoring",
|
||||
"category": "Troubleshooting",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Easy",
|
||||
"type": "mcq",
|
||||
"weight": 3,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "crashloop-fix",
|
||||
"title": "Fix a CrashLoopBackOff Pod",
|
||||
"category": "Troubleshooting",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Medium",
|
||||
"type": "task",
|
||||
"weight": 7,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "cronjob-task",
|
||||
"title": "Create a CronJob",
|
||||
"category": "Workloads & Scheduling",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Easy",
|
||||
"type": "task",
|
||||
"weight": 4,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "daemonset-mcq",
|
||||
"title": "Understanding DaemonSets",
|
||||
"category": "Workloads",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Easy",
|
||||
"type": "mcq",
|
||||
"weight": 3,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "delete-by-label-basics",
|
||||
"title": "Bulk Deletion by Label",
|
||||
"category": "Core Concepts",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Easy",
|
||||
"type": "task",
|
||||
"weight": 3,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "deploy-nginx",
|
||||
"title": "Deploy and Expose Nginx",
|
||||
"category": "Workloads",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Easy",
|
||||
"type": "task",
|
||||
"weight": 5,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "deployment-rollback",
|
||||
"title": "Rolling Back a Deployment",
|
||||
"category": "Workloads & Scheduling",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Easy",
|
||||
"type": "task",
|
||||
"weight": 5,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "deployment-strategy-mcq",
|
||||
"title": "Deployment Update Strategies",
|
||||
"category": "Workloads",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Medium",
|
||||
"type": "mcq",
|
||||
"weight": 3,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "dns-resolution-mcq",
|
||||
"title": "Kubernetes DNS Resolution",
|
||||
"category": "Services & Networking",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Easy",
|
||||
"type": "mcq",
|
||||
"weight": 3,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "dry-run-manifest-basics",
|
||||
"title": "Generating YAML Manifests",
|
||||
"category": "Core Concepts",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Easy",
|
||||
"type": "task",
|
||||
"weight": 4,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "edit-deployment-basics",
|
||||
"title": "Updating Deployments",
|
||||
"category": "Workloads",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Easy",
|
||||
"type": "task",
|
||||
"weight": 4,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "emptydir-pod",
|
||||
"title": "Shared emptyDir Volume Between Containers",
|
||||
"category": "Storage",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Easy",
|
||||
"type": "task",
|
||||
"weight": 5,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "endpoint-fix-task",
|
||||
"title": "Fix a Broken Service Selector",
|
||||
"category": "Troubleshooting",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Medium",
|
||||
"type": "task",
|
||||
"weight": 7,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "env-vars-configmap",
|
||||
"title": "Environment Variables from ConfigMap",
|
||||
"category": "Configuration",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Easy",
|
||||
"type": "task",
|
||||
"weight": 4,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "etcd-backup-mcq",
|
||||
"title": "etcd Backup and Restore",
|
||||
"category": "Cluster Administration",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Hard",
|
||||
"type": "mcq",
|
||||
"weight": 5,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "exec-command-basics",
|
||||
"title": "Execute Commands in Pods",
|
||||
"category": "Troubleshooting",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Easy",
|
||||
"type": "task",
|
||||
"weight": 3,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "expose-service-basics",
|
||||
"title": "Exposing an Application",
|
||||
"category": "Services & Networking",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Easy",
|
||||
"type": "task",
|
||||
"weight": 4,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "extract-logs-basics",
|
||||
"title": "Extract Container Logs",
|
||||
"category": "Troubleshooting",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Easy",
|
||||
"type": "task",
|
||||
"weight": 4,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "field-selector-basics",
|
||||
"title": "Filtering Resources with Field Selectors",
|
||||
"category": "Core Concepts",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Easy",
|
||||
"type": "task",
|
||||
"weight": 4,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "ingress-task",
|
||||
"title": "Create an Ingress Resource",
|
||||
"category": "Services & Networking",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Medium",
|
||||
"type": "task",
|
||||
"weight": 7,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "init-container-task-basics",
|
||||
"title": "Pod with Init Container",
|
||||
"category": "Core Concepts",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Medium",
|
||||
"type": "task",
|
||||
"weight": 5,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "init-containers-mcq",
|
||||
"title": "Init Containers Behaviour",
|
||||
"category": "Core Concepts",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Easy",
|
||||
"type": "mcq",
|
||||
"weight": 3,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "job-task",
|
||||
"title": "Create a One-Shot Job",
|
||||
"category": "Workloads & Scheduling",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Easy",
|
||||
"type": "task",
|
||||
"weight": 4,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "jobs-cronjobs-mcq",
|
||||
"title": "Jobs vs CronJobs",
|
||||
"category": "Workloads",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Easy",
|
||||
"type": "mcq",
|
||||
"weight": 3,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "jsonpath-basics",
|
||||
"title": "JSONPath Data Extraction",
|
||||
"category": "Core Concepts",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Medium",
|
||||
"type": "task",
|
||||
"weight": 5,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "kubectl-cp-basics",
|
||||
"title": "Copy Files to Containers",
|
||||
"category": "Troubleshooting",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Medium",
|
||||
"type": "task",
|
||||
"weight": 4,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "kubectl-diff-basics",
|
||||
"title": "Previewing Changes with kubectl diff",
|
||||
"category": "Core Concepts",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Medium",
|
||||
"type": "task",
|
||||
"weight": 4,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "kubectl-essentials-mcq",
|
||||
"title": "Essential kubectl Commands",
|
||||
"category": "Core Concepts",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Easy",
|
||||
"type": "mcq",
|
||||
"weight": 2,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "kubectl-explain-basics",
|
||||
"title": "Exploring the API with kubectl explain",
|
||||
"category": "Core Concepts",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Easy",
|
||||
"type": "task",
|
||||
"weight": 3,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "kubectl-output-format-mcq",
|
||||
"title": "kubectl Output Formats",
|
||||
"category": "Core Concepts",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Easy",
|
||||
"type": "mcq",
|
||||
"weight": 2,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "kubectl-patch-basics",
|
||||
"title": "Patching Resources with kubectl patch",
|
||||
"category": "Core Concepts",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Medium",
|
||||
"type": "task",
|
||||
"weight": 5,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "labels-selectors-mcq",
|
||||
"title": "Labels and Selectors",
|
||||
"category": "Core Concepts",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Easy",
|
||||
"type": "mcq",
|
||||
"weight": 3,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "limitrange-task",
|
||||
"title": "LimitRange for Default Container Limits",
|
||||
"category": "Workloads & Scheduling",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Medium",
|
||||
"type": "task",
|
||||
"weight": 6,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "liveness-probe-task",
|
||||
"title": "Configure a Liveness Probe",
|
||||
"category": "Workloads",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Medium",
|
||||
"type": "task",
|
||||
"weight": 6,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "multi-container-pod-basics",
|
||||
"title": "Create a Multi-Container Pod",
|
||||
"category": "Core Concepts",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Easy",
|
||||
"type": "task",
|
||||
"weight": 5,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "namespaces-basics",
|
||||
"title": "Working with Namespaces",
|
||||
"category": "Core Concepts",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Easy",
|
||||
"type": "task",
|
||||
"weight": 4,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "network-policy",
|
||||
"title": "Isolate Traffic with NetworkPolicy",
|
||||
"category": "Networking",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Hard",
|
||||
"type": "task",
|
||||
"weight": 9,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "networkpolicy-egress",
|
||||
"title": "Egress NetworkPolicy",
|
||||
"category": "Security",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Hard",
|
||||
"type": "task",
|
||||
"weight": 8,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "node-cordon-basics",
|
||||
"title": "Cordoning and Uncordoning a Node",
|
||||
"category": "Cluster Management",
|
||||
"isolation_type": "ephemeral_cluster",
|
||||
"difficulty": "Easy",
|
||||
"type": "task",
|
||||
"weight": 4,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "node-label-selector",
|
||||
"title": "Node Labels and nodeSelector",
|
||||
"category": "Cluster Administration",
|
||||
"isolation_type": "ephemeral_cluster",
|
||||
"difficulty": "Easy",
|
||||
"type": "task",
|
||||
"weight": 5,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "node-taint-toleration",
|
||||
"title": "Taints and Tolerations",
|
||||
"category": "Cluster Administration",
|
||||
"isolation_type": "ephemeral_cluster",
|
||||
"difficulty": "Medium",
|
||||
"type": "task",
|
||||
"weight": 7,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "nodeport-task",
|
||||
"title": "Expose a Deployment via NodePort",
|
||||
"category": "Services & Networking",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Easy",
|
||||
"type": "task",
|
||||
"weight": 5,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "pod-affinity-mcq",
|
||||
"title": "Pod Affinity vs Anti-Affinity",
|
||||
"category": "Workloads & Scheduling",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Medium",
|
||||
"type": "mcq",
|
||||
"weight": 4,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "pod-basics-mcq",
|
||||
"title": "Pod Lifecycle States",
|
||||
"category": "Core Concepts",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Easy",
|
||||
"type": "mcq",
|
||||
"weight": 3,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "pod-disruption-budget-task",
|
||||
"title": "Configure a PodDisruptionBudget",
|
||||
"category": "Cluster Administration",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Medium",
|
||||
"type": "task",
|
||||
"weight": 6,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "pod-env-vars-inline",
|
||||
"title": "Pod with Inline Environment Variables",
|
||||
"category": "Configuration",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Easy",
|
||||
"type": "task",
|
||||
"weight": 4,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "pod-labeling-basics",
|
||||
"title": "Labelling Resources",
|
||||
"category": "Core Concepts",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Easy",
|
||||
"type": "task",
|
||||
"weight": 3,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "pod-node-assignment-mcq",
|
||||
"title": "Assigning Pods to Nodes",
|
||||
"category": "Scheduling",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Medium",
|
||||
"type": "mcq",
|
||||
"weight": 3,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "pod-security-context",
|
||||
"title": "Pod Security Context",
|
||||
"category": "Security",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Medium",
|
||||
"type": "task",
|
||||
"weight": 6,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "priority-class-task",
|
||||
"title": "Pod Priority and PriorityClass",
|
||||
"category": "Workloads & Scheduling",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Medium",
|
||||
"type": "task",
|
||||
"weight": 6,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "pv-pvc-mount",
|
||||
"title": "Persistent Storage with PV and PVC",
|
||||
"category": "Storage",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Medium",
|
||||
"type": "task",
|
||||
"weight": 7,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "pvc-dynamic-task",
|
||||
"title": "Dynamic PVC Provisioning",
|
||||
"category": "Storage",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Medium",
|
||||
"type": "task",
|
||||
"weight": 6,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "rbac-clusterrole",
|
||||
"title": "ClusterRole and ClusterRoleBinding",
|
||||
"category": "Cluster Administration",
|
||||
"isolation_type": "ephemeral_cluster",
|
||||
"difficulty": "Medium",
|
||||
"type": "task",
|
||||
"weight": 8,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "rbac-role",
|
||||
"title": "RBAC: Create Role and RoleBinding",
|
||||
"category": "Security",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Hard",
|
||||
"type": "task",
|
||||
"weight": 9,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "readiness-probe-task",
|
||||
"title": "Configure a Readiness Probe",
|
||||
"category": "Workloads & Scheduling",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Medium",
|
||||
"type": "task",
|
||||
"weight": 6,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "resource-limits-task",
|
||||
"title": "Resource Requests and Limits",
|
||||
"category": "Configuration",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Easy",
|
||||
"type": "task",
|
||||
"weight": 5,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "resource-quota-ns",
|
||||
"title": "ResourceQuota for a Namespace",
|
||||
"category": "Cluster Administration",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Medium",
|
||||
"type": "task",
|
||||
"weight": 7,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "restart-policy-mcq",
|
||||
"title": "Pod Restart Policies",
|
||||
"category": "Core Concepts",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Easy",
|
||||
"type": "mcq",
|
||||
"weight": 3,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "rolling-update-task",
|
||||
"title": "Perform a Rolling Update",
|
||||
"category": "Workloads",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Easy",
|
||||
"type": "task",
|
||||
"weight": 5,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "rootnode-enforce-limits",
|
||||
"title": "Stop the Next Outage: Enforce Resource Defaults",
|
||||
"category": "Observability & Ops",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Hard",
|
||||
"type": "task",
|
||||
"weight": 10,
|
||||
@@ -24,7 +25,9 @@
|
||||
}
|
||||
],
|
||||
"setup_commands": [
|
||||
{ "command": "kubectl create namespace workloads --dry-run=client -o yaml | kubectl apply -f -" }
|
||||
{
|
||||
"command": "kubectl create namespace workloads --dry-run=client -o yaml | kubectl apply -f -"
|
||||
}
|
||||
],
|
||||
"validation": {
|
||||
"description": "Checks that the LimitRange exists with the correct default values.",
|
||||
@@ -63,7 +66,11 @@
|
||||
},
|
||||
"default_namespace": "workloads",
|
||||
"teardown_commands": [
|
||||
{ "command": "kubectl delete limitrange resource-defaults -n workloads --ignore-not-found" },
|
||||
{ "command": "kubectl delete namespace workloads --ignore-not-found --wait=false" }
|
||||
{
|
||||
"command": "kubectl delete limitrange resource-defaults -n workloads --ignore-not-found"
|
||||
},
|
||||
{
|
||||
"command": "kubectl delete namespace workloads --ignore-not-found --wait=false"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "rootnode-probe-port-mismatch",
|
||||
"title": "Stuck Not-Ready: The Probe Port Mismatch",
|
||||
"category": "Observability & Ops",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Medium",
|
||||
"type": "task",
|
||||
"weight": 8,
|
||||
@@ -24,8 +25,12 @@
|
||||
}
|
||||
],
|
||||
"setup_commands": [
|
||||
{ "command": "kubectl create deployment api-gateway --image=nginx:1.25 --replicas=2" },
|
||||
{ "command": "kubectl patch deployment api-gateway --type='json' -p='[{\"op\":\"add\",\"path\":\"/spec/template/spec/containers/0/readinessProbe\",\"value\":{\"httpGet\":{\"path\":\"/\",\"port\":8080},\"initialDelaySeconds\":3,\"periodSeconds\":5}}]'" }
|
||||
{
|
||||
"command": "kubectl create deployment api-gateway --image=nginx:1.25 --replicas=2"
|
||||
},
|
||||
{
|
||||
"command": "kubectl patch deployment api-gateway --type='json' -p='[{\"op\":\"add\",\"path\":\"/spec/template/spec/containers/0/readinessProbe\",\"value\":{\"httpGet\":{\"path\":\"/\",\"port\":8080},\"initialDelaySeconds\":3,\"periodSeconds\":5}}]'"
|
||||
}
|
||||
],
|
||||
"validation": {
|
||||
"description": "Checks that the probe port is corrected and both replicas are Ready.",
|
||||
@@ -52,6 +57,8 @@
|
||||
},
|
||||
"default_namespace": "default",
|
||||
"teardown_commands": [
|
||||
{ "command": "kubectl delete deployment api-gateway --ignore-not-found" }
|
||||
{
|
||||
"command": "kubectl delete deployment api-gateway --ignore-not-found"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "rootnode-runaway-monitor",
|
||||
"title": "Recover the Monitoring Stack",
|
||||
"category": "Observability & Ops",
|
||||
"isolation_type": "ephemeral_cluster",
|
||||
"difficulty": "Medium",
|
||||
"type": "task",
|
||||
"weight": 8,
|
||||
@@ -24,9 +25,15 @@
|
||||
}
|
||||
],
|
||||
"setup_commands": [
|
||||
{ "command": "kubectl create namespace monitoring" },
|
||||
{ "command": "kubectl create deployment node-metrics --image=nginx:1.25 --replicas=1 -n monitoring" },
|
||||
{ "command": "kubectl set resources deployment node-metrics -n monitoring --requests=memory=64Gi" }
|
||||
{
|
||||
"command": "kubectl create namespace monitoring"
|
||||
},
|
||||
{
|
||||
"command": "kubectl create deployment node-metrics --image=nginx:1.25 --replicas=1 -n monitoring"
|
||||
},
|
||||
{
|
||||
"command": "kubectl set resources deployment node-metrics -n monitoring --requests=memory=64Gi"
|
||||
}
|
||||
],
|
||||
"validation": {
|
||||
"description": "Checks that node-metrics is right-sized: scheduled, 1/1 Ready, and still declaring a memory request.",
|
||||
@@ -53,6 +60,8 @@
|
||||
},
|
||||
"default_namespace": "monitoring",
|
||||
"teardown_commands": [
|
||||
{ "command": "kubectl delete namespace monitoring --ignore-not-found --wait=false" }
|
||||
{
|
||||
"command": "kubectl delete namespace monitoring --ignore-not-found --wait=false"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "scale-deployment",
|
||||
"title": "Scaling a Deployment",
|
||||
"category": "Workloads",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Easy",
|
||||
"type": "task",
|
||||
"weight": 4,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "secrets-basics",
|
||||
"title": "Creating and Using Secrets",
|
||||
"category": "Configuration",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Easy",
|
||||
"type": "task",
|
||||
"weight": 5,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "serviceaccount-pod",
|
||||
"title": "ServiceAccount for Pod API Access",
|
||||
"category": "Cluster Administration",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Medium",
|
||||
"type": "task",
|
||||
"weight": 7,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "services-mcq",
|
||||
"title": "Kubernetes Service Types",
|
||||
"category": "Networking",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Easy",
|
||||
"type": "mcq",
|
||||
"weight": 4,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "sort-by-basics",
|
||||
"title": "Sorting kubectl Output",
|
||||
"category": "Core Concepts",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Easy",
|
||||
"type": "task",
|
||||
"weight": 3,
|
||||
@@ -60,4 +61,4 @@
|
||||
"command": "rm -f /tmp/pods-sorted.txt /tmp/pods-by-name.txt"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "static-pods-mcq",
|
||||
"title": "Static Pods in Kubernetes",
|
||||
"category": "Core Concepts",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Medium",
|
||||
"type": "mcq",
|
||||
"weight": 3,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"id": "storageclass-mcq",
|
||||
"title": "StorageClass Reclaim Policies",
|
||||
"category": "Storage",
|
||||
"isolation_type": "shared_namespace",
|
||||
"difficulty": "Easy",
|
||||
"type": "mcq",
|
||||
"weight": 3,
|
||||
|
||||
Reference in New Issue
Block a user