App shop-demo con guasti
Un componente sano di riferimento e sei componenti, ciascuno rotto in modo diverso. La tabella è il “risultato atteso” contro cui valutare i tool AI.
| Componente | Guasto | Sintomo | Segnale principale |
|---|---|---|---|
catalog |
nessuno | Running, Ready | baseline |
frontend |
tag immagine inesistente | ImagePullBackOff | evento Failed to pull image |
api |
memory limit sotto il consumo | OOMKilled → CrashLoopBackOff | lastState.terminated.reason: OOMKilled |
worker |
ConfigMap mancante | CreateContainerConfigError | evento configmap "worker-config" not found |
checkout |
readiness probe su porta sbagliata | Running, 0/1 Ready | evento Readiness probe failed |
checkout-svc |
selector errato | Service senza endpoint | endpoints vuoti |
orders-db |
PVC su StorageClass inesistente | PVC e pod Pending | evento storageclass "fast-ssd" not found |
Manifest
Sezione intitolata “Manifest”mkdir -p ~/Downloads/K8S-AI/lab && cd ~/Downloads/K8S-AI/labcat > shop-demo.yaml <<'EOF2'apiVersion: v1kind: Namespacemetadata: name: shop-demo labels: purpose: ai-debug-lab---# baseline: healthyapiVersion: apps/v1kind: Deploymentmetadata: name: catalog namespace: shop-demospec: replicas: 1 selector: matchLabels: { app: catalog } template: metadata: labels: { app: catalog } spec: containers: - name: podinfo image: ghcr.io/stefanprodan/podinfo:6.7.1 ports: [{ containerPort: 9898, name: http }] readinessProbe: httpGet: { path: /readyz, port: http } resources: requests: { cpu: 10m, memory: 32Mi } limits: { memory: 64Mi }---apiVersion: v1kind: Servicemetadata: name: catalog namespace: shop-demospec: selector: { app: catalog } ports: [{ port: 80, targetPort: http }]---# fault 1: image tag does not existapiVersion: apps/v1kind: Deploymentmetadata: name: frontend namespace: shop-demospec: replicas: 1 selector: matchLabels: { app: frontend } template: metadata: labels: { app: frontend } spec: containers: - name: nginx image: nginx:1.27-doesnotexist resources: requests: { cpu: 10m, memory: 16Mi }---# fault 2: memory limit below real usage -> OOMKilledapiVersion: apps/v1kind: Deploymentmetadata: name: api namespace: shop-demospec: replicas: 1 selector: matchLabels: { app: api } template: metadata: labels: { app: api } spec: containers: - name: stress image: polinux/stress command: ["stress", "--vm", "1", "--vm-bytes", "200M", "--vm-hang", "1"] resources: requests: { cpu: 10m, memory: 32Mi } limits: { memory: 64Mi }---# fault 3: references a ConfigMap that does not existapiVersion: apps/v1kind: Deploymentmetadata: name: worker namespace: shop-demospec: replicas: 1 selector: matchLabels: { app: worker } template: metadata: labels: { app: worker } spec: containers: - name: worker image: busybox:1.36 command: ["sh", "-c", "echo queue=$QUEUE_URL; sleep 3600"] env: - name: QUEUE_URL valueFrom: configMapKeyRef: { name: worker-config, key: queue_url } resources: requests: { cpu: 5m, memory: 8Mi }---# fault 4: readiness probe on the wrong portapiVersion: apps/v1kind: Deploymentmetadata: name: checkout namespace: shop-demospec: replicas: 1 selector: matchLabels: { app: checkout } template: metadata: labels: { app: checkout } spec: containers: - name: podinfo image: ghcr.io/stefanprodan/podinfo:6.7.1 ports: [{ containerPort: 9898, name: http }] readinessProbe: httpGet: { path: /readyz, port: 8080 } periodSeconds: 5 resources: requests: { cpu: 10m, memory: 32Mi } limits: { memory: 64Mi }---# fault 5: selector does not match any podapiVersion: v1kind: Servicemetadata: name: checkout-svc namespace: shop-demospec: selector: { app: check-out } ports: [{ port: 80, targetPort: 9898 }]---# fault 6: PVC on a StorageClass that does not existapiVersion: v1kind: PersistentVolumeClaimmetadata: name: orders-db-data namespace: shop-demospec: accessModes: [ReadWriteOnce] storageClassName: fast-ssd resources: requests: { storage: 1Gi }---apiVersion: apps/v1kind: Deploymentmetadata: name: orders-db namespace: shop-demospec: replicas: 1 selector: matchLabels: { app: orders-db } template: metadata: labels: { app: orders-db } spec: containers: - name: redis image: redis:7 volumeMounts: [{ name: data, mountPath: /data }] resources: requests: { cpu: 10m, memory: 32Mi } volumes: - name: data persistentVolumeClaim: { claimName: orders-db-data }EOF2kubectl apply -f shop-demo.yamlVerifica dello stato rotto
Sezione intitolata “Verifica dello stato rotto”kubectl -n shop-demo get pods,svc,endpoints,pvckubectl -n shop-demo get events --sort-by=.lastTimestamp | tail -25kubectl -n shop-demo get pods -o custom-columns=NAME:.metadata.name,READY:.status.containerStatuses[0].ready,RESTARTS:.status.containerStatuses[0].restartCount,WAITING:.status.containerStatuses[0].state.waiting.reason,LAST:.status.containerStatuses[0].lastState.terminated.reasonAlert attesi
Sezione intitolata “Alert attesi”kube-prometheus-stack include già le regole che scattano su questi guasti, dopo la durata for: (5–15 minuti):
| Alert | Componenti |
|---|---|
KubePodCrashLooping |
api |
KubePodNotReady |
frontend, worker, checkout, orders-db |
KubeDeploymentReplicasMismatch |
tutti i deployment rotti |
KubeContainerWaiting |
frontend, worker |
curl -s localhost:9093/api/v2/alerts | jq -r '.[] | select(.labels.namespace=="shop-demo") | "\(.labels.alertname)\t\(.labels.pod // .labels.deployment)"'curl -s 'localhost:9090/api/v1/query' --data-urlencode 'query=ALERTS{namespace="shop-demo",alertstate="firing"}' | jq -r '.data.result[].metric | "\(.alertname) \(.pod // .deployment // "")"'