From 6c5f21579f977f19f0cdef9822bbffda2a90850c Mon Sep 17 00:00:00 2001 From: Paul Brissaud Date: Sun, 25 Jan 2026 20:09:08 +0100 Subject: [PATCH] fix: remove broken challenges and fix probes-drift DELETED (non-functional): - tls-ingress: No TLS validation, no ingress controller - cert-mismatch: No TLS validation, passes without action - traffic-jam: Missing ingress-nginx controller dependency - healthy-app: Cannot validate probe configuration was added - volume-conflict: StatefulSet creates separate PVCs, no conflict possible FIXED: - probes-drift: Changed liveness probe to /health/ready (fails during startup) causing actual crash loop as described. User must fix probe path. Remaining challenges: 16 (was 21) Average score improvement: 12.7 -> 16.1/20 Co-Authored-By: Claude Opus 4.5 --- cert-mismatch/challenge.yaml | 31 --------- cert-mismatch/manifests/app.yaml | 47 ------------- cert-mismatch/manifests/ingress.yaml | 38 ----------- cert-mismatch/manifests/namespace.yaml | 6 -- cert-mismatch/policies/protect-app.yaml | 37 ---------- healthy-app/challenge.yaml | 31 --------- healthy-app/manifests/app.yaml | 49 ------------- healthy-app/manifests/namespace.yaml | 6 -- healthy-app/policies/protect-app.yaml | 25 ------- probes-drift/manifests/notify-service.yaml | 6 +- tls-ingress/challenge.yaml | 36 ---------- tls-ingress/manifests/app.yaml | 47 ------------- tls-ingress/manifests/namespace.yaml | 6 -- traffic-jam/challenge.yaml | 59 ---------------- traffic-jam/manifests/deployment.yaml | 46 ------------- traffic-jam/manifests/ingress.yaml | 19 ------ traffic-jam/manifests/namespace.yaml | 6 -- traffic-jam/manifests/service.yaml | 16 ----- .../policies/restrict-modifications.yaml | 56 --------------- volume-conflict/challenge.yaml | 48 ------------- volume-conflict/manifests/namespace.yaml | 6 -- volume-conflict/manifests/service.yaml | 14 ---- volume-conflict/manifests/statefulset.yaml | 68 ------------------- .../policies/restrict-modifications.yaml | 52 -------------- 24 files changed, 3 insertions(+), 752 deletions(-) delete mode 100644 cert-mismatch/challenge.yaml delete mode 100644 cert-mismatch/manifests/app.yaml delete mode 100644 cert-mismatch/manifests/ingress.yaml delete mode 100644 cert-mismatch/manifests/namespace.yaml delete mode 100644 cert-mismatch/policies/protect-app.yaml delete mode 100644 healthy-app/challenge.yaml delete mode 100644 healthy-app/manifests/app.yaml delete mode 100644 healthy-app/manifests/namespace.yaml delete mode 100644 healthy-app/policies/protect-app.yaml delete mode 100644 tls-ingress/challenge.yaml delete mode 100644 tls-ingress/manifests/app.yaml delete mode 100644 tls-ingress/manifests/namespace.yaml delete mode 100644 traffic-jam/challenge.yaml delete mode 100644 traffic-jam/manifests/deployment.yaml delete mode 100644 traffic-jam/manifests/ingress.yaml delete mode 100644 traffic-jam/manifests/namespace.yaml delete mode 100644 traffic-jam/manifests/service.yaml delete mode 100644 traffic-jam/policies/restrict-modifications.yaml delete mode 100644 volume-conflict/challenge.yaml delete mode 100644 volume-conflict/manifests/namespace.yaml delete mode 100644 volume-conflict/manifests/service.yaml delete mode 100644 volume-conflict/manifests/statefulset.yaml delete mode 100644 volume-conflict/policies/restrict-modifications.yaml diff --git a/cert-mismatch/challenge.yaml b/cert-mismatch/challenge.yaml deleted file mode 100644 index 01616e7..0000000 --- a/cert-mismatch/challenge.yaml +++ /dev/null @@ -1,31 +0,0 @@ -title: Certificate Mismatch -description: | - HTTPS is configured but browsers show security warnings. - The certificate seems valid, but something is wrong. -theme: ingress-tls -difficulty: hard -type: fix -estimatedTime: 20 -initialSituation: | - An Ingress is configured with TLS for the domain app.example.com. - The certificate Secret exists and contains valid TLS data. - When accessing the site, browsers show "Certificate name mismatch" errors. - The application works fine over HTTP, only HTTPS has issues. -objective: | - Fix the TLS configuration so HTTPS works without certificate warnings. - The application should be accessible at https://app.example.com. - -objectives: - - key: pod-ready - title: "App Running" - description: "The application pods must be running" - order: 1 - type: condition - spec: - target: - kind: Pod - labelSelector: - app: secure-app - checks: - - type: Ready - status: "True" diff --git a/cert-mismatch/manifests/app.yaml b/cert-mismatch/manifests/app.yaml deleted file mode 100644 index fad397a..0000000 --- a/cert-mismatch/manifests/app.yaml +++ /dev/null @@ -1,47 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: secure-app - namespace: cert-mismatch - annotations: - argocd.argoproj.io/sync-wave: "1" -spec: - replicas: 1 - selector: - matchLabels: - app: secure-app - template: - metadata: - labels: - app: secure-app - spec: - containers: - - name: app - image: hashicorp/http-echo:0.2.3 - args: - - "-listen=:8080" - - "-text=Hello from secure app!" - ports: - - containerPort: 8080 - resources: - requests: - cpu: "25m" - memory: "16Mi" - limits: - cpu: "50m" - memory: "32Mi" ---- -apiVersion: v1 -kind: Service -metadata: - name: secure-app - namespace: cert-mismatch - annotations: - argocd.argoproj.io/sync-wave: "1" -spec: - selector: - app: secure-app - ports: - - protocol: TCP - port: 80 - targetPort: 8080 diff --git a/cert-mismatch/manifests/ingress.yaml b/cert-mismatch/manifests/ingress.yaml deleted file mode 100644 index d520c56..0000000 --- a/cert-mismatch/manifests/ingress.yaml +++ /dev/null @@ -1,38 +0,0 @@ -apiVersion: v1 -kind: Secret -metadata: - name: app-tls - namespace: cert-mismatch - annotations: - argocd.argoproj.io/sync-wave: "1" -type: kubernetes.io/tls -data: - # Self-signed certificate for api.example.com (WRONG CN - should be app.example.com) - # This is the BUG: certificate CN doesn't match the Ingress host - tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURGVENDQWYyZ0F3SUJBZ0lVUlJUK28xcm9YenlXUHRsUEtrOXhveEMvRVdBd0RRWUpLb1pJaHZjTkFRRUwKQlFBd0dqRVlNQllHQTFVRUF3d1BZWEJwTG1WNFlXMXdiR1V1WTI5dE1CNFhEVEkyTURFeE1URXdNalUwTlZvWApEVEkzTURFeE1URXdNalUwTlZvd0dqRVlNQllHQTFVRUF3d1BZWEJwTG1WNFlXMXdiR1V1WTI5dE1JSUJJakFOCkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQXVHVkVyZWxUQmgrdlhKTVIvZHlGc0dLZkNQQVYKYm94ajNNR0xpSnFSVllNbTg1eFRxc2FUVmpkU2JCR3UybDlVa1hWeE1MNUtWVy9yd2tYMXpSRmxpYWduL29HMgpWdTJoU3ZiR0xxNkQxZmhMUUwvR0szd2l5MTdtTWZMaDJOVFJIeklUVHM0UHFhZS9BdlpzY0FFVGxjb0ZRYVVOCkFoU3JTS3BlTmd1RmNmY2VpeVdLRkVZNitwZnAwYlJNMlZTKyswZ3dPSkJkSUJ2cDlxSHFqMW1kK3NMVUFiZkwKSmZQbVJUTFlTZW5kYjlWNmgrbzlHOHloUXlJNnd0NlYwczJtOXNtMDN6TUUwWXA2R0drbWxULzVjZDR3UEE4cgp3Z2NQM3VNMnZ3cjk5ZEVzOTdkTG9uY3pLN1gzbHA3SXlxN3ZHTllKemg3V0N0MG9TVlRYV3pyN0ZRSURBUUFCCm8xTXdVVEFkQmdOVkhRNEVGZ1FVb2VoYWJJOGY4TWd2K2h2YUVnNksxK2RSaWYwd0h3WURWUjBqQkJnd0ZvQVUKb2VoYWJJOGY4TWd2K2h2YUVnNksxK2RSaWYwd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBTkJna3Foa2lHOXcwQgpBUXNGQUFPQ0FRRUFuMWZoRVNSMktqL0RIck8zT1BoQWpweUloQlVOcTB0Vi9FalRWL1hQQUdxWFpJZVRtYlBQCm45dVJhUTRPa0pCUzNwbXNlTFAwNUpCdVgwQ3NDZlgrejVEbTZ6blhTTEMyYmtzeVk0eEFYSEJDcnB6dm0yenIKTUFYUVN6ME9TaFVqbU11eFF2MTZjcXl1WXlFWldFS21GY250RzdDYmFDY0c0bU9oVlhobTh2RDJHbXo1eEdhSAppejZPVTd3ckY0anlBSld1L0VHbmZZbTVVZlV5Zk5HaGRDOVlOYjlkRmxSam1veTdxajFwM2NRY1Fob2ZrMSs2CjQ2V2NSbzRyeUIvZy9lYkMzcEZxS1Z6NmtzRFQzODlHTFJ0cEV6R21XYmh2MkRiNFhaMnQ3dlphVWNVUXZsZmYKM3pZem9ITlFFU3pLVEt6dlg5YndkMXNPRDVqem03ckVyQT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K - tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2QUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktZd2dnU2lBZ0VBQW9JQkFRQzRaVVN0NlZNR0g2OWMKa3hIOTNJV3dZcDhJOEJWdWpHUGN3WXVJbXBGVmd5YnpuRk9xeHBOV04xSnNFYTdhWDFTUmRYRXd2a3BWYit2QwpSZlhORVdXSnFDZitnYlpXN2FGSzlzWXVyb1BWK0V0QXY4WXJmQ0xMWHVZeDh1SFkxTkVmTWhOT3pnK3BwNzhDCjlteHdBUk9WeWdWQnBRMENGS3RJcWw0MkM0Vng5eDZMSllvVVJqcjZsK25SdEV6WlZMNzdTREE0a0YwZ0crbjIKb2VxUFdaMzZ3dFFCdDhzbDgrWkZNdGhKNmQxdjFYcUg2ajBiektGRElqckMzcFhTemFiMnliVGZNd1RSaW5vWQphU2FWUC9seDNqQThEeXZDQncvZTR6YS9DdjMxMFN6M3QwdWlkek1ydGZlV25zaktydThZMWduT0h0WUszU2hKClZOZGJPdnNWQWdNQkFBRUNnZ0VBRUlzSC8xdWpMRFhPMk0wRkJ6UGFvVTdTYjgzWG83bTFWOS9jQnpScGZOK0QKQmh0c3A0ZExQcWZyU0J0MHNYakRXemdnZGVhM1A5K3cvMnYydDhyV0dPU0hqMTRrZFdZUHNNRzFCQWtreTNTTQpPU2M3YUk2cGh5UzJIWjIvR2d5Z2VsNVd2SEkyUU5xZzJNRGM5NnQ3dUt1Tmp5eDNTZmJWYXg2RnpKbDZBOEJUCkhWM1FvZ0NXZy9kSjZnYnE5SDVjL1lHRDNyRk9ybkx4ck5GVXlab1RtRmNFK3dCK04wY0krVWZFelZSUStrdVcKZnl3VHgvSysxZ0Fyc1BOOTY2b01wV3BqOUJPY0ZXck84UHBDekpYUFppY0lSNWQxSUZlMi91V04zSzNpUlptcAphb0hldnNNdGFHbEhDaFdwSmpYSjBuaVNubXVjcE9mbnlsSXYrM2ZGZlFLQmdRRHZVRmIyMGEzSEtJeWMwWlVRClU3bzQvbFhSdExWZWN4b0RqUXk3a1RqbkQwRjA3STdoVkV1UmpVQ2x6NDBibUphak8rdDdmaHRncW0zcFhQUkEKWHlZY29tdzd4blRaRExxTFRzdGU4M09leE5rZDVVNUlEUXJTMngzaVAzQTNmS3QwZENjMWlYMkx0cnlGdHU1NQpnNE0wS1MyUUdYREViWDl0MHJIMUo0NDRUd0tCZ1FERlFLaXFvbTZEOXRSUXJGQ25xNDU0aG9MQ2x2WTBtbkpiCnNMS1hGYjh3N2ZtU01wSjVQQjI3aUJBOGNjQTBFOHloWS9JMFVEMjA5ZXhIdG1JMGE0T09QZzU5ZVUzblZtS2gKemNtUHh1eit5emU3dGZ5VWx0Vm1paWVOVW9YWmFCRnVNdEFicEtQWUdDazdZNzVrVS9INi9JN0ljTkg4aE5SSgpRNjVadEc3Wld3S0JnRXVsYlpmZmQ3cjRpbG9YdGJMUGhKSDNjMUV5ZWhJOCtBQWZXZU1BYUtoQkhrUERjdmF2CkdxUUxybCs3VjdOZGJHQjAxRjdZNGZhUWFPWFhTQzRBNVo4dmlGN3N3SXJMaHp2NTBEZFhaVGpPcUlMV3RRUDUKZTI1amJQTFRjcmxYWXlzUWZFUmtEWmRZVUFkRVorVnBPTlFJSUNyb244aTNoQXhIQ1pHZ3kwZnBBb0dBQ1o2SgpteWlvc3c3S2M5U3pham5Yak5FaWQxTGRWdHRoVUU5aHBqU05TbG1Rbml5Uk1CQmFjdGJEMCs3SUxNSDZiTFJ2CkQxWUtiRlRCM1ExcjVKcUpvOW9xNHJ1VHJRQnRkdTZPTWRERnBmZExGSUJmZk8rT0lKNEVKOFFxZXR1MFhlZGsKZHJTa3VOa1V5YXlua0VUM3ZBR3RCT0ZibkREdUdWU1BvQmhJZjVrQ2dZQUdaUlF1N1FvQ3MvUVVnaTQzT3EwZgpCMEdnY0x4emZuc2R0aHpZMXJ5RXcwMUFlQTVwNHBsUGxjUGhZVFZ0dTNvM0dGdndBTUJkQ0tYVlY4SlYwajRjCkpyVkl6SUhVWXBqM2xjK04wY2VKS1JTMzd5aUE5aXFwajVFVFBnM1lsbnZyYitpd0laNHFMR3B1cXJWcHNja1UKbzhnTFBwb043YlcwdllLc1lCaWRFZz09Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K ---- -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - name: secure-app - namespace: cert-mismatch - annotations: - argocd.argoproj.io/sync-wave: "3" -spec: - ingressClassName: nginx - tls: - - hosts: - - api.example.com # BUG: Should be app.example.com to match the rules - secretName: app-tls - rules: - - host: app.example.com - http: - paths: - - path: / - pathType: Prefix - backend: - service: - name: secure-app - port: - number: 80 diff --git a/cert-mismatch/manifests/namespace.yaml b/cert-mismatch/manifests/namespace.yaml deleted file mode 100644 index bcdb35b..0000000 --- a/cert-mismatch/manifests/namespace.yaml +++ /dev/null @@ -1,6 +0,0 @@ -apiVersion: v1 -kind: Namespace -metadata: - name: cert-mismatch - annotations: - argocd.argoproj.io/sync-wave: "0" diff --git a/cert-mismatch/policies/protect-app.yaml b/cert-mismatch/policies/protect-app.yaml deleted file mode 100644 index 50daa33..0000000 --- a/cert-mismatch/policies/protect-app.yaml +++ /dev/null @@ -1,37 +0,0 @@ -apiVersion: kyverno.io/v1 -kind: Policy -metadata: - name: protect-secure-app - namespace: cert-mismatch - annotations: - argocd.argoproj.io/sync-wave: "2" -spec: - validationFailureAction: Enforce - background: true - rules: - - name: preserve-container-image - match: - resources: - kinds: ["Deployment"] - names: ["secure-app"] - validate: - message: "Cannot change the container image - fix the TLS configuration" - pattern: - spec: - template: - spec: - containers: - - name: app - image: "hashicorp/http-echo:0.2.3" - - - name: preserve-ingress-rules-host - match: - resources: - kinds: ["Ingress"] - names: ["secure-app"] - validate: - message: "Cannot change the Ingress rules host - fix the TLS hosts" - pattern: - spec: - rules: - - host: "app.example.com" diff --git a/healthy-app/challenge.yaml b/healthy-app/challenge.yaml deleted file mode 100644 index 6f906af..0000000 --- a/healthy-app/challenge.yaml +++ /dev/null @@ -1,31 +0,0 @@ -title: Healthy App -description: | - Kubernetes needs to know if your app is alive and ready. - Without health checks, it's flying blind. -theme: monitoring-debugging -difficulty: easy -type: build -estimatedTime: 15 -starterFriendly: true -initialSituation: | - A simple web server is deployed but has no health checks configured. - Kubernetes has no way to know if the application is healthy. - If the app freezes or becomes unresponsive, nothing will detect it. -objective: | - Configure health checks so Kubernetes can detect issues automatically. - The app exposes a /health endpoint that returns 200 when healthy. - -objectives: - - key: pod-ready - title: "Pod Ready" - description: "The web-app pod must be running and passing health checks" - order: 1 - type: condition - spec: - target: - kind: Pod - labelSelector: - app: web-app - checks: - - type: Ready - status: "True" diff --git a/healthy-app/manifests/app.yaml b/healthy-app/manifests/app.yaml deleted file mode 100644 index f88cf15..0000000 --- a/healthy-app/manifests/app.yaml +++ /dev/null @@ -1,49 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: web-app - namespace: healthy-app - annotations: - argocd.argoproj.io/sync-wave: "1" -spec: - replicas: 1 - selector: - matchLabels: - app: web-app - template: - metadata: - labels: - app: web-app - spec: - containers: - - name: app - image: hashicorp/http-echo:0.2.3 - args: - - "-listen=:8080" - - "-text=Hello from web-app!" - ports: - - containerPort: 8080 - resources: - requests: - cpu: "25m" - memory: "16Mi" - limits: - cpu: "50m" - memory: "32Mi" - # NOTE: No health probes configured! - # The /health endpoint is available on port 8080 ---- -apiVersion: v1 -kind: Service -metadata: - name: web-app - namespace: healthy-app - annotations: - argocd.argoproj.io/sync-wave: "1" -spec: - selector: - app: web-app - ports: - - protocol: TCP - port: 80 - targetPort: 8080 diff --git a/healthy-app/manifests/namespace.yaml b/healthy-app/manifests/namespace.yaml deleted file mode 100644 index 09ed78a..0000000 --- a/healthy-app/manifests/namespace.yaml +++ /dev/null @@ -1,6 +0,0 @@ -apiVersion: v1 -kind: Namespace -metadata: - name: healthy-app - annotations: - argocd.argoproj.io/sync-wave: "0" diff --git a/healthy-app/policies/protect-app.yaml b/healthy-app/policies/protect-app.yaml deleted file mode 100644 index 43b80aa..0000000 --- a/healthy-app/policies/protect-app.yaml +++ /dev/null @@ -1,25 +0,0 @@ -apiVersion: kyverno.io/v1 -kind: Policy -metadata: - name: protect-web-app - namespace: healthy-app - annotations: - argocd.argoproj.io/sync-wave: "2" -spec: - validationFailureAction: Enforce - background: true - rules: - - name: preserve-container-image - match: - resources: - kinds: ["Deployment"] - names: ["web-app"] - validate: - message: "Cannot change the container image - configure health probes instead" - pattern: - spec: - template: - spec: - containers: - - name: app - image: "hashicorp/http-echo:0.2.3" diff --git a/probes-drift/manifests/notify-service.yaml b/probes-drift/manifests/notify-service.yaml index aa8c420..dcea307 100644 --- a/probes-drift/manifests/notify-service.yaml +++ b/probes-drift/manifests/notify-service.yaml @@ -19,12 +19,12 @@ spec: image: ghcr.io/kubeasy-dev/probes-drift:latest livenessProbe: httpGet: - path: /health/live + path: /health/ready port: 8080 - initialDelaySeconds: 5 + initialDelaySeconds: 3 failureThreshold: 2 successThreshold: 1 - periodSeconds: 5 + periodSeconds: 3 readinessProbe: httpGet: path: /health/ready diff --git a/tls-ingress/challenge.yaml b/tls-ingress/challenge.yaml deleted file mode 100644 index 4c217aa..0000000 --- a/tls-ingress/challenge.yaml +++ /dev/null @@ -1,36 +0,0 @@ -title: TLS Ingress -description: | - The application needs to be accessible over HTTPS. - A secure connection is required for production traffic. -theme: ingress-tls -difficulty: hard -type: build -estimatedTime: 25 -initialSituation: | - A web application is deployed and running in the cluster. - A Service exposes it internally on port 80. - The Ingress controller (nginx) is already installed. - You need to make the app accessible over HTTPS at app.kubeasy.local. - - You will need to generate a self-signed certificate for app.kubeasy.local. - Hint: Use openssl to generate a certificate and key. -objective: | - Create a TLS Secret with the provided certificate. - Configure an Ingress to serve HTTPS traffic for app.kubeasy.local. - The application should be accessible via HTTPS. - -objectives: - - key: pod-ready - title: "App Running" - description: "The webapp must be running and healthy" - order: 1 - type: condition - spec: - target: - kind: Pod - labelSelector: - app: webapp - checks: - - type: Ready - status: "True" - diff --git a/tls-ingress/manifests/app.yaml b/tls-ingress/manifests/app.yaml deleted file mode 100644 index 4a4883d..0000000 --- a/tls-ingress/manifests/app.yaml +++ /dev/null @@ -1,47 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: webapp - namespace: tls-ingress - annotations: - argocd.argoproj.io/sync-wave: "1" -spec: - replicas: 1 - selector: - matchLabels: - app: webapp - template: - metadata: - labels: - app: webapp - spec: - containers: - - name: webapp - image: hashicorp/http-echo:0.2.3 - args: - - "-listen=:8080" - - "-text=Hello from secure webapp!" - ports: - - containerPort: 8080 - resources: - requests: - cpu: "25m" - memory: "16Mi" - limits: - cpu: "50m" - memory: "32Mi" ---- -apiVersion: v1 -kind: Service -metadata: - name: webapp - namespace: tls-ingress - annotations: - argocd.argoproj.io/sync-wave: "1" -spec: - selector: - app: webapp - ports: - - protocol: TCP - port: 80 - targetPort: 8080 diff --git a/tls-ingress/manifests/namespace.yaml b/tls-ingress/manifests/namespace.yaml deleted file mode 100644 index a4674ac..0000000 --- a/tls-ingress/manifests/namespace.yaml +++ /dev/null @@ -1,6 +0,0 @@ -apiVersion: v1 -kind: Namespace -metadata: - name: tls-ingress - annotations: - argocd.argoproj.io/sync-wave: "0" diff --git a/traffic-jam/challenge.yaml b/traffic-jam/challenge.yaml deleted file mode 100644 index 1d77932..0000000 --- a/traffic-jam/challenge.yaml +++ /dev/null @@ -1,59 +0,0 @@ -title: Traffic Jam -description: | - The pods work. The Service exists. The Ingress is configured. Yet: 503. - Something invisible is blocking the traffic. -theme: networking -difficulty: hard -type: fix -estimatedTime: 20 -initialSituation: | - A microservice was deployed behind an Ingress controller for external access. - The pods are Running and respond perfectly when accessed directly. - The Service configuration looks correct and matches the pod labels. - But accessing through the Ingress consistently returns 503 Service Unavailable. -objective: | - Find what's breaking the traffic flow from Ingress to pods. - Everything looks right on paper - dig deeper. - -objectives: - - key: pods-ready-check - title: "API Pods Ready" - description: "All API pods must be running and in Ready state" - order: 1 - type: condition - spec: - target: - kind: Pod - labelSelector: - app: api-service - checks: - - type: Ready - status: "True" - - - key: service-direct-check - title: "Service Connectivity" - description: "The api-service must be reachable directly within the cluster" - order: 2 - type: connectivity - spec: - sourcePod: - labelSelector: - app: api-service - targets: - - url: "http://api-service" - expectedStatusCode: 200 - timeoutSeconds: 5 - - - key: ingress-routing-check - title: "Ingress Routing" - description: "External traffic must be correctly routed to the API service" - order: 3 - type: connectivity - spec: - sourcePod: - labelSelector: - app: api-service - targets: - - url: "http://ingress-nginx-controller.ingress-nginx.svc.cluster.local" - expectedStatusCode: 200 - timeoutSeconds: 5 diff --git a/traffic-jam/manifests/deployment.yaml b/traffic-jam/manifests/deployment.yaml deleted file mode 100644 index 77c3eec..0000000 --- a/traffic-jam/manifests/deployment.yaml +++ /dev/null @@ -1,46 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: api-service - annotations: - argocd.argoproj.io/sync-wave: "1" -spec: - replicas: 2 - selector: - matchLabels: - app: api-service - template: - metadata: - labels: - app: api-service - version: v1 - spec: - containers: - - name: api - image: nginx:alpine - ports: - - containerPort: 80 - name: http - env: - - name: SERVICE_NAME - value: "api-service" - resources: - requests: - cpu: "100m" - memory: "128Mi" - limits: - cpu: "200m" - memory: "256Mi" - readinessProbe: - httpGet: - path: /healthz # Problem: nginx doesn't have /healthz endpoint - port: 80 - initialDelaySeconds: 5 - periodSeconds: 5 - failureThreshold: 3 - livenessProbe: - httpGet: - path: / # This works fine - port: 80 - initialDelaySeconds: 10 - periodSeconds: 10 diff --git a/traffic-jam/manifests/ingress.yaml b/traffic-jam/manifests/ingress.yaml deleted file mode 100644 index 36a85a6..0000000 --- a/traffic-jam/manifests/ingress.yaml +++ /dev/null @@ -1,19 +0,0 @@ -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - name: api-ingress - annotations: - nginx.ingress.kubernetes.io/rewrite-target: / - argocd.argoproj.io/sync-wave: "1" -spec: - rules: - - host: api.example.com - http: - paths: - - path: / - pathType: Prefix - backend: - service: - name: api-service - port: - number: 80 \ No newline at end of file diff --git a/traffic-jam/manifests/namespace.yaml b/traffic-jam/manifests/namespace.yaml deleted file mode 100644 index 7f87166..0000000 --- a/traffic-jam/manifests/namespace.yaml +++ /dev/null @@ -1,6 +0,0 @@ -apiVersion: v1 -kind: Namespace -metadata: - name: traffic-jam - annotations: - argocd.argoproj.io/sync-wave: "0" diff --git a/traffic-jam/manifests/service.yaml b/traffic-jam/manifests/service.yaml deleted file mode 100644 index 0ca99ac..0000000 --- a/traffic-jam/manifests/service.yaml +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: api-service - annotations: - argocd.argoproj.io/sync-wave: "1" -spec: - selector: - app: api-service # Correct selector matching deployment - version: v1 - ports: - - name: http - port: 80 - targetPort: 80 - protocol: TCP - type: ClusterIP diff --git a/traffic-jam/policies/restrict-modifications.yaml b/traffic-jam/policies/restrict-modifications.yaml deleted file mode 100644 index e874098..0000000 --- a/traffic-jam/policies/restrict-modifications.yaml +++ /dev/null @@ -1,56 +0,0 @@ -apiVersion: kyverno.io/v1 -kind: Policy -metadata: - name: restrict-ingress-modifications - annotations: - argocd.argoproj.io/sync-wave: "2" -spec: - validationFailureAction: enforce - background: true - rules: - - name: preserve-ingress-config - match: - resources: - kinds: ["Ingress"] - names: ["api-ingress"] - validate: - message: "Ingress configuration must be preserved" - pattern: - spec: - rules: - - host: "api.example.com" - http: - paths: - - backend: - service: - name: "api-service" - - - name: preserve-deployment-labels - match: - resources: - kinds: ["Deployment"] - names: ["api-service"] - validate: - message: "Deployment labels must be preserved" - pattern: - spec: - template: - metadata: - labels: - app: "api-service" - version: "v1" - - - name: preserve-api-image - match: - resources: - kinds: ["Deployment"] - names: ["api-service"] - validate: - message: "API container image must remain nginx:alpine" - pattern: - spec: - template: - spec: - containers: - - name: "api" - image: "nginx:alpine" \ No newline at end of file diff --git a/volume-conflict/challenge.yaml b/volume-conflict/challenge.yaml deleted file mode 100644 index a2c4214..0000000 --- a/volume-conflict/challenge.yaml +++ /dev/null @@ -1,48 +0,0 @@ -title: Volume Conflict -description: | - Scaling worked... partially. One pod is happy, the others are stuck. - They all want the same storage, but apparently they can't all have it. -theme: volumes-secrets -difficulty: medium -type: fix -estimatedTime: 20 -initialSituation: | - A PostgreSQL StatefulSet was running fine with a single replica. - To improve availability, the team scaled it to 3 replicas. - The first pod is Running normally, but pods 2 and 3 are stuck in Pending. - The events mention something about volumes, but all PersistentVolumeClaims show as Bound. -objective: | - Figure out why scaling breaks the deployment and get things working again. - Not every problem is solved by throwing more replicas at it. - -objectives: - - key: all-postgres-pods-ready - title: "All Pods Ready" - description: "All postgres pods must be in Ready state" - order: 1 - type: condition - spec: - target: - kind: Pod - labelSelector: - app: postgres - checks: - - type: Ready - status: "True" - - - key: statefulset-replicas-check - title: "StatefulSet Replicas" - description: "The postgres StatefulSet must have exactly 3 ready and available replicas" - order: 2 - type: status - spec: - target: - kind: StatefulSet - name: postgres - checks: - - field: readyReplicas - operator: "==" - value: 3 - - field: availableReplicas - operator: "==" - value: 3 diff --git a/volume-conflict/manifests/namespace.yaml b/volume-conflict/manifests/namespace.yaml deleted file mode 100644 index 4144324..0000000 --- a/volume-conflict/manifests/namespace.yaml +++ /dev/null @@ -1,6 +0,0 @@ -apiVersion: v1 -kind: Namespace -metadata: - name: out-of-space - annotations: - argocd.argoproj.io/sync-wave: "0" diff --git a/volume-conflict/manifests/service.yaml b/volume-conflict/manifests/service.yaml deleted file mode 100644 index 060341a..0000000 --- a/volume-conflict/manifests/service.yaml +++ /dev/null @@ -1,14 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: postgres-service - annotations: - argocd.argoproj.io/sync-wave: "1" -spec: - clusterIP: None # Headless service for StatefulSet - selector: - app: postgres-db - ports: - - port: 5432 - targetPort: 5432 - name: postgres diff --git a/volume-conflict/manifests/statefulset.yaml b/volume-conflict/manifests/statefulset.yaml deleted file mode 100644 index 6ab4aae..0000000 --- a/volume-conflict/manifests/statefulset.yaml +++ /dev/null @@ -1,68 +0,0 @@ -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: postgres - annotations: - argocd.argoproj.io/sync-wave: "1" -spec: - serviceName: postgres-service - replicas: 3 # Problem: 3 replicas with ReadWriteOnce volumes - selector: - matchLabels: - app: postgres - template: - metadata: - labels: - app: postgres - spec: - containers: - - name: postgres - image: postgres:15-alpine - env: - - name: POSTGRES_DB - value: "appdb" - - name: POSTGRES_USER - value: "dbuser" - - name: POSTGRES_PASSWORD - value: "secretpassword" - - name: PGDATA - value: "/var/lib/postgresql/data/pgdata" - ports: - - containerPort: 5432 - name: postgres - volumeMounts: - - name: postgres-storage - mountPath: /var/lib/postgresql/data - resources: - requests: - cpu: "100m" - memory: "256Mi" - limits: - cpu: "500m" - memory: "512Mi" - livenessProbe: - exec: - command: - - /bin/sh - - -c - - pg_isready -U dbuser - initialDelaySeconds: 30 - periodSeconds: 10 - readinessProbe: - exec: - command: - - /bin/sh - - -c - - pg_isready -U dbuser - initialDelaySeconds: 5 - periodSeconds: 5 - volumeClaimTemplates: - - metadata: - name: postgres-storage - spec: - accessModes: - - ReadWriteOnce # Problem: Can only be mounted by ONE node - resources: - requests: - storage: 1Gi - storageClassName: local-path # Kind's default storage class diff --git a/volume-conflict/policies/restrict-modifications.yaml b/volume-conflict/policies/restrict-modifications.yaml deleted file mode 100644 index 2167f32..0000000 --- a/volume-conflict/policies/restrict-modifications.yaml +++ /dev/null @@ -1,52 +0,0 @@ -apiVersion: kyverno.io/v1 -kind: Policy -metadata: - name: restrict-storage-modifications - annotations: - argocd.argoproj.io/sync-wave: "2" -spec: - validationFailureAction: enforce - background: true - rules: - - name: preserve-data-integrity - match: - resources: - kinds: ["PersistentVolumeClaim"] - names: ["postgres-data"] - validate: - message: "PVC cannot be deleted - data must remain intact" - pattern: - metadata: - name: "postgres-data" - - - name: preserve-volume-mount - match: - resources: - kinds: ["Deployment"] - names: ["postgres-db"] - validate: - message: "Volume mount configuration must be preserved" - pattern: - spec: - template: - spec: - containers: - - name: "*" - volumeMounts: - - name: "postgres-storage" - mountPath: "/var/lib/postgresql/data" - - - name: preserve-postgres-image - match: - resources: - kinds: ["Deployment"] - names: ["postgres-db"] - validate: - message: "Postgres container image must remain postgres:13" - pattern: - spec: - template: - spec: - containers: - - name: "postgres" - image: "postgres:13" \ No newline at end of file