Kubernetes Workshop: Intermediate – Übungsaufgaben mit Lösungen
Bezug: 02-intermediate-DE-aktualisiert.md
Schwierigkeitsgrad: Intermediate
Format: Hands-on-Lab mit Musterlösungen und Walkthroughs
Ziel dieses Übungsdokuments
Dieses Übungsdokument ergänzt den Intermediate-Workshop mit praxisnahen Aufgaben, Lösungen und Walkthroughs. Der Schwerpunkt liegt auf Workload-Auswahl, Init Containern, Sidecars, Ephemeral Containern, Probes, graceful Shutdown, PodDisruptionBudgets, Requests, Limits, QoS, LimitRange, ResourceQuota, Scheduling, NetworkPolicy, DNS, Ingress oder Gateway API, Storage, Helm, Kustomize und systematischem Troubleshooting.
Voraussetzungen
Du brauchst:
- einen Lab-Cluster mit funktionierendem CNI
- CoreDNS
kubectl- optional:
helm - optional:
kustomizeoderkubectl kustomize - optional: eine StorageClass
- optional: Ingress Controller oder Gateway Controller
Empfohlener Namespace:
export NS=workshop-intermediate
kubectl create namespace "$NS"
kubectl config set-context --current --namespace="$NS"
Aufgabenübersicht
| Nr. | Thema | Ergebnis |
|---|---|---|
| 1 | Workload-Auswahl | Deployment, Job und CronJob fachlich abgegrenzt |
| 2 | Init Container und Sidecar | Pod-Lebenszyklen nachvollzogen |
| 3 | Probes und Lifecycle | Startup, Readiness und Liveness sauber getrennt |
| 4 | Resources, QoS, LimitRange, Quota | Namespace-Grenzen und Scheduling-Wirkung geprüft |
| 5 | Scheduling | Node Labels, nodeSelector, Taints und Tolerations getestet |
| 6 | NetworkPolicy und DNS | Default Deny plus gezielte Erlaubnisse erstellt |
| 7 | Ingress oder Gateway | HTTP-App extern erreichbar gemacht oder sauber eingeordnet |
| 8 | PVC und StatefulSet | persistenter Zustand getestet |
| 9 | Helm und Kustomize | gerenderte Manifeste verglichen |
| 10 | Troubleshooting-Parcours | typische Fehler systematisch behoben |
Teil A – Aufgaben
Aufgabe 1: Workload-Ressource auswählen
Ziel
Du entscheidest, ob Deployment, Job oder CronJob fachlich passt.
Ausgangslage
Du sollst drei Anforderungen modellieren:
- Ein Webserver soll dauerhaft laufen und rollend aktualisiert werden.
- Eine Datenmigration soll einmalig laufen und danach beendet sein.
- Ein Cleanup soll jede Stunde laufen.
Arbeitsauftrag
- Erstelle für jeden Fall ein Minimalmanifest.
- Wende die Manifeste an.
- Prüfe Status und Events.
- Dokumentiere, warum die gewählte Ressource passt.
Aufgabe 2: Init Container und Sidecar einordnen
Ziel
Du verstehst, wann ein Init Container vor der Anwendung laufen muss und wann ein zusätzlicher Container denselben Pod-Lebenszyklus teilt.
Arbeitsauftrag
Erstelle einen Pod, bei dem:
- ein Init Container eine Datei in ein
emptyDirschreibt, - der App Container diese Datei liest,
- ein Sidecar Container periodisch eine Heartbeat-Datei schreibt.
Prüfe:
- Reihenfolge der Containerstarts,
- Logs aller Container,
- Inhalt des gemeinsamen Volumes.
Aufgabe 3: Probes korrekt trennen
Ziel
Du korrigierst eine fehlerhafte Probe-Konfiguration, die Neustarts verursacht.
Ausgangslage
Eine Beispiel-App startet langsam. Die Liveness Probe prüft zu früh denselben Pfad wie Readiness.
Arbeitsauftrag
- Erstelle ein Deployment mit absichtlich zu aggressiver Liveness Probe.
- Beobachte Events und Restarts.
- Ergänze eine Startup Probe.
- Trenne Readiness und Liveness fachlich.
- Erkläre, warum Readiness Traffic steuert und Liveness Neustarts auslöst.
Aufgabe 4: Resources, QoS, LimitRange und ResourceQuota
Ziel
Du setzt Requests und Limits, beobachtest QoS-Klassen und erzeugst Namespace-Grenzen.
Arbeitsauftrag
- Erstelle eine LimitRange mit Default Requests und Limits.
- Erstelle eine ResourceQuota für CPU, Memory und Pod-Anzahl.
- Rolle drei Pods aus:
- ohne explizite Ressourcen,
- mit Requests kleiner als Limits,
- mit Requests gleich Limits.
- Bestimme die QoS-Klassen.
- Erzeuge absichtlich eine Quota-Verletzung.
Aufgabe 5: Scheduling mit Node Labels, nodeSelector, Taint und Toleration
Ziel
Du steuerst die Platzierung eines Pods und interpretierst Pending-Events.
Arbeitsauftrag
- Label einen Lab-Node mit
workshop-role=apps. - Erstelle einen Pod mit passendem
nodeSelector. - Erstelle einen Pod mit nicht passendem
nodeSelector. - Setze einen Taint auf den Node.
- Erstelle einmal einen Pod ohne Toleration und einmal mit Toleration.
- Dokumentiere die Events.
Aufgabe 6: NetworkPolicy Default Deny plus DNS-Erlaubnis
Ziel
Du erstellst eine Default-Deny-Policy und erlaubst danach gezielt DNS und App-Traffic.
Arbeitsauftrag
- Erstelle zwei Deployments:
frontendundbackend. - Erstelle Services für beide.
- Prüfe, dass
frontendbackenderreichen kann. - Erstelle eine Default-Deny-Policy für Ingress und Egress.
- Prüfe, dass Traffic blockiert ist.
- Erlaube DNS-Egress.
- Erlaube
frontendzubackendauf Port 8080. - Prüfe erneut.
Aufgabe 7: Ingress oder Gateway bereitstellen
Ziel
Du veröffentlichst eine HTTP-Anwendung über Ingress oder beschreibst alternativ die Gateway-API-Ressourcen, wenn kein Controller installiert ist.
Arbeitsauftrag
- Prüfe, ob ein Ingress Controller oder Gateway Controller vorhanden ist.
- Stelle eine HTTP-App bereit.
- Erstelle entweder eine Ingress-Ressource oder ein Gateway/HTTPRoute-Beispiel.
- Prüfe Controller-Events, Backend-Service und Routing.
- Dokumentiere, warum eine Ingress-Ressource ohne Controller keine Wirkung hat.
Aufgabe 8: PVC und StatefulSet nutzen
Ziel
Du betreibst einen kleinen stateful Workload mit PVC und prüfst, ob Daten nach Pod-Neuerstellung erhalten bleiben.
Arbeitsauftrag
- Prüfe vorhandene StorageClasses.
- Erstelle ein StatefulSet mit
volumeClaimTemplates. - Schreibe eine Datei in das Volume.
- Lösche den Pod.
- Prüfe nach der Neuerstellung, ob die Datei noch existiert.
- Dokumentiere, warum ein
hostPath-Lab keine Produktionsannahme ist.
Aufgabe 9: Helm und Kustomize vergleichen
Ziel
Du renderst Manifeste, bevor du sie anwendest, und vergleichst Helm mit Kustomize.
Arbeitsauftrag
- Erstelle eine kleine Kustomize-Base und ein Overlay
dev. - Rendere das Overlay.
- Erstelle ein minimales Helm Chart oder nutze ein lokales Beispielchart.
- Rendere das Helm Chart.
- Vergleiche Reviewbarkeit, Parametrisierung und Fehlerrisiko.
Aufgabe 10: Troubleshooting-Parcours
Ziel
Du untersuchst fünf typische Fehlerbilder methodisch.
Fehlerbilder
- Pod bleibt
Pendingwegen falschemnodeSelector. - Pod zeigt
ImagePullBackOffwegen falschem Image-Tag. - Pod zeigt
CrashLoopBackOffwegen fehlerhaftem Startkommando. - PVC bleibt
Pendingwegen falscher StorageClass. - Service hat keine Endpoints wegen falschem Selector.
Arbeitsauftrag
Für jeden Fehler dokumentierst du:
- Symptom,
- Diagnosekommando,
- relevante Events oder Logs,
- Ursache,
- Fix,
- Validierung.
Teil B – Lösungen und Walkthroughs
Lösung 1: Workload-Ressource auswählen
Deployment für dauerhaft laufenden Webserver
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
namespace: workshop-intermediate
spec:
replicas: 2
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: web
image: nginx:1.27
ports:
- containerPort: 80
Job für einmalige Migration
apiVersion: batch/v1
kind: Job
metadata:
name: migration
namespace: workshop-intermediate
spec:
template:
spec:
restartPolicy: OnFailure
containers:
- name: migration
image: busybox:1.36
command: ["sh", "-c", "echo Migration läuft; sleep 3; echo Migration fertig"]
CronJob für stündlichen Cleanup
apiVersion: batch/v1
kind: CronJob
metadata:
name: cleanup
namespace: workshop-intermediate
spec:
schedule: "0 * * * *"
concurrencyPolicy: Forbid
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 1
jobTemplate:
spec:
template:
spec:
restartPolicy: OnFailure
containers:
- name: cleanup
image: busybox:1.36
command: ["sh", "-c", "date; echo cleanup"]
Prüfung:
kubectl apply -f deployment.yml
kubectl apply -f job.yml
kubectl apply -f cronjob.yml
kubectl get deployment,job,cronjob,pod
kubectl logs job/migration
Fachliche Entscheidung:
| Anforderung | Ressource | Begründung |
|---|---|---|
| dauerhaft laufender HTTP-Dienst | Deployment | Replikate, Rollouts, Rollbacks |
| einmalige Migration | Job | Abschlusszustand ist fachlich gewünscht |
| stündliches Cleanup | CronJob | zeitgesteuerte Job-Erzeugung |
Lösung 2: Init Container und Sidecar
Manifest:
apiVersion: v1
kind: Pod
metadata:
name: lifecycle-demo
namespace: workshop-intermediate
labels:
app: lifecycle-demo
spec:
volumes:
- name: shared
emptyDir: {}
initContainers:
- name: init-write
image: busybox:1.36
command: ["sh", "-c", "echo vorbereitet > /shared/init.txt"]
volumeMounts:
- name: shared
mountPath: /shared
containers:
- name: app
image: busybox:1.36
command: ["sh", "-c", "while true; do cat /shared/init.txt; sleep 30; done"]
volumeMounts:
- name: shared
mountPath: /shared
- name: sidecar
image: busybox:1.36
command: ["sh", "-c", "while true; do date > /shared/heartbeat.txt; sleep 10; done"]
volumeMounts:
- name: shared
mountPath: /shared
Prüfung:
kubectl apply -f lifecycle-demo.yml
kubectl get pod lifecycle-demo
kubectl describe pod lifecycle-demo
kubectl logs lifecycle-demo -c init-write
kubectl logs lifecycle-demo -c app
kubectl exec lifecycle-demo -c app -- ls -l /shared
kubectl exec lifecycle-demo -c app -- cat /shared/heartbeat.txt
Erklärung:
- Init Container laufen vor App Containern und müssen erfolgreich enden.
- Sidecars laufen parallel zur Anwendung.
emptyDirteilt Dateien innerhalb desselben Pods, bleibt aber nicht über Pod-Löschung hinaus erhalten.
Lösung 3: Probes korrigieren
Robustes Beispielmanifest:
apiVersion: apps/v1
kind: Deployment
metadata:
name: probe-demo
namespace: workshop-intermediate
spec:
replicas: 1
selector:
matchLabels:
app: probe-demo
template:
metadata:
labels:
app: probe-demo
spec:
containers:
- name: app
image: registry.k8s.io/e2e-test-images/agnhost:2.53
args: ["netexec", "--http-port=8080"]
ports:
- containerPort: 8080
startupProbe:
httpGet:
path: /healthz
port: 8080
failureThreshold: 30
periodSeconds: 2
readinessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 2
periodSeconds: 5
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 10
periodSeconds: 10
Prüfung:
kubectl apply -f probe-demo.yml
kubectl rollout status deployment/probe-demo
kubectl describe pod -l app=probe-demo
kubectl get pods -w
Mustererklärung:
- Startup Probe schützt langsame Starts; solange sie nicht erfolgreich ist, werden Liveness und Readiness nicht aktiv.
- Readiness entscheidet, ob ein Pod Endpoints für Services erhält.
- Liveness entscheidet, ob kubelet den Container neu startet.
- Eine zu aggressive Liveness Probe erzeugt Neustart-Schleifen.
Lösung 4: Resources, QoS, LimitRange und ResourceQuota
LimitRange:
apiVersion: v1
kind: LimitRange
metadata:
name: defaults
namespace: workshop-intermediate
spec:
limits:
- type: Container
defaultRequest:
cpu: 100m
memory: 128Mi
default:
cpu: 500m
memory: 256Mi
max:
cpu: "1"
memory: 512Mi
ResourceQuota:
apiVersion: v1
kind: ResourceQuota
metadata:
name: namespace-quota
namespace: workshop-intermediate
spec:
hard:
pods: "5"
requests.cpu: "1"
requests.memory: 1Gi
limits.cpu: "3"
limits.memory: 2Gi
Prüfung:
kubectl apply -f limitrange.yml
kubectl apply -f quota.yml
kubectl describe limitrange defaults
kubectl describe resourcequota namespace-quota
Pod mit Burstable QoS:
apiVersion: v1
kind: Pod
metadata:
name: burstable-pod
namespace: workshop-intermediate
spec:
containers:
- name: app
image: busybox:1.36
command: ["sh", "-c", "sleep 3600"]
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 256Mi
Pod mit Guaranteed QoS:
apiVersion: v1
kind: Pod
metadata:
name: guaranteed-pod
namespace: workshop-intermediate
spec:
containers:
- name: app
image: busybox:1.36
command: ["sh", "-c", "sleep 3600"]
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 100m
memory: 128Mi
QoS prüfen:
kubectl apply -f burstable-pod.yml
kubectl apply -f guaranteed-pod.yml
kubectl get pod burstable-pod -o jsonpath='{.status.qosClass}{"\n"}'
kubectl get pod guaranteed-pod -o jsonpath='{.status.qosClass}{"\n"}'
Quota-Verletzung erzeugen:
apiVersion: v1
kind: Pod
metadata:
name: too-large
namespace: workshop-intermediate
spec:
containers:
- name: app
image: busybox:1.36
command: ["sh", "-c", "sleep 3600"]
resources:
requests:
cpu: "2"
memory: 2Gi
limits:
cpu: "2"
memory: 2Gi
Erwartung:
kubectl apply -f too-large.yml
Der API Server lehnt die Ressource wegen ResourceQuota ab.
Lösung 5: Scheduling
Node auswählen:
NODE=$(kubectl get nodes -o jsonpath='{.items[0].metadata.name}')
kubectl label node "$NODE" workshop-role=apps
kubectl get nodes --show-labels | grep workshop-role
Pod mit passendem nodeSelector:
apiVersion: v1
kind: Pod
metadata:
name: scheduled-ok
namespace: workshop-intermediate
spec:
nodeSelector:
workshop-role: apps
containers:
- name: app
image: busybox:1.36
command: ["sh", "-c", "sleep 3600"]
Pod mit nicht passendem nodeSelector:
apiVersion: v1
kind: Pod
metadata:
name: scheduled-pending
namespace: workshop-intermediate
spec:
nodeSelector:
workshop-role: does-not-exist
containers:
- name: app
image: busybox:1.36
command: ["sh", "-c", "sleep 3600"]
Prüfung:
kubectl apply -f scheduled-ok.yml
kubectl apply -f scheduled-pending.yml
kubectl get pods -o wide
kubectl describe pod scheduled-pending
Taint setzen:
kubectl taint node "$NODE" dedicated=apps:NoSchedule
Pod mit Toleration:
apiVersion: v1
kind: Pod
metadata:
name: tolerated
namespace: workshop-intermediate
spec:
nodeSelector:
workshop-role: apps
tolerations:
- key: dedicated
operator: Equal
value: apps
effect: NoSchedule
containers:
- name: app
image: busybox:1.36
command: ["sh", "-c", "sleep 3600"]
Cleanup:
kubectl delete pod scheduled-ok scheduled-pending tolerated --ignore-not-found
kubectl taint node "$NODE" dedicated=apps:NoSchedule-
kubectl label node "$NODE" workshop-role-
Erklärung:
nodeSelectorist hart: kein passender Node bedeutetPending.- Taint weist Pods ab.
- Toleration erlaubt einem Pod, einen Taint zu tolerieren; sie erzwingt nicht allein die Platzierung.
Lösung 6: NetworkPolicy und DNS
Beispiel-App:
apiVersion: apps/v1
kind: Deployment
metadata:
name: backend
namespace: workshop-intermediate
spec:
replicas: 1
selector:
matchLabels:
app: backend
template:
metadata:
labels:
app: backend
spec:
containers:
- name: backend
image: registry.k8s.io/e2e-test-images/agnhost:2.53
args: ["netexec", "--http-port=8080"]
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: backend
namespace: workshop-intermediate
spec:
selector:
app: backend
ports:
- name: http
port: 8080
targetPort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
namespace: workshop-intermediate
spec:
replicas: 1
selector:
matchLabels:
app: frontend
template:
metadata:
labels:
app: frontend
spec:
containers:
- name: frontend
image: curlimages/curl:8.8.0
command: ["sh", "-c", "sleep 3600"]
Test vor Policy:
kubectl apply -f net-demo.yml
kubectl wait --for=condition=Available deployment/backend --timeout=90s
kubectl wait --for=condition=Available deployment/frontend --timeout=90s
FRONTEND=$(kubectl get pod -l app=frontend -o jsonpath='{.items[0].metadata.name}')
kubectl exec "$FRONTEND" -- curl -s http://backend:8080/hostname
Default Deny:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny
namespace: workshop-intermediate
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
DNS-Egress erlauben:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-dns-egress
namespace: workshop-intermediate
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
Frontend zu Backend erlauben:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend-to-backend
namespace: workshop-intermediate
spec:
podSelector:
matchLabels:
app: backend
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 8080
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend-egress-to-backend
namespace: workshop-intermediate
spec:
podSelector:
matchLabels:
app: frontend
policyTypes:
- Egress
egress:
- to:
- podSelector:
matchLabels:
app: backend
ports:
- protocol: TCP
port: 8080
Prüfung:
kubectl apply -f default-deny.yml
kubectl apply -f allow-dns-egress.yml
kubectl apply -f allow-frontend-backend.yml
kubectl exec "$FRONTEND" -- nslookup backend
kubectl exec "$FRONTEND" -- curl -s --max-time 5 http://backend:8080/hostname
Hinweis:
NetworkPolicies wirken nur, wenn das CNI-Plugin sie durchsetzt.
Lösung 7: Ingress oder Gateway
Controller prüfen:
kubectl get ingressclass
kubectl get gatewayclass 2>/dev/null || true
kubectl get pods -A | grep -Ei 'ingress|gateway|traefik|nginx|envoy|haproxy'
Ingress-Beispiel:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: web
namespace: workshop-intermediate
spec:
rules:
- host: web.localtest.me
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: backend
port:
number: 8080
Prüfung:
kubectl apply -f ingress.yml
kubectl describe ingress web
kubectl get ingress web
Gateway-API-Beispiel, falls Gateway API installiert ist:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: web
namespace: workshop-intermediate
spec:
parentRefs:
- name: shared-gateway
namespace: gateway-system
hostnames:
- web.localtest.me
rules:
- backendRefs:
- name: backend
port: 8080
Fachliche Erklärung:
- Ingress ist nur eine Regelbeschreibung.
- Ein Ingress Controller muss diese Regel in Proxy-/Load-Balancer-Konfiguration übersetzen.
- Gateway API trennt Infrastrukturverantwortung stärker von Anwendungsrouting.
Lösung 8: PVC und StatefulSet
StorageClass prüfen:
kubectl get storageclass
StatefulSet:
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: data-demo
namespace: workshop-intermediate
spec:
serviceName: data-demo
replicas: 1
selector:
matchLabels:
app: data-demo
template:
metadata:
labels:
app: data-demo
spec:
containers:
- name: app
image: busybox:1.36
command: ["sh", "-c", "while true; do sleep 3600; done"]
volumeMounts:
- name: data
mountPath: /data
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 1Gi
Anwenden und testen:
kubectl apply -f statefulset.yml
kubectl rollout status statefulset/data-demo
kubectl exec data-demo-0 -- sh -c 'echo persistenz-test > /data/test.txt'
kubectl delete pod data-demo-0
kubectl wait --for=condition=Ready pod/data-demo-0 --timeout=120s
kubectl exec data-demo-0 -- cat /data/test.txt
Erwartung:
Die Datei ist nach Pod-Neuerstellung weiterhin vorhanden, weil der PVC wieder mit data-demo-0 verbunden wird.
Einordnung:
- StatefulSets bieten stabile Pod-Namen und stabile PVC-Zuordnung.
- Ein lokales
hostPath-Volume im Lab ist bequem, aber nicht portabel und kein Produktionsspeicher.
Lösung 9: Helm und Kustomize
Kustomize-Struktur:
kustomize-demo/
base/
deployment.yml
service.yml
kustomization.yml
overlays/
dev/
kustomization.yml
base/kustomization.yml:
resources:
- deployment.yml
- service.yml
overlays/dev/kustomization.yml:
resources:
- ../../base
namePrefix: dev-
labels:
- pairs:
environment: dev
images:
- name: nginx
newTag: "1.27"
Rendern:
kubectl kustomize kustomize-demo/overlays/dev
kubectl apply -k kustomize-demo/overlays/dev --dry-run=server
Minimales Helm Chart:
helm create webchart
helm template web ./webchart
helm lint ./webchart
Vergleich:
| Kriterium | Helm | Kustomize |
|---|---|---|
| Modell | Paket mit Templates und Values | Base/Overlay ohne Template-Sprache |
| Stärke | viele Parameter, Releases, Chart-Ökosystem | YAML-nah, gut reviewbar |
| Risiko | komplexe Templates können schwer prüfbar sein | Overlays können unübersichtlich werden |
| Pflichtprüfung | helm template, helm lint |
kubectl kustomize, dry-run |
Lösung 10: Troubleshooting-Parcours
Musterdiagnose:
| Fehlerbild | Diagnose | Ursache | Fix |
|---|---|---|---|
Pending |
kubectl describe pod |
kein Node erfüllt nodeSelector |
Label korrigieren oder Selector entfernen |
ImagePullBackOff |
Events im Pod | Image/Tag/Registry falsch | gültiges Image setzen |
CrashLoopBackOff |
kubectl logs --previous |
Prozess beendet sich fehlerhaft | Startkommando/App-Konfiguration korrigieren |
PVC Pending |
kubectl describe pvc |
StorageClass fehlt oder Provisioner fehlt | StorageClass korrigieren oder bereitstellen |
| Service ohne Endpoints | kubectl get endpoints, Labels prüfen |
Selector passt nicht | Selector oder Pod-Labels korrigieren |
Standardabfolge:
kubectl get all
kubectl get pod -o wide
kubectl describe pod <pod>
kubectl get events --sort-by=.metadata.creationTimestamp
kubectl logs <pod>
kubectl logs <pod> --previous
kubectl get svc,endpoints,endpointslices
kubectl describe pvc <pvc>
Cleanup
kubectl delete namespace workshop-intermediate
Bewertungscheckliste
| Kriterium | Erfüllt? |
|---|---|
| Workload-Ressourcen fachlich unterschieden | ☐ |
| Init Container, Sidecar und App Container erklärt | ☐ |
| Probes korrekt getrennt | ☐ |
| Requests, Limits, QoS, LimitRange und Quota angewendet | ☐ |
| Scheduling-Events interpretiert | ☐ |
| NetworkPolicy inklusive DNS berücksichtigt | ☐ |
| Ingress/Gateway Controller-Rolle erklärt | ☐ |
| PVC und StatefulSet getestet | ☐ |
| Helm und Kustomize gerendert | ☐ |
| Troubleshooting-Parcours dokumentiert | ☐ |