Musterlösung: Kubernetes-Prüfung 02 – Intermediate
Schwierigkeitsgrad: Intermediate
Sprache: Deutsch
Typ: Musterlösung / Erwartungshorizont
Diese Datei ist eine passende Lösung zur Prüfung
02-intermediate-kubernetes-pruefung-DE.md.
Die Manifeste sind Lab-Beispiele. Tool- und Cluster-Abhängigkeiten wie StorageClass, Ingress Controller, Gateway API oder NetworkPolicy-Unterstützung müssen im jeweiligen Lab geprüft werden.
1. Hinweise zur Verwendung
Empfohlener Namespace:
export NS=exam-intermediate
Eine vollständige Lösung muss nicht exakt dieselben Images verwenden, solange sie ungefährlich sind, die geforderten Kubernetes-Konzepte zeigen und reproduzierbar validiert werden. Wo ein Tool nicht vorhanden ist, ist eine fachlich korrekte Ersatzbewertung akzeptabel.
2. Teil A: Musterantworten Wissensfragen
1. Deployment, StatefulSet, Job und CronJob
| Ressource | Einsatz |
|---|---|
| Deployment | dauerhaft laufende stateless Services mit Rollout und Rollback |
| StatefulSet | Workloads mit stabiler Identität und stabiler PVC-Zuordnung |
| Job | einmalige oder endlich laufende Aufgabe, zum Beispiel Migration |
| CronJob | zeitgesteuerte wiederkehrende Jobs |
Ein Deployment ist für einmalige Migrationen ungeeignet, weil es Prozesse dauerhaft am Leben halten möchte.
2. Init Container, Sidecar Container und Ephemeral Container
Init Container laufen vor den App-Containern und müssen erfolgreich enden. Sidecars laufen parallel zur App und teilen Netzwerk, Volumes und Pod-Lebenszyklus. Ephemeral Container werden nachträglich für Debugging hinzugefügt und sind nicht Teil des normalen Deployment-Modells.
3. Startup, Readiness und Liveness Probe
| Probe | Wirkung |
|---|---|
| Startup Probe | schützt langsame Starts; bis Erfolg werden Readiness/Liveness zurückgehalten |
| Readiness Probe | entscheidet, ob der Pod Service-Traffic erhält |
| Liveness Probe | entscheidet, ob kubelet den Container neu startet |
4. Risiko aggressiver Liveness Probes
Eine zu aggressive Liveness Probe kann unter Last oder während langsamer Starts gesunde Container neu starten. Dadurch entstehen Crash-Schleifen, unnötige Downtime und verstärkte Last.
5. Wirkung von Requests auf Scheduling und HPA
CPU- und Memory-Requests sind Planungswerte für den Scheduler. CPU-Requests sind außerdem die Basis für CPU-basierte HPA-Auslastung. Fehlende oder unrealistische Requests führen zu schlechter Platzierung, irreführendem Autoscaling und Noisy-Neighbor-Problemen.
6. QoS-Klassen
| QoS | Bedingung | Wirkung |
|---|---|---|
| Guaranteed | CPU und Memory Requests = Limits für alle Container | höchste Stabilität bei Ressourcendruck |
| Burstable | Requests gesetzt, aber nicht identisch zu Limits | mittlere Priorität |
| BestEffort | keine Requests und Limits | zuerst verdrängbar bei Ressourcendruck |
7. LimitRange und ResourceQuota
LimitRange setzt Defaults und Grenzwerte für einzelne Pods oder Container im Namespace. ResourceQuota begrenzt den Gesamtverbrauch eines Namespaces, zum Beispiel Pods, CPU, Memory oder PVCs.
8. nodeSelector, Affinity, Taints und Tolerations
nodeSelector ist eine harte einfache Node-Auswahl. Affinity ist ausdrucksstärker und kann harte oder weiche Regeln formulieren. Taints markieren Nodes so, dass Pods ohne passende Toleration nicht geplant werden. Tolerations erlauben die Platzierung auf tainted Nodes, erzwingen sie aber nicht.
9. Warum ein Pod trotz korrektem Manifest Pending bleiben kann
Typische Ursachen sind Ressourcenmangel, nicht passende Node-Selectoren, Affinity-Regeln, nicht tolerierte Taints, fehlende PVCs oder StorageClass-Probleme. Diagnose erfolgt über kubectl describe pod und Events.
10. Service, EndpointSlice, Pod-Readiness und DNS
Ein Service definiert eine stabile Adresse und einen Selector. EndpointSlices enthalten die tatsächlich erreichbaren Pod-Endpunkte. Nur ready Pods werden für normalen Service-Traffic berücksichtigt. CoreDNS löst Service-Namen auf.
11. DNS-Egress bei Default-Deny-NetworkPolicies
Bei Egress Default Deny sind auch DNS-Anfragen blockiert, sofern sie nicht explizit erlaubt werden. Ohne DNS-Egress können Pods Service-Namen wie backend nicht auflösen.
12. Ingress-Ressource und Ingress Controller
Die Ingress-Ressource beschreibt HTTP-Routing-Regeln. Ein Ingress Controller setzt diese Regeln praktisch als Proxy- oder Load-Balancer-Konfiguration um. Ohne Controller bleibt die Ressource weitgehend wirkungslos.
13. PV, PVC, StorageClass und CSI
| Begriff | Rolle |
|---|---|
| PV | bereitgestelltes Storage-Objekt im Cluster |
| PVC | Anforderung eines Pods oder Workloads an Storage |
| StorageClass | beschreibt dynamische Bereitstellung und Parameter |
| CSI | Schnittstelle/Plugin für Storage-Systeme |
14. Warum hostPath keine Produktionslösung ist
hostPath bindet direkt ein Node-Dateisystem ein. Das ist nicht portabel, bindet Daten an einen Node und kann Sicherheitsrisiken erzeugen. In Labs ist es praktisch, aber kein generischer Produktionsspeicher.
15. Prüfungen bei PVC Pending, Service ohne Endpoints und CreateContainerConfigError
| Fehlerbild | Prüfung |
|---|---|
| PVC Pending | kubectl describe pvc, StorageClass, Provisioner, Events |
| Service ohne Endpoints | Pod-Labels, Service-Selector, Readiness, EndpointSlices |
| CreateContainerConfigError | fehlende ConfigMap/Secret, falscher Key, ungültige Env-/Volume-Referenz |
3. Teil B: Architekturentscheidung
Muster für architecture-decision.md:
# Architekturentscheidung – Shop-Lab
| Anforderung | Entscheidung | Begründung |
| --- | --- | --- |
| HTTP-Frontend dauerhaft und rollend aktualisieren | Deployment | stateless, Replikate, Rollout, Rollback |
| Backend-API mit Health Checks und Ressourcen | Deployment + Service | dauerhaft laufender interner Dienst, Readiness für Traffic, Liveness für echte Defekte |
| Migration einmalig pro Release | Job | erfolgreicher Abschluss ist Zielzustand |
| Cleanup stündlich ohne parallele Jobs | CronJob mit `concurrencyPolicy: Forbid` | zeitgesteuerte Jobs, keine Überlappung |
| Kleiner stateful Workload mit Daten nach Pod-Neuerstellung | StatefulSet mit `volumeClaimTemplates` | stabile Pod-Identität und PVC-Zuordnung |
| Externe Erreichbarkeit | Ingress oder Gateway API | Ressource braucht passenden Controller |
| Namespace vor Übernutzung schützen | LimitRange + ResourceQuota | Defaults und Gesamtgrenzen |
| Frontend darf nur Backend und DNS erreichen | NetworkPolicy Default Deny + Allow-Regeln | Egress und Ingress gezielt erlauben |
4. Teil C: Praxislösung
C1: Namespace, LimitRange und ResourceQuota
namespace.yml
apiVersion: v1
kind: Namespace
metadata:
name: exam-intermediate
labels:
environment: exam
level: intermediate
resources/limitrange.yml
apiVersion: v1
kind: LimitRange
metadata:
name: default-container-limits
namespace: exam-intermediate
spec:
limits:
- type: Container
defaultRequest:
cpu: 100m
memory: 128Mi
default:
cpu: 500m
memory: 512Mi
max:
cpu: "2"
memory: 2Gi
resources/resourcequota.yml
apiVersion: v1
kind: ResourceQuota
metadata:
name: exam-quota
namespace: exam-intermediate
spec:
hard:
pods: "10"
requests.cpu: "2"
requests.memory: 2Gi
limits.cpu: "4"
limits.memory: 4Gi
Anwenden:
kubectl apply -f namespace.yml
kubectl apply -f resources/limitrange.yml
kubectl apply -f resources/resourcequota.yml
kubectl describe limitrange default-container-limits -n exam-intermediate
kubectl describe resourcequota exam-quota -n exam-intermediate
Quota-Verletzung als Beispiel:
apiVersion: v1
kind: Pod
metadata:
name: too-large
namespace: exam-intermediate
spec:
containers:
- name: app
image: busybox:1.36
command: ["sh", "-c", "sleep 3600"]
resources:
requests:
cpu: "3"
memory: 3Gi
limits:
cpu: "3"
memory: 3Gi
Erwartung: Der API Server lehnt den Pod wegen ResourceQuota ab.
C2: Frontend und Backend mit Probes
workloads/backend.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: backend
namespace: exam-intermediate
labels:
app: backend
component: api
environment: exam
spec:
replicas: 2
selector:
matchLabels:
app: backend
template:
metadata:
labels:
app: backend
component: api
environment: exam
spec:
containers:
- name: backend
image: registry.k8s.io/e2e-test-images/agnhost:2.53
args: ["netexec", "--http-port=8080"]
ports:
- name: http
containerPort: 8080
startupProbe:
httpGet:
path: /healthz
port: 8080
failureThreshold: 30
periodSeconds: 2
readinessProbe:
httpGet:
path: /healthz
port: 8080
periodSeconds: 5
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 15
periodSeconds: 10
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 256Mi
workloads/frontend.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
namespace: exam-intermediate
labels:
app: frontend
component: web
environment: exam
spec:
replicas: 1
selector:
matchLabels:
app: frontend
template:
metadata:
labels:
app: frontend
component: web
environment: exam
spec:
containers:
- name: frontend
image: curlimages/curl:8.8.0
command: ["sh", "-c", "sleep 3600"]
readinessProbe:
exec:
command: ["sh", "-c", "command -v curl >/dev/null"]
periodSeconds: 10
livenessProbe:
exec:
command: ["sh", "-c", "test -d /tmp"]
initialDelaySeconds: 10
periodSeconds: 20
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
cpu: 200m
memory: 128Mi
networking/services.yml
apiVersion: v1
kind: Service
metadata:
name: backend
namespace: exam-intermediate
spec:
selector:
app: backend
ports:
- name: http
port: 8080
targetPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: frontend
namespace: exam-intermediate
spec:
selector:
app: frontend
ports:
- name: http
port: 80
targetPort: 8080
Anwenden und prüfen:
kubectl apply -f workloads/backend.yml
kubectl apply -f workloads/frontend.yml
kubectl apply -f networking/services.yml
kubectl rollout status deployment/backend -n exam-intermediate
kubectl rollout status deployment/frontend -n exam-intermediate
kubectl get deploy,pod,svc,endpoints,endpointslices -n exam-intermediate
Readiness vs. Liveness:
- Readiness nimmt Pods aus dem Service-Traffic, ohne sie neu zu starten.
- Liveness startet Container neu und darf nur echte, nicht selbstheilende Defekte erkennen.
C3: Job und CronJob
workloads/migration-job.yml
apiVersion: batch/v1
kind: Job
metadata:
name: migration
namespace: exam-intermediate
spec:
backoffLimit: 2
template:
spec:
restartPolicy: OnFailure
containers:
- name: migration
image: busybox:1.36
command: ["sh", "-c", "echo Migration startet; sleep 3; echo Migration erfolgreich"]
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
cpu: 200m
memory: 128Mi
workloads/cleanup-cronjob.yml
apiVersion: batch/v1
kind: CronJob
metadata:
name: cleanup
namespace: exam-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 fertig"]
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
cpu: 200m
memory: 128Mi
Prüfung:
kubectl apply -f workloads/migration-job.yml
kubectl apply -f workloads/cleanup-cronjob.yml
kubectl get job,cronjob,pod -n exam-intermediate
kubectl logs job/migration -n exam-intermediate
C4: Scheduling prüfen
Node labeln:
NODE=$(kubectl get nodes -o jsonpath='{.items[0].metadata.name}')
kubectl label node "$NODE" exam-role=apps
kubectl get nodes --show-labels | grep exam-role
Pod mit passendem Selector:
apiVersion: v1
kind: Pod
metadata:
name: scheduled-ok
namespace: exam-intermediate
spec:
nodeSelector:
exam-role: apps
containers:
- name: app
image: busybox:1.36
command: ["sh", "-c", "sleep 3600"]
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
cpu: 100m
memory: 128Mi
Pod mit nicht passendem Selector:
apiVersion: v1
kind: Pod
metadata:
name: scheduled-pending
namespace: exam-intermediate
spec:
nodeSelector:
exam-role: does-not-exist
containers:
- name: app
image: busybox:1.36
command: ["sh", "-c", "sleep 3600"]
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
cpu: 100m
memory: 128Mi
Taint und Toleration:
kubectl taint node "$NODE" dedicated=apps:NoSchedule
Pod mit Toleration:
apiVersion: v1
kind: Pod
metadata:
name: tolerated
namespace: exam-intermediate
spec:
nodeSelector:
exam-role: apps
tolerations:
- key: dedicated
operator: Equal
value: apps
effect: NoSchedule
containers:
- name: app
image: busybox:1.36
command: ["sh", "-c", "sleep 3600"]
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
cpu: 100m
memory: 128Mi
Validierung:
kubectl get pods -o wide -n exam-intermediate
kubectl describe pod scheduled-pending -n exam-intermediate
kubectl get events -n exam-intermediate --sort-by=.metadata.creationTimestamp
Rückbau der Node-Änderungen:
kubectl taint node "$NODE" dedicated=apps:NoSchedule-
kubectl label node "$NODE" exam-role-
C5: NetworkPolicy Default Deny plus Erlaubnisse
networking/networkpolicies.yml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny
namespace: exam-intermediate
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-dns-egress
namespace: exam-intermediate
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend-egress-to-backend
namespace: exam-intermediate
spec:
podSelector:
matchLabels:
app: frontend
policyTypes:
- Egress
egress:
- to:
- podSelector:
matchLabels:
app: backend
ports:
- protocol: TCP
port: 8080
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-backend-ingress-from-frontend
namespace: exam-intermediate
spec:
podSelector:
matchLabels:
app: backend
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 8080
Prüfung:
kubectl apply -f networking/networkpolicies.yml
kubectl get networkpolicy -n exam-intermediate
FRONTEND=$(kubectl get pod -l app=frontend -n exam-intermediate -o jsonpath='{.items[0].metadata.name}')
kubectl exec "$FRONTEND" -n exam-intermediate -- nslookup backend
kubectl exec "$FRONTEND" -n exam-intermediate -- curl -s --max-time 5 http://backend:8080/hostname
CNI-Einordnung:
kubectl get pods -A | grep -Ei 'calico|cilium|weave|antrea|flannel|kindnet'
Eine gute Lösung dokumentiert, ob das konkrete CNI NetworkPolicies durchsetzt. Flannel ohne Policy-Erweiterung ist beispielsweise anders zu bewerten als Calico oder Cilium.
C6: Ingress oder Gateway API
Controller prüfen:
kubectl get ingressclass
kubectl get gatewayclass 2>/dev/null || true
kubectl get pods -A | grep -Ei 'ingress|gateway|nginx|traefik|envoy|haproxy'
Beispiel networking/ingress-or-gateway.yml als Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: shop
namespace: exam-intermediate
spec:
rules:
- host: shop.localtest.me
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: backend
port:
number: 8080
Prüfung:
kubectl apply -f networking/ingress-or-gateway.yml
kubectl describe ingress shop -n exam-intermediate
kubectl get ingress shop -n exam-intermediate
Wenn kein Controller vorhanden ist:
Im Lab ist kein Ingress- oder Gateway-Controller installiert. Die Ressource kann vom API Server angenommen werden, hat aber keine praktische Routing-Wirkung, weil kein Controller sie in Proxy- oder Load-Balancer-Konfiguration übersetzt.
Gateway-API-Beispiel, falls Gateway API vorhanden ist
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: shop
namespace: exam-intermediate
spec:
parentRefs:
- name: shared-gateway
namespace: gateway-system
hostnames:
- shop.localtest.me
rules:
- backendRefs:
- name: backend
port: 8080
C7: PVC und StatefulSet
StorageClasses prüfen:
kubectl get storageclass
storage/statefulset.yml
apiVersion: v1
kind: Service
metadata:
name: data-demo
namespace: exam-intermediate
spec:
clusterIP: None
selector:
app: data-demo
ports:
- name: dummy
port: 80
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: data-demo
namespace: exam-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
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
cpu: 100m
memory: 128Mi
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 1Gi
Test:
kubectl apply -f storage/statefulset.yml
kubectl rollout status statefulset/data-demo -n exam-intermediate
kubectl exec data-demo-0 -n exam-intermediate -- sh -c 'echo persistenz-test > /data/test.txt'
kubectl delete pod data-demo-0 -n exam-intermediate
kubectl wait --for=condition=Ready pod/data-demo-0 -n exam-intermediate --timeout=120s
kubectl exec data-demo-0 -n exam-intermediate -- cat /data/test.txt
Erwartung: Die Datei ist nach Pod-Neuerstellung weiterhin vorhanden.
C8: Helm und Kustomize rendern
Beispiel Kustomize
Struktur:
packaging/kustomize/
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 packaging/kustomize/overlays/dev > packaging/kustomize-output.md
kubectl apply -k packaging/kustomize/overlays/dev --dry-run=server
Beispiel Helm
helm create packaging/webchart
helm lint packaging/webchart
helm template web packaging/webchart > packaging/helm-output.md
Vergleich:
| Kriterium | Helm | Kustomize |
|---|---|---|
| Modell | Chart mit Templates und Values | Base/Overlay auf YAML-Basis |
| Stärke | parametrisierbare Pakete | gute Reviewbarkeit ohne Template-Sprache |
| Risiko | Templates können komplex und schwer prüfbar werden | Overlay-Ketten können unübersichtlich werden |
| Pflichtprüfung | helm lint, helm template |
kubectl kustomize, dry-run |
5. Teil D: Troubleshooting-Parcours
Muster für troubleshooting.md:
| Fehlerbild | Symptom | Diagnose | Ursache | Fix | Validierung |
|---|---|---|---|---|---|
Pod Pending wegen falschem nodeSelector |
Pod wird nicht geplant | kubectl describe pod, Events |
kein Node erfüllt Selector | Selector korrigieren oder Node passend labeln | Pod erhält Node in kubectl get pod -o wide |
ImagePullBackOff |
Pod kann Image nicht ziehen | kubectl describe pod, Events |
falscher Image-Tag oder Registry | gültiges Image setzen | Pod wird Running oder Deployment verfügbar |
CrashLoopBackOff |
Container startet wiederholt neu | kubectl logs --previous, Exit-Code |
Startkommando oder App-Konfig fehlerhaft | Kommando/Config korrigieren | Restart-Zähler steigt nicht weiter |
PVC Pending |
PVC wird nicht gebunden | kubectl describe pvc, kubectl get storageclass |
StorageClass fehlt oder Provisioner fehlt | StorageClass korrigieren oder bereitstellen | PVC Bound |
| Service ohne Endpoints | Service existiert, aber keine Ziele | kubectl get endpoints, Labels, Selector |
Selector passt nicht zu Pod-Labels | Selector oder Labels korrigieren | EndpointSlices enthalten Pod-IPs |
Nützliche Standardbefehle:
kubectl get all -n exam-intermediate
kubectl get pods -o wide -n exam-intermediate
kubectl describe pod <pod> -n exam-intermediate
kubectl get events -n exam-intermediate --sort-by=.metadata.creationTimestamp
kubectl logs <pod> -n exam-intermediate
kubectl logs <pod> -n exam-intermediate --previous
kubectl get svc,endpoints,endpointslices -n exam-intermediate
kubectl describe pvc <pvc> -n exam-intermediate
6. Erwartete Abgabestruktur
02-intermediate-abgabe/
answers.md
architecture-decision.md
workloads/
frontend.yml
backend.yml
migration-job.yml
cleanup-cronjob.yml
resources/
limitrange.yml
resourcequota.yml
networking/
services.yml
networkpolicies.yml
ingress-or-gateway.yml
storage/
statefulset.yml
packaging/
kustomize-output.md
helm-output.md
troubleshooting.md
evidence.md
cleanup.md
Muster für evidence.md:
# Evidence – Intermediate
## Kontext
- Namespace: exam-intermediate
- CNI: <ermittelt>
- StorageClass: <ermittelt oder nicht vorhanden>
- Ingress/Gateway Controller: <ermittelt oder nicht vorhanden>
## Prüfungen
```bash
kubectl get deploy,job,cronjob,pod,svc,endpoints,endpointslices,pvc -n exam-intermediate
kubectl get networkpolicy -n exam-intermediate
kubectl get events -n exam-intermediate --sort-by=.metadata.creationTimestamp
```
## Ergebnisse
- Backend verfügbar: ja/nein
- Frontend kann Backend erreichen: ja/nein
- DNS funktioniert nach DNS-Allow-Policy: ja/nein
- StatefulSet-Persistenz geprüft: ja/nein
- Troubleshooting-Parcours dokumentiert: ja/nein
7. Cleanup
kubectl delete namespace exam-intermediate
Falls Node-Änderungen durchgeführt wurden, müssen sie vorher oder zusätzlich zurückgebaut werden:
NODE=<node-name>
kubectl taint node "$NODE" dedicated=apps:NoSchedule- || true
kubectl label node "$NODE" exam-role- || true
8. Bewertungs- und Prüferhinweise
Eine sehr gute Intermediate-Lösung:
- wählt Workload-Ressourcen fachlich korrekt,
- trennt Readiness, Liveness und Startup sauber,
- nutzt Requests, Limits, LimitRange und ResourceQuota sinnvoll,
- interpretiert Scheduling-Events statt zu raten,
- prüft NetworkPolicies inklusive DNS und CNI-Wirkung,
- erklärt Ingress/Gateway Controller-Abhängigkeiten,
- testet PVC/StatefulSet oder dokumentiert fehlende StorageClass korrekt,
- rendert Helm und Kustomize vor dem Anwenden,
- dokumentiert alle fünf Troubleshooting-Fälle methodisch,
- baut Node-Labels und Taints sauber zurück.