Workshop wiki · German

Musterlösung: Kubernetes-Prüfung 02 – Intermediate

Schwierigkeitsgrad: Intermediate Sprache: Deutsch Typ: Musterlösung / Erwartungshorizont

Workshop examples as ZIP files
Learning progress in the web app

Mark chapters as read, view reading progress and check off practice modules after enabling the optional web app. Workshop progress is calculated from chapters across all document pages. Your choices stay on this device; there is no account or server sync. Installation is not required. Withdrawing your choice in Privacy settings deletes the progress.

Reading progress0%
0%
0 / 8 chapters read
Other language versionEnglish ↗Greek ↗

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:

bash
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.


01 / 08

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

02 / 08

3. Teil B: Architekturentscheidung

Muster für architecture-decision.md:

markdown
# 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 |

03 / 08

4. Teil C: Praxislösung

C1: Namespace, LimitRange und ResourceQuota

namespace.yml

yaml
apiVersion: v1
kind: Namespace
metadata:
  name: exam-intermediate
  labels:
    environment: exam
    level: intermediate

resources/limitrange.yml

yaml
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

yaml
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:

bash
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:

yaml
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

yaml
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

yaml
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

yaml
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:

bash
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

yaml
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

yaml
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:

bash
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:

bash
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:

yaml
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:

yaml
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:

bash
kubectl taint node "$NODE" dedicated=apps:NoSchedule

Pod mit Toleration:

yaml
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:

bash
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:

bash
kubectl taint node "$NODE" dedicated=apps:NoSchedule-
kubectl label node "$NODE" exam-role-

C5: NetworkPolicy Default Deny plus Erlaubnisse

networking/networkpolicies.yml

yaml
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:

bash
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:

bash
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:

bash
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

yaml
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:

bash
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:

markdown
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

yaml
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:

bash
kubectl get storageclass

storage/statefulset.yml

yaml
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:

bash
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:

text
packaging/kustomize/
  base/
    deployment.yml
    service.yml
    kustomization.yml
  overlays/dev/
    kustomization.yml

base/kustomization.yml:

yaml
resources:
  - deployment.yml
  - service.yml

overlays/dev/kustomization.yml:

yaml
resources:
  - ../../base
namePrefix: dev-
labels:
  - pairs:
      environment: dev
images:
  - name: nginx
    newTag: "1.27"

Rendern:

bash
kubectl kustomize packaging/kustomize/overlays/dev > packaging/kustomize-output.md
kubectl apply -k packaging/kustomize/overlays/dev --dry-run=server

Beispiel Helm

bash
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

04 / 08

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:

bash
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

05 / 08

6. Erwartete Abgabestruktur

text
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:

markdown
# 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

06 / 08

7. Cleanup

bash
kubectl delete namespace exam-intermediate

Falls Node-Änderungen durchgeführt wurden, müssen sie vorher oder zusätzlich zurückgebaut werden:

bash
NODE=<node-name>
kubectl taint node "$NODE" dedicated=apps:NoSchedule- || true
kubectl label node "$NODE" exam-role- || true

07 / 08

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.
08 / 08

K8S · Orthevs Academy

31 modules as one continuous learning path.

The sequence remains unchanged: from the lab skeleton through technical foundations and operating models to final troubleshooting. The technical directory names are deliberately preserved.

Orthevs – Engineering the foundation for what comes next.

Orthevs as an app

Install Orthevs

The Orthevs web app can be installed on supported mobile devices and desktop browsers.

iPhone and iPad

Open Orthevs in Safari. Tap Share, then Add to Home Screen. Enable Open as Web App if offered, then tap Add.

Android

For the web app, open the browser menu and choose Install app or Add to Home screen. Confirm the installation.

Desktop browser

Open the browser menu or the install icon in the address bar, then choose Install app or Add to Dock.

Web app installation depends on your browser. If no install prompt appears, follow the browser steps shown above.