Zum Inhalt

Manifeste Debugging

Ziel

In diesem Projekt geht es darum, fehlerhafte Kubernetes-Manifeste zu debuggen und zu reparieren. Sie werden:

  • mehrere defekte Szenarien Schritt für Schritt analysieren und beheben
  • die betroffenen Ressourcen so reparieren, dass die Anwendung wieder lauffähig ist

Hilfsmittel

  • Versuchen Sie, die unten stehenden Aufgaben mit Hilfe der Folien und des Cheatsheets eigenständig zu lösen.
  • Sollten Sie dabei Probleme haben, finden Sie bei jeder Aufgabe einen ausklappbaren Block, in dem der Lösungsweg beschrieben wird.

Aufgabe - Szenario 1

  • Wechseln Sie in den Ordner debugging-manifests/scenario-1. In diesem Szenario liegen fehlerhafte Kubernetes-Manifeste für eine kleine Web-Frontend-Anwendung vor. Untersuchen Sie das Deployment und finden Sie den Grund dafür, dass der Pod nicht sauber startet.

Reparieren Sie das Manifest so, dass der Web-Frontend-Pod anschließend korrekt startet.

Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)

Im Deployment ist ein ungültiger Image-Tag hinterlegt. Ändern Sie in deployment.yaml das Image von nginx:this-tag-does-not-exist zu einem gültigen Nginx-Tag, zum Beispiel nginx:1.27.

Aufgabe - Szenario 2

  • Wechseln Sie in den Ordner debugging-manifests/scenario-2. Hier finden Sie ein Deployment für einen Training-Webserver mit einer dazugehörigen Konfiguration. Der Pod startet, gerät aber sofort in einen CrashLoopBackOff-Status.

Untersuchen Sie die Logs des Pods und finden Sie den Grund für den Fehler. Reparieren Sie das Manifest so, dass der Webserver-Pod korrekt läuft.

Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)

Der Pod kann nicht starten, weil der angegebene Pfad zum Script nicht korrekt ist. In app.yaml wird das Script unter /app/start-server.sh aufgerufen, die ConfigMap wird aber unter /opt/training gemountet.

Fehler: Das Script existiert bei diesem Pfad nicht.

Lösung: Ändern Sie in der args des Containers den Pfad von /app/start-server.sh zu /opt/training/start-server.sh. Alternativ können Sie auch das Volume mountPath auf /app ändern, wenn Sie das Script dort haben möchten.

Aufgabe - Szenario 3

  • Wechseln Sie in den Ordner debugging-manifests/scenario-3. Hier finden Sie ein Deployment für eine Product API mit dazugehörigen ConfigMaps und Service. Der Pod startet ebenfalls nicht korrekt.

Untersuchen Sie die Manifeste und finden Sie den Fehler. Der Pod oder die Initialisierung gibt Ihnen Hinweise auf das Problem. Reparieren Sie die Manifeste.

Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)

Das Problem liegt bei den fehlenden Umgebungsvariablen in der ConfigMap. Im Deployment app.yaml wird die Umgebungsvariable HTTP_PORT aus der ConfigMap geladen:

- name: HTTP_PORT
  valueFrom:
    configMapKeyRef:
      name: product-api-config
      key: HTTP_PORT

Aber in configmap.yaml ist der Schlüssel HTTP_PORT nicht definiert - nur APP_NAME, APP_ENVIRONMENT und index.html.

Fehler: Die Pod-Initialisierung schlägt fehl, weil der fehlende Key nicht aufgelöst werden kann.

Lösung: Fügen Sie den fehlenden Schlüssel HTTP_PORT: "8080" zur ConfigMap hinzu.

Aufgabe - Szenario 4

  • Wechseln Sie in den Ordner debugging-manifests/scenario-4. Hier finden Sie ein Deployment für einen Report Generator. Der Pod wird erstellt, bleibt aber im Status Pending stecken und startet nicht.

Untersuchen Sie das Deployment und finden Sie den Grund für das Problem. Reparieren Sie das Manifest, damit der Pod gestartet werden kann.

Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)

Das Problem liegt bei den angeforderten Ressourcen im Deployment. In app.yaml werden unrealistische Ressourcen angefordert:

resources:
  requests:
    cpu: "100"
    memory: "256Gi"
  limits:
    cpu: "100"
    memory: "256Gi"

Fehler: Der Pod kann nicht gestartet werden (bleibt Pending), da kein Node 100 CPU-Kerne und 256GB RAM verfügbar hat.

Lösung: Reduzieren Sie die Ressourcen auf realistische Werte, zum Beispiel:

resources:
  requests:
    cpu: "50m"
    memory: "64Mi"
  limits:
    cpu: "100m"
    memory: "128Mi"

Aufgabe - Szenario 5

  • Wechseln Sie in den Ordner debugging-manifests/scenario-5.
  • Führen Sie zunächst das Script setup-node-label.sh aus, um einen Node zu labeln.
  • Rollen Sie anschließend das Deployment aus.

Der Pod wird erstellt, bleibt aber wieder im Status Pending stecken. Untersuchen Sie das Deployment und finden Sie den Grund für das Problem.

Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)

Das Problem liegt bei einem Tippfehler im Node-Label-Selektor. Das Script setup-node-label.sh labelt den Node mit dem Label training.example.com/workload=general.

Im Deployment app.yaml wird aber nach einem anderen Label gesucht:

affinity:
  nodeAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
      nodeSelectorTerms:
        - matchExpressions:
            - key: training.example.com/worklaod
              operator: In
              values:
                - general

Fehler: Der Key ist falsch geschrieben: training.example.com/worklaod (mit Tippfehler "worklaod" statt "workload"). Der Node hat dieses Label nicht, daher kann der Pod nicht gestartet werden.

Lösung: Korrigieren Sie den Tippfehler in app.yaml von worklaod zu workload:

- key: training.example.com/workload

Aufgabe - Szenario 6

  • Wechseln Sie in den Ordner debugging-manifests/scenario-6. Hier finden Sie ein Deployment für eine Memory-Application mit einer dazugehörigen Python-Anwendung in einer ConfigMap.

Rollen Sie das Deployment aus. Der Pod startet zwar, wird aber sofort beendet. Untersuchen Sie die Manifeste und finden Sie das Problem. Reparieren Sie die Manifeste.

Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)

Das Problem liegt bei einem zu niedrigen Memory Limit im Deployment. Die Python-Anwendung in configmap.yaml allokaziert 96 MB Speicher:

BUFFER_SIZE = 96 * 1024 * 1024

Im Deployment app.yaml sind aber nur folgende Limits gesetzt:

resources:
  requests:
    cpu: 10m
    memory: 32Mi
  limits:
    cpu: 100m
    memory: 64Mi

Fehler: Die Anwendung versucht 96MB zu allokieren, aber das Limit ist nur 64MB. Kubernetes beendet den Pod mit OOMKilled (Out Of Memory Killed).

Lösung: Erhöhen Sie die Memory Limits in app.yaml auf mindestens 100Mi:

resources:
  requests:
    cpu: 10m
    memory: 64Mi
  limits:
    cpu: 100m
    memory: 100Mi

Aufgabe - Szenario 7

  • Wechseln Sie in den Ordner debugging-manifests/scenario-7. Hier finden Sie ein Deployment für eine Slow-Application, die eine längere Startupzeit benötigt.

Rollen Sie das Deployment aus. Der Pod wird erstellt, startet aber sofort wieder neu (Restart-Loop). Finden Sie den Grund, warum die Anwendung neu gestartet wird, und reparieren Sie das Manifest.

Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)

Das Problem liegt bei den falsch konfigurierten Liveness- und Readiness-Probes. Die Anwendung braucht 25 Sekunden zum Starten:

time.sleep(25)

Aber die Probes sind so konfiguriert:

readinessProbe:
  initialDelaySeconds: 2
  failureThreshold: 1

livenessProbe:
  initialDelaySeconds: 2
  failureThreshold: 2

Fehler: Die livenessProbe beginnt bereits nach 2 Sekunden Checks durchzuführen, aber die Anwendung ist noch nicht bereit (wird erst nach 25 Sekunden bereit). Nach 2 fehlgeschlagenen Versuchen wird der Pod von Kubernetes als "dead" markiert und neu gestartet.

Lösung: Erhöhen Sie das initialDelaySeconds der livenessProbe auf mindestens 30 Sekunden, damit die Anwendung erst vollständig hochgefahren ist:

livenessProbe:
  httpGet:
    path: /health
    port: http
  initialDelaySeconds: 30
  periodSeconds: 3
  timeoutSeconds: 1
  failureThreshold: 2

Aufgabe - Szenario 8

  • Wechseln Sie in den Ordner debugging-manifests/scenario-8. Hier finden Sie ein Deployment für eine Status-Page mit zwei Containern.

Rollen Sie das Deployment aus. Der Pod wird erstellt, aber der Webserver wird nie bereit (bleibt in Not Ready-Status stecken). Untersuchen Sie die Container-Logs und das Manifest. Finden Sie heraus, warum der Webserver nicht auf die generierte Statusseite zugreifen kann, und reparieren Sie das Manifest.

Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)

Das Problem liegt bei der falschen Container-Konfiguration. Der content-sync Container soll die Status-Seite generieren, beendet sich aber sofort nach Abschluss. Da er als regulärer Container definiert ist, wird der Pod als fehlgeschlagen markiert.

Im Manifest wird der content-sync in der containers Liste definiert:

containers:
  - name: webserver
    ...
  - name: content-sync
    ...
    args:
      - |
        echo "Generating status page"
        cat > /shared/index.html <<EOF
        ...
        EOF
        echo "Status page successfully generated"

Fehler: Der content-sync Container beendet sich nach der Generierung und wird als crashed interpretiert. Der Webserver kann nicht auf die Datei zugreifen, da der Pod neu startet.

Lösung: Verschieben Sie den content-sync Container in die initContainers Liste, damit er sich als Init-Container vor dem Webserver ausführt und sich dann beendet, ohne den Pod neu zu starten:

spec:
  initContainers:
    - name: content-sync
      image: busybox:1.36.1
      ...
  containers:
    - name: webserver
      ...

Aufgabe - Szenario 9

  • Wechseln Sie in den Ordner debugging-manifests/scenario-9. Hier finden Sie ein Deployment für eine Orders-API mit einem dazugehörigen Service.

Rollen Sie die Manifeste aus. Die Pods starten korrekt und sind bereit, aber die Webseite ist über den Service nicht erreichbar. Untersuchen Sie die Manifeste und finden Sie den Grund, warum der Service die Pods nicht erreichen kann. Reparieren Sie die Manifeste. Die API kann über den HTTP Endpunkt /orders aufgerufen werden.

Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)

Das Problem liegt bei einem Tippfehler in den Label-Selektoren zwischen Service und Deployment.

Der Service in service.yaml selektiert nach:

selector:
  app.kubernetes.io/name: order-api

Das Deployment in deployment.yaml labelt aber mit:

labels:
  app.kubernetes.io/name: orders-api
  app.kubernetes.io/component: backend

Fehler: Der Service sucht nach order-api (Singular), aber das Deployment labelt mit orders-api (Plural). Die Labels passen nicht zusammen, daher hat der Service keine Endpoints und die Pods sind nicht erreichbar.

Lösung: Korrigieren Sie den Label-Selektor im Service von order-api zu orders-api, damit die Labels passen:

selector:
  app.kubernetes.io/name: orders-api