Kubernetes Workshop: Fundamentals – Übungsaufgaben mit Lösungen
Bezug: 01-fundamentals-DE-aktualisiert.md
Schwierigkeitsgrad: Fundamentals
Format: Hands-on-Lab mit Musterlösungen und Walkthroughs
Ziel dieses Übungsdokuments
Dieses Übungsdokument ergänzt den Fundamentals-Workshop mit konkreten Aufgaben, überprüfbaren Ergebnissen und vollständigen Lösungen. Der Schwerpunkt liegt auf sicherer Grundbedienung, Kubernetes-Objektmodell, kubectl, Pods, Deployments, ReplicaSets, Services, Labels, Selectors, ConfigMaps, Secrets, Namespaces, Rollouts, Skalierung, Rollback und erster Fehlerdiagnose.
Du arbeitest ausschließlich in einem Lab-Cluster. Verwende keine produktiven Cluster-Kontexte und keine echten Zugangsdaten.
Voraussetzungen
Du brauchst:
kubectl- einen lokalen oder bereitgestellten Kubernetes-Cluster, zum Beispiel
kind,minikubeoderk3d - einen ungefährlichen Cluster-Kontext
- Schreibrechte in einem eigenen Namespace
Empfohlener Namespace für alle Übungen:
export NS=workshop-fundamentals
Arbeitsregeln
- Prüfe vor jeder Übung den aktiven Kontext.
- Arbeite nur im Namespace
$NS. - Speichere Manifeste als Dateien, bevor du sie anwendest.
- Nutze
kubectl apply --dry-run=server, sofern dein Cluster das unterstützt. - Prüfe nach jeder Änderung Status, Events und Logs.
- Dokumentiere am Ende den Rückbau.
Aufgabenübersicht
| Nr. | Thema | Ergebnis |
|---|---|---|
| 1 | Kontext, Cluster und Namespace | sicherer Lab-Kontext und Namespace |
| 2 | Objektmodell lesen | Deployment-Manifest erklären |
| 3 | Deployment und Service | einfache Web-App intern erreichbar |
| 4 | Labels und Selectors | Service-Fehler diagnostiziert und behoben |
| 5 | ConfigMap und Secret | Konfiguration und Beispiel-Secret eingebunden |
| 6 | Rollout, Skalierung und Rollback | Image-Update, Skalierung und Rollback durchgeführt |
| 7 | Troubleshooting: ImagePullBackOff | falsches Image diagnostiziert und korrigiert |
| 8 | Troubleshooting: CrashLoopBackOff | crashende Anwendung diagnostiziert und korrigiert |
| 9 | Betriebsnotiz und Rückbau | Ressourcenliste, Validierung und Cleanup dokumentiert |
Teil A – Aufgaben
Aufgabe 1: Kontext, Cluster und Namespace prüfen
Ziel
Du stellst sicher, dass du im richtigen Cluster arbeitest und erstellst einen eigenen Namespace.
Arbeitsauftrag
- Prüfe den aktiven Kontext.
- Prüfe Cluster-Informationen und Nodes.
- Erstelle den Namespace
workshop-fundamentals. - Setze den Namespace für den aktuellen Kontext.
- Dokumentiere Clustername, Node-Anzahl und Kubernetes-Version.
Erwartetes Ergebnis
- Der Namespace existiert.
kubectl get podszeigt standardmäßig Ressourcen ausworkshop-fundamentals.- Du kannst erklären, warum der Kontext vor jedem Lab geprüft wird.
Aufgabe 2: Kubernetes-Objektmodell lesen
Ziel
Du liest ein Deployment-Manifest und erkennst apiVersion, kind, metadata, spec, selector, Pod-Template und Container-Konfiguration.
Arbeitsauftrag
Erstelle die Datei deployment.yml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
namespace: workshop-fundamentals
labels:
app: web
tier: frontend
environment: lab
spec:
replicas: 2
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
tier: frontend
environment: lab
spec:
containers:
- name: nginx
image: nginx:1.27
ports:
- containerPort: 80
Beantworte schriftlich:
- Welche API-Gruppe wird verwendet?
- Welche Ressource wird erstellt?
- Wo steht der gewünschte Zustand?
- Welche Labels bekommen die Pods?
- Wofür wird der Selector verwendet?
Aufgabe 3: Deployment und Service ausrollen
Ziel
Du rollst eine einfache Webanwendung aus und machst sie über einen internen ClusterIP-Service erreichbar.
Arbeitsauftrag
- Wende
deployment.ymlan. - Erstelle die Datei
service.yml:
apiVersion: v1
kind: Service
metadata:
name: web
namespace: workshop-fundamentals
labels:
app: web
spec:
type: ClusterIP
selector:
app: web
ports:
- name: http
port: 80
targetPort: 80
- Wende
service.ymlan. - Prüfe Deployment, ReplicaSet, Pods, Service, Endpoints und EndpointSlices.
- Teste den Service per temporärem Debug-Pod.
Erwartetes Ergebnis
- Zwei Pods laufen.
- Der Service hat Endpoints.
- Ein temporärer Pod kann
http://weberreichen.
Aufgabe 4: Labels und Selectors absichtlich brechen
Ziel
Du verstehst, warum Services Pods über Labels und Selectors finden und nicht über Pod-Namen.
Arbeitsauftrag
- Ändere den Service-Selector in
service.ymlabsichtlich falsch:
selector:
app: wrong-web
- Wende die Änderung an.
- Prüfe Service, Endpoints und EndpointSlices.
- Korrigiere den Selector wieder auf
app: web. - Prüfe erneut.
Erwartetes Ergebnis
- Mit falschem Selector hat der Service keine Endpoints.
- Nach der Korrektur sind Endpoints wieder vorhanden.
Aufgabe 5: ConfigMap und Secret einbinden
Ziel
Du unterscheidest nicht-sensitive Konfiguration von sensiblen Beispielwerten und bindest beides in einen Pod ein.
Arbeitsauftrag
Erstelle configmap.yml:
apiVersion: v1
kind: ConfigMap
metadata:
name: web-config
namespace: workshop-fundamentals
data:
APP_MODE: lab
WELCOME_TEXT: "Hallo aus Kubernetes"
Erstelle secret.yml:
apiVersion: v1
kind: Secret
metadata:
name: web-secret
namespace: workshop-fundamentals
type: Opaque
stringData:
DEMO_PASSWORD: "not-a-real-secret"
Erweitere dein Deployment so, dass APP_MODE als Environment-Variable und DEMO_PASSWORD als Datei eingebunden wird.
Erwartetes Ergebnis
- Die ConfigMap existiert.
- Das Secret existiert.
- Der Pod enthält
APP_MODEals Environment-Variable. - Das Secret ist als Datei im Container sichtbar.
Aufgabe 6: Rollout, Skalierung und Rollback durchführen
Ziel
Du nutzt Deployment-Rollouts kontrolliert und kannst eine Änderung zurücknehmen.
Arbeitsauftrag
- Prüfe den aktuellen Rollout-Status.
- Skaliere das Deployment auf drei Replikate.
- Ändere das Image von
nginx:1.27aufnginx:1.26. - Prüfe Rollout-Status und Rollout-History.
- Führe ein Rollback durch.
- Prüfe, welches Image danach aktiv ist.
Erwartetes Ergebnis
- Drei Pods laufen.
- Die Rollout-History zeigt mindestens zwei Revisionen.
- Nach dem Rollback läuft wieder das vorherige Image.
Aufgabe 7: Fehlerbild ImagePullBackOff diagnostizieren
Ziel
Du provozierst einen Image-Pull-Fehler und behebst ihn anhand von Events.
Arbeitsauftrag
Erstelle bad-image.yml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: bad-image
namespace: workshop-fundamentals
spec:
replicas: 1
selector:
matchLabels:
app: bad-image
template:
metadata:
labels:
app: bad-image
spec:
containers:
- name: app
image: nginx:this-tag-does-not-exist
ports:
- containerPort: 80
- Wende das Manifest an.
- Prüfe Pod-Status und Events.
- Korrigiere das Image auf
nginx:1.27. - Prüfe erneut.
Aufgabe 8: Fehlerbild CrashLoopBackOff diagnostizieren
Ziel
Du provozierst eine crashende Anwendung, liest Logs und korrigierst das Startkommando.
Arbeitsauftrag
Erstelle crashloop.yml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: crashloop
namespace: workshop-fundamentals
spec:
replicas: 1
selector:
matchLabels:
app: crashloop
template:
metadata:
labels:
app: crashloop
spec:
containers:
- name: app
image: busybox:1.36
command: ["sh", "-c", "echo 'ich beende mich sofort'; exit 1"]
- Wende das Manifest an.
- Prüfe den Pod-Status.
- Lies Logs und vorherige Logs.
- Korrigiere das Kommando so, dass der Container läuft.
- Prüfe erneut.
Aufgabe 9: Betriebsnotiz und Rückbau
Ziel
Du dokumentierst, was erstellt wurde, wie du den Zustand geprüft hast und wie alles zurückgebaut wird.
Arbeitsauftrag
Erstelle notes.md mit:
- Cluster-Kontext
- Namespace
- angewendete Manifeste
- erzeugte Ressourcen
- wichtigste Diagnosebefehle
- bekannte Fehler und Fixes
- Cleanup-Befehl
Teil B – Lösungen und Walkthroughs
Lösung 1: Kontext, Cluster und Namespace prüfen
kubectl config current-context
kubectl cluster-info
kubectl version --client
kubectl get nodes -o wide
kubectl create namespace workshop-fundamentals
kubectl config set-context --current --namespace=workshop-fundamentals
kubectl get pods
Validierung:
kubectl get namespace workshop-fundamentals
kubectl config view --minify --output 'jsonpath={..namespace}'
Mustererklärung:
- Der Kontext bestimmt, mit welchem Cluster
kubectlspricht. - Der Namespace begrenzt die Standard-Sicht von
kubectl, ersetzt aber keine Sicherheitsisolation. kubectl cluster-infozeigt API-Erreichbarkeit.kubectl get nodes -o widezeigt Node-Status und Laufzeitumgebung.
Lösung 2: Kubernetes-Objektmodell lesen
Musterantworten:
| Frage | Antwort |
|---|---|
| API-Gruppe | apps/v1; Ressource aus der Apps-API-Gruppe |
| Ressource | Deployment |
| gewünschter Zustand | unter spec |
| Pod-Labels | app=web, tier=frontend, environment=lab |
| Selector | verbindet Deployment mit den von ihm verwalteten Pods |
Hilfreiche Erkundung:
kubectl explain deployment
kubectl explain deployment.spec
kubectl explain deployment.spec.template.spec.containers
kubectl api-resources | grep -i deployment
Lösung 3: Deployment und Service ausrollen
kubectl apply --dry-run=server -f deployment.yml
kubectl apply -f deployment.yml
kubectl rollout status deployment/web
kubectl apply --dry-run=server -f service.yml
kubectl apply -f service.yml
Prüfung:
kubectl get deployment,replicaset,pod,svc,endpoints,endpointslices
kubectl describe deployment web
kubectl describe svc web
Service-Test:
kubectl run curl --rm -i --tty --restart=Never --image=curlimages/curl:8.8.0 -- http://web
Alternative, falls interaktives kubectl run in deiner Umgebung anders reagiert:
kubectl run curl --restart=Never --image=curlimages/curl:8.8.0 -- sleep 3600
kubectl wait --for=condition=Ready pod/curl --timeout=60s
kubectl exec curl -- curl -s http://web
kubectl delete pod curl
Erwartung:
deployment.apps/webist verfügbar.service/webhat eine ClusterIP.endpoints/webenthält Pod-IP-Adressen.
Lösung 4: Labels und Selectors korrigieren
Falschen Selector anwenden:
kubectl apply -f service.yml
kubectl get svc,endpoints,endpointslices
kubectl describe svc web
Typisches Symptom:
Endpoints: <none>
Diagnose:
kubectl get pods --show-labels
kubectl get svc web -o yaml
Korrektur in service.yml:
selector:
app: web
Danach:
kubectl apply -f service.yml
kubectl get endpoints web
kubectl get endpointslices -l kubernetes.io/service-name=web
Fachliche Erklärung:
Ein Service kennt keine festen Pod-Namen. Er findet Pods über den Selector. Wenn Selector und Pod-Labels nicht zusammenpassen, existiert zwar der Service, aber er hat keine Ziele.
Lösung 5: ConfigMap und Secret einbinden
ConfigMap und Secret anwenden:
kubectl apply -f configmap.yml
kubectl apply -f secret.yml
kubectl get configmap,secret
Deployment-Erweiterung:
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
namespace: workshop-fundamentals
labels:
app: web
tier: frontend
environment: lab
spec:
replicas: 2
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
tier: frontend
environment: lab
spec:
containers:
- name: nginx
image: nginx:1.27
ports:
- containerPort: 80
env:
- name: APP_MODE
valueFrom:
configMapKeyRef:
name: web-config
key: APP_MODE
volumeMounts:
- name: web-secret-volume
mountPath: /etc/demo-secret
readOnly: true
volumes:
- name: web-secret-volume
secret:
secretName: web-secret
Anwenden und prüfen:
kubectl apply -f deployment.yml
kubectl rollout status deployment/web
POD=$(kubectl get pod -l app=web -o jsonpath='{.items[0].metadata.name}')
kubectl exec "$POD" -- printenv APP_MODE
kubectl exec "$POD" -- ls -l /etc/demo-secret
kubectl exec "$POD" -- cat /etc/demo-secret/DEMO_PASSWORD
Fachliche Einordnung:
- ConfigMaps sind für nicht-sensitive Konfiguration gedacht.
- Secrets sind für sensitive Werte gedacht, aber Base64 ist keine Verschlüsselung.
- Echte Secrets gehören nicht in Lernmanifeste oder Klartext-Git.
Lösung 6: Rollout, Skalierung und Rollback
Status prüfen:
kubectl rollout status deployment/web
kubectl get deployment web
Skalieren:
kubectl scale deployment/web --replicas=3
kubectl rollout status deployment/web
kubectl get pods -l app=web
Image ändern:
kubectl set image deployment/web nginx=nginx:1.26
kubectl rollout status deployment/web
kubectl rollout history deployment/web
Aktives Image prüfen:
kubectl get deployment web -o jsonpath='{.spec.template.spec.containers[0].image}{"\n"}'
Rollback:
kubectl rollout undo deployment/web
kubectl rollout status deployment/web
kubectl get deployment web -o jsonpath='{.spec.template.spec.containers[0].image}{"\n"}'
Mustererklärung:
scaleverändertspec.replicas.set imageverändert das Pod-Template und erzeugt dadurch eine neue Revision.rollout undosetzt die vorherige Revision wieder als Zielzustand.
Lösung 7: ImagePullBackOff
Anwenden:
kubectl apply -f bad-image.yml
kubectl get pods -l app=bad-image
Diagnose:
POD=$(kubectl get pod -l app=bad-image -o jsonpath='{.items[0].metadata.name}')
kubectl describe pod "$POD"
kubectl get events --sort-by=.metadata.creationTimestamp
Typischer Befund:
- Image-Tag existiert nicht.
- Events enthalten Meldungen zu
Failed to pull imageoderErrImagePull.
Korrektur:
kubectl set image deployment/bad-image app=nginx:1.27
kubectl rollout status deployment/bad-image
kubectl get pods -l app=bad-image
Oder Datei korrigieren und erneut anwenden:
sed -i 's/nginx:this-tag-does-not-exist/nginx:1.27/' bad-image.yml
kubectl apply -f bad-image.yml
Lösung 8: CrashLoopBackOff
Anwenden:
kubectl apply -f crashloop.yml
kubectl get pods -l app=crashloop
Diagnose:
POD=$(kubectl get pod -l app=crashloop -o jsonpath='{.items[0].metadata.name}')
kubectl describe pod "$POD"
kubectl logs "$POD"
kubectl logs "$POD" --previous
Typischer Befund:
- Container startet.
- Kommando beendet sich mit Exit-Code
1. - Kubernetes startet ihn erneut; dadurch entsteht
CrashLoopBackOff.
Korrektur per Manifest:
apiVersion: apps/v1
kind: Deployment
metadata:
name: crashloop
namespace: workshop-fundamentals
spec:
replicas: 1
selector:
matchLabels:
app: crashloop
template:
metadata:
labels:
app: crashloop
spec:
containers:
- name: app
image: busybox:1.36
command: ["sh", "-c", "echo 'ich bleibe aktiv'; sleep 3600"]
Anwenden:
kubectl apply -f crashloop.yml
kubectl rollout status deployment/crashloop
kubectl get pods -l app=crashloop
Lösung 9: Betriebsnotiz und Rückbau
Muster für notes.md:
# Betriebsnotiz – Fundamentals Lab
## Kontext
- Cluster-Kontext: <aus kubectl config current-context>
- Namespace: workshop-fundamentals
- Datum: <Datum eintragen>
## Manifeste
- deployment.yml
- service.yml
- configmap.yml
- secret.yml
- bad-image.yml
- crashloop.yml
## Validierung
- kubectl get deployment,rs,pod,svc,endpoints,endpointslices
- kubectl rollout status deployment/web
- kubectl describe pod <pod>
- kubectl logs <pod>
## Fehler und Fixes
| Fehler | Ursache | Fix |
| --- | --- | --- |
| Service ohne Endpoints | falscher Selector | Selector auf app=web korrigiert |
| ImagePullBackOff | ungültiger Image-Tag | Image auf nginx:1.27 gesetzt |
| CrashLoopBackOff | Prozess beendet sich mit exit 1 | Kommando auf sleep 3600 geändert |
## Rückbau
kubectl delete namespace workshop-fundamentals
Cleanup:
kubectl delete namespace workshop-fundamentals
Validierung nach Cleanup:
kubectl get namespace workshop-fundamentals
Erwartung: Der Namespace ist gelöscht oder befindet sich kurzzeitig im Status Terminating.
Bewertungscheckliste
| Kriterium | Erfüllt? |
|---|---|
| Kontext vor Anwendung geprüft | ☐ |
| eigener Namespace verwendet | ☐ |
| Deployment-Manifest erklärt | ☐ |
| Service mit Endpoints erstellt | ☐ |
| Selector-Fehler diagnostiziert | ☐ |
| ConfigMap und Secret korrekt eingebunden | ☐ |
| Rollout, Skalierung und Rollback durchgeführt | ☐ |
ImagePullBackOff anhand von Events erklärt |
☐ |
CrashLoopBackOff anhand von Logs erklärt |
☐ |
| Cleanup dokumentiert | ☐ |