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 einenCrashLoopBackOff-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 StatusPendingstecken 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.shaus, 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