Eine übersichtliche Referenz der Architekturmuster, die in der CKAD-Prüfung getestet werden. Von oben nach unten lesen oder zu einem Abschnitt springen.
Anwendungsumgebung, Konfiguration und Sicherheit
Erstellen Sie eine ConfigMap oder ein generisches Secret aus Befehlszeilen-Schlüssel-Wert-Paaren.
Verwenden Sie `kubectl create configmap <name> --from-literal=<key>=<value>` oder `kubectl create secret generic <name> --from-literal=<key>=<value>`.
Warum: `--from-literal` dient der direkten Schlüssel-Wert-Eingabe. Verwenden Sie das Flag mehrmals für mehrere Schlüssel. Dies ist schneller als das Erstellen einer YAML-Datei für einfache Fälle.
Injizieren Sie alle Schlüssel-Wert-Paare aus einer ConfigMap oder einem Secret als Umgebungsvariablen in einen Container.
Verwenden Sie in der Container-Spezifikation `envFrom` mit `configMapRef` oder `secretRef`. Beispiel: `envFrom: [{configMapRef: {name: my-config}}]`.
Warum: `envFrom` ist ein Massenvorgang, der alle Schlüssel aus der Quelle auf Umgebungsvariablen abbildet. Dies vermeidet das manuelle Auflisten jedes Schlüssels.
Warum: `valueFrom` bietet eine selektive Injektion und ermöglicht das Zuordnen des Quellschlüssels zu einem anderen Namen der Umgebungsvariablen.
Binden Sie eine ConfigMap oder ein Secret als Dateien in einen Pod ein, um Live-Updates zu ermöglichen.
Definieren Sie ein `volume` vom Typ `configMap` oder `secret`. Binden Sie es mit `volumeMounts` in den Container ein. Die Dateien werden nach den Schlüsseln benannt.
Warum: Eingebundene Dateien aus ConfigMaps/Secrets werden automatisch aktualisiert, wenn sich die Quelle ändert. Umgebungsvariablen nicht, was einen Neustart des Pods erfordert.
Setzen Sie bewährte Sicherheitspraktiken durch: Verhindern Sie das Ausführen als Root, machen Sie das Root-Dateisystem schreibgeschützt oder geben Sie eine Benutzer-ID an.
Verwenden Sie `securityContext` auf Pod- oder Containerebene. Setzen Sie `runAsNonRoot: true`, `readOnlyRootFilesystem: true` und/oder `runAsUser: <UID>`.
Warum: SecurityContext bietet eine feingranulare, deklarative Kontrolle über Container-Privilegien, die für die Härtung von Anwendungen und die Einhaltung von Sicherheitsrichtlinien unerlässlich ist.
Erteilen Sie einem Pod minimale Berechtigungen für den Zugriff auf die Kubernetes API.
1. Erstellen Sie ein benutzerdefiniertes `ServiceAccount`. 2. Erstellen Sie eine `Role` mit nur den notwendigen API-Berechtigungen (z. B. Pods auflisten). 3. Erstellen Sie ein `RoleBinding`, um ServiceAccount und Role zu verknüpfen. 4. Weisen Sie den ServiceAccount dem Pod über `spec.serviceAccountName` zu.
Warum: Folgt dem Prinzip der geringsten Rechte und minimiert die Angriffsfläche, falls ein Pod kompromittiert wird.
Verhindern Sie das automatische Mounten eines ServiceAccount-Tokens in einen Pod, der keinen API-Zugriff benötigt.
Setzen Sie `automountServiceAccountToken: false` in der Pod-Spezifikation oder direkt im ServiceAccount.
Warum: Reduziert die Angriffsfläche, indem keine API-Anmeldeinformationen an Container bereitgestellt werden, die diese nicht benötigen.
Erstellen Sie ein Secret zur Verwendung bei der TLS-Terminierung für einen Ingress oder einen anderen sicheren Dienst.
Verwenden Sie `kubectl create secret tls <secret-name> --cert=<path/to/cert.pem> --key=<path/to/key.pem>`.
Warum: Dies erstellt ein Secret des richtigen Typs `kubernetes.io/tls` mit den von Ingress-Controllern erwarteten Standarddaten-Schlüsseln `tls.crt` und `tls.key`.
Exponieren Sie Pod-Metadaten (wie Name, Namespace, Labels oder Node-IP) für einen Container.
Verwenden Sie die Downward API, um Metadaten als Umgebungsvariablen oder Dateien in einem `downwardAPI`-Volume zu projizieren. Beispiel: `valueFrom: {fieldRef: {fieldPath: metadata.name}}`.
Warum: Ermöglicht Containern, selbstbewusst zu sein, ohne die Kubernetes API abfragen zu müssen, was die Konfiguration vereinfacht und RBAC-Anforderungen reduziert.
Legen Sie Standard-CPU-/Speicheranforderungen und -limits für alle Pods in einem Namespace fest.
Erstellen Sie ein `LimitRange`-Objekt im Namespace. Definieren Sie `default`- und `defaultRequest`-Werte für Ressourcen.
Warum: Stellt sicher, dass alle Pods Ressourcenbeschränkungen haben, was die Planung und Stabilität verbessert, auch wenn Entwickler vergessen, diese anzugeben. Funktioniert im Zusammenspiel mit ResourceQuota.
Begrenzen Sie die Gesamtmenge an Ressourcen (CPU, Speicher, Objektanzahl), die in einem Namespace verbraucht werden können.
Erstellen Sie ein `ResourceQuota`-Objekt. Definieren Sie harte Limits in `spec.hard`, z. B. `requests.cpu: "4"`, `pods: "10"`.
Warum: Verhindert, dass ein Namespace oder Team alle Cluster-Ressourcen verbraucht, und gewährleistet eine faire Ressourcenverteilung.
Anwendungsdesign und -erstellung
Führen Sie erforderliche Aufgaben (z. B. auf eine Datenbank warten, Migrationen ausführen, Daten abrufen) aus, bevor die Hauptanwendung startet.
Definieren Sie einen oder mehrere `initContainers` in der Pod-Spezifikation. Sie werden sequentiell bis zum Abschluss ausgeführt, bevor die Hauptanwendungscontainer starten.
Warum: Entkoppelt die Setup-Logik vom Anwendungscontainer und stellt sicher, dass Abhängigkeiten erfüllt sind, bevor die Anwendung startet.
Erweitern Sie einen primären Anwendungscontainer mit Hilfsfunktionen wie Logging, Monitoring oder Proxying.
Fügen Sie der Pod-Spezifikation einen zweiten Container (den Sidecar) hinzu. Beide Container teilen sich Ressourcen wie Netzwerk und Volumes.
Warum: Erweitert die Funktionalität, ohne den Hauptanwendungscode zu ändern, und fördert die Trennung von Belangen.
Teilen Sie ein Verzeichnis zum Lesen/Schreiben zwischen Containern im selben Pod.
Definieren Sie ein `emptyDir`-Volume in der Pod-Spezifikation und binden Sie es in alle erforderlichen Container ein.
Warum: `emptyDir` bietet ein einfaches, kurzlebiges Speichervolume, das für die Lebensdauer des Pods existiert und perfekt für die gemeinsame Datennutzung innerhalb eines Pods ist.
Überschreiben Sie das Standard-ENTRYPOINT und/oder CMD eines Container-Images.
Verwenden Sie in der Container-Spezifikation `command`, um ENTRYPOINT zu überschreiben, und `args`, um CMD zu überschreiben. `command: ["/bin/sh"], args: ["-c", "echo hello"]`.
Warum: Bietet volle Kontrolle über den Container-Startbefehl aus der Pod-Definition, nützlich zur Anpassung generischer Images.
Führen Sie eine endliche Aufgabe bis zum Abschluss aus und steuern Sie Parallelität sowie die Anzahl erfolgreicher Abschlüsse.
Verwenden Sie eine `Job`-Ressource. Legen Sie `spec.completions` für die angestrebte Erfolgsanzahl und `spec.parallelism` für die Anzahl gleichzeitiger Pods fest. Verwenden Sie `spec.backoffLimit`, um Wiederholungen zu steuern.
Warum: Jobs sind für Aufgaben konzipiert, die bis zum Abschluss ausgeführt werden, im Gegensatz zu langlaufenden Deployments. Diese Einstellungen sind entscheidend für die Verwaltung von Batch-Workloads.
Planen Sie eine wiederkehrende Aufgabe mit Cron-Syntax und steuern Sie, wie sich überlappende Jobs verhalten sollen.
Verwenden Sie eine `CronJob`-Ressource. Definieren Sie das `spec.schedule` im Cron-Format (z. B. `*/5 * * * *`). Setzen Sie `spec.concurrencyPolicy` auf `Allow`, `Forbid` oder `Replace`.
Warum: Automatisiert geplante Aufgaben. `concurrencyPolicy` ist entscheidend, um überlappende Ausführungen (`Forbid`) zu verhindern oder veraltete zu ersetzen (`Replace`).
Erstellen Sie schnell ein YAML-Manifest für eine Ressource, ohne sie im Cluster zu erstellen.
Verwenden Sie die Flags `--dry-run=client -o yaml` mit imperativen Befehlen. Beispiel: `kubectl run nginx --image=nginx --dry-run=client -o yaml > pod.yaml`.
Warum: Spart Zeit durch das Gerüstbauen eines gültigen Manifests, das angepasst und dann deklarativ angewendet werden kann.
Anwendungsbereitstellung
Aktualisieren, skalieren, den Status überprüfen, den Verlauf anzeigen und ein Deployment imperativ zurücksetzen.
Verwenden Sie `kubectl set image`, `kubectl scale`, `kubectl rollout status`, `kubectl rollout history` und `kubectl rollout undo`.
Warum: Dies sind die wichtigsten imperativen Befehle zur Verwaltung des Lebenszyklus einer bereitgestellten Anwendung während der Entwicklung und Fehlerbehebung.
Steuern Sie die Geschwindigkeit und Sicherheit eines Deployment-Updates, um die Verfügbarkeit zu gewährleisten.
Konfigurieren Sie in `spec.strategy.rollingUpdate` `maxSurge` (wie viele zusätzliche Pods erstellt werden können) und `maxUnavailable` (wie viele Pods gleichzeitig nicht verfügbar sein können).
Warum: Das Ausbalancieren von `maxSurge` und `maxUnavailable` ist entscheidend für die Verwaltung von Kapazität vs. Ressourcennutzung während Updates. Für keine Ausfallzeit muss `maxUnavailable` kleiner sein als `replicas`.
Stellen Sie sicher, dass niemals zwei Versionen einer Anwendung gleichzeitig laufen, indem Sie alle alten Pods beenden, bevor Sie neue erstellen.
Setzen Sie `spec.strategy.type: Recreate` im Deployment.
Warum: Garantiert, dass alte und neue Versionen nicht koexistieren, was für Anwendungen notwendig ist, die nicht mit zwei verschiedenen Versionen umgehen können, die auf dieselben Daten zugreifen. Diese Strategie führt zu Ausfallzeiten.
Nehmen Sie mehrere Änderungen an einem aktiven Deployment vor, ohne für jede Änderung einen zwischenzeitlichen Rollout auszulösen.
Verwenden Sie `kubectl rollout pause deployment/<name>`, wenden Sie Änderungen an, dann `kubectl rollout resume deployment/<name>`.
Warum: Konsolidiert mehrere Updates in einem einzigen Rollout-Ereignis, wodurch unnötige Wechsel und Race Conditions verhindert werden.
Begrenzen Sie die Anzahl der alten ReplicaSets, die für ein Deployment beibehalten werden, um etcd-Speicherplatz zu sparen.
Setzen Sie `spec.revisionHistoryLimit` auf die gewünschte Anzahl der zu behaltenden Revisionen (z. B. 3). Standard ist 10.
Warum: Ein niedrigeres Limit reduziert die etcd-Unordnung. Ein Setzen auf `0` deaktiviert die Rollback-Funktion vollständig.
Dokumentieren Sie den Grund für ein Deployment-Update, damit er im Revisionsverlauf erscheint.
Fügen Sie dem Deployment-Manifest eine `kubernetes.io/change-cause`-Annotation hinzu. Beispiel: `kubectl annotate deployment/nginx kubernetes.io/change-cause="update to 1.20"`.
Warum: Bietet wertvollen Kontext beim Anzeigen des Rollout-Verlaufs (`kubectl rollout history`), was die Identifizierung der Revision erleichtert, auf die zurückgesetzt werden soll.
Stellen Sie eine neue Anwendungsversion neben der alten bereit und wechseln Sie den Datenverkehr sofort und ohne Ausfallzeit.
Verwenden Sie zwei Deployments (z. B. `app-blue`, `app-green`) mit unterschiedlichen Versionslabels. Ein einziger Service wählt die aktive Version über seinen `selector` aus. Zum Umschalten verwenden Sie `kubectl patch service`, um den Selector auf das neue Versionslabel zu aktualisieren.
Warum: Bietet sofortige, risikoarme Releases und sofortige Rollback-Fähigkeit durch einfaches Zurücksetzen des Service-Selectors.
Leiten Sie einen kleinen Prozentsatz des Datenverkehrs an eine neue Anwendungsversion zum Testen in der Produktion um.
Verwenden Sie zwei Deployments (stabil, Canary), die dasselbe Selektor-Label teilen. Ein Service zielt auf beide ab. Steuern Sie den Verkehrsanteil durch das Verhältnis der Replicas (z. B. 9 stabile Replicas, 1 Canary für 10% des Datenverkehrs).
Warum: Eine einfache Methode zur Durchführung von Canary-Releases ohne Service Mesh, die ein kontrolliertes, risikoarmes Testen neuer Funktionen ermöglicht. Die Verkehrsverteilung ist annähernd.
Dienste und Netzwerke
Exponieren Sie eine Reihe von Pods nur für die Kommunikation innerhalb des Clusters.
Verwenden Sie einen Service mit `type: ClusterIP`. Dies ist der Standardtyp.
Warum: `ClusterIP` bietet eine stabile interne IP-Adresse und einen DNS-Namen für einen Service, wodurch einzelne Pod-IPs abstrahiert werden.
Exponieren Sie einen Service auf einem statischen Port an der IP-Adresse jedes Knotens.
Verwenden Sie einen Service mit `type: NodePort`. K8s weist einen Port aus einem Bereich zu (Standard: 30000-32767).
Warum: Nützlich für die Entwicklung oder wenn kein externer Load Balancer verfügbar ist. Datenverkehr an `<NodeIP>:<NodePort>` wird an den Service weitergeleitet.
Leiten Sie externen HTTP/S-Verkehr basierend auf Hostname oder URL-Pfad an interne Services weiter.
Erstellen Sie eine `Ingress`-Ressource. Definieren Sie `rules` für Hosts und `http.paths`, um diese Backend-Services zuzuordnen. Konfigurieren Sie TLS mit `spec.tls`, das auf ein TLS Secret verweist.
Warum: Ingress bietet L7-Routing, konsolidiert mehrere Services unter einer externen IP und entlastet die TLS-Terminierung.
Beschränken Sie den Netzwerkverkehr zu und von Pods basierend auf Labels, Namespaces oder IP-Blöcken.
Erstellen Sie eine `NetworkPolicy`, die Pods mit `podSelector` anspricht. Definieren Sie `ingress`- und/oder `egress`-Regeln, um spezifischen Datenverkehr zuzulassen. Standardmäßig verweigert das Anwenden einer Richtlinie auf einen Pod den gesamten Datenverkehr, der nicht explizit zugelassen ist.
Warum: NetworkPolicies sind grundlegend für die Netzwerksegmentierung und die Implementierung eines Zero-Trust-Sicherheitsmodells in Kubernetes.
Blockieren Sie standardmäßig den gesamten Ingress- und Egress-Verkehr für alle Pods in einem Namespace.
Erstellen Sie eine NetworkPolicy mit einem leeren `podSelector: {}` und leeren Ingress-/Egress-Regeln. Beispiel: `podSelector: {}, policyTypes: [Ingress, Egress]`.
Warum: Etabliert eine sichere Baseline, bei der der gesamte Datenverkehr verweigert wird, es sei denn, er wird explizit durch andere, spezifischere NetworkPolicies zugelassen.
Stellen Sie einen stabilen DNS-Eintrag bereit, der direkt zu allen Pod-IPs auflöst, ohne eine virtuelle IP für den Lastausgleich.
Erstellen Sie einen Service mit `spec.clusterIP: None`.
Warum: Unerlässlich für zustandsbehaftete Anwendungen (wie StatefulSets) oder Peer-to-Peer-Systeme, die bestimmte Pods direkt entdecken und mit ihnen kommunizieren müssen.
Stellen Sie sicher, dass Backend-Pods die ursprüngliche Client-IP für Datenverkehr von einem NodePort- oder LoadBalancer-Service sehen.
Setzen Sie `spec.externalTrafficPolicy: Local` im Service.
Warum: Die Standardrichtlinie (`Cluster`) verschleiert die Quell-IP über Netzwerkadressübersetzung. `Local` bewahrt sie, kann aber zu einer ungleichmäßigen Verkehrsverteilung führen, wenn Pods nicht auf allen Nodes vorhanden sind.
Stellen Sie sicher, dass alle Anfragen von einem bestimmten Client an denselben Pod gesendet werden.
Setzen Sie im Service `spec.sessionAffinity: ClientIP`.
Warum: Bietet 'Sticky Sessions', die für ältere Anwendungen erforderlich sind, die den Sitzungsstatus im Speicher auf einem bestimmten Pod speichern.
Ein Pod in einem Namespace muss mit einem Service in einem anderen Namespace kommunizieren.
Verwenden Sie den erweiterten DNS-Namen: `<service-name>.<namespace-name>.svc.cluster.local` oder die Kurzform `<service-name>.<namespace-name>`.
Warum: Einfache Servicenamen werden nur innerhalb desselben Namespaces aufgelöst. Die Kommunikation über Namespaces hinweg erfordert die Angabe des Ziel-Namespaces in der DNS-Abfrage.
Anwendungsbeobachtbarkeit und Wartung
Definieren Sie Gesundheitsprüfungen zur Verwaltung des Pod-Lebenszyklus: Neustart bei Fehler vs. Entfernen aus dem Dienst.
`livenessProbe`: Startet den Container neu, wenn die Prüfung fehlschlägt. `readinessProbe`: Entfernt den Pod aus den Service-Endpunkten, wenn die Prüfung fehlschlägt. `startupProbe`: Deaktiviert andere Prüfungen, bis der Container seinen Start abgeschlossen hat.
Warum: Korrekt konfigurierte Probes sind unerlässlich für die Selbstheilung von Anwendungen und das Erreichen von Zero-Downtime-Deployments.
Diagnostizieren Sie, warum ein Pod in einem nicht-Running-Zustand (z. B. Pending, ContainerCreating, CrashLoopBackOff) feststeckt.
Verwenden Sie `kubectl describe pod <pod-name>`. Der Abschnitt `Events` liefert wichtige Hinweise vom Scheduler (Ressourcenprobleme), kubelet (Image-Pull-Fehler) oder der Container-Laufzeitumgebung.
Warum: `describe` ist der wichtigste Befehl zum Verständnis von Pod-Lebenszyklusproblemen, die auftreten, bevor die Anwendung startet oder etwas protokolliert.
Überprüfen Sie die Logs eines Containers, der abgestürzt ist und sich nun in einer Neustartschleife befindet (CrashLoopBackOff).
Verwenden Sie `kubectl logs <pod-name> --previous`.
Warum: Das Flag `--previous` zeigt die Logs der letzten beendeten Instanz des Containers an, die den Fehler enthalten, der zum Absturz geführt hat.
Zeigen Sie Logs von allen Pods, die einem Label-Selektor entsprechen, in Echtzeit an und verfolgen Sie diese.
Verwenden Sie `kubectl logs -l <label-selector> -f`. Fügen Sie `--prefix` hinzu, um zu sehen, von welchem Pod jede Zeile stammt.
Warum: Aggregiert Logs von einer verteilten Anwendung und bietet eine vereinheitlichte Ansicht ihres Verhaltens.
Führen Sie einen Befehl aus oder erhalten Sie eine interaktive Shell in einem laufenden Container zum Debuggen.
Verwenden Sie `kubectl exec -it <pod-name> -- /bin/sh` (oder `/bin/bash`). Das `--` trennt kubectl-Flags vom Befehl.
Warum: Bietet direkten Zugriff auf die Containerumgebung für Live-Debugging, das Überprüfen von Dateien oder das Testen der Netzwerkkonnektivität.
Zeigen Sie den aktuellen CPU- und Speicherverbrauch eines laufenden Pods an.
Verwenden Sie `kubectl top pod <pod-name>`. Verwenden Sie `--containers`, um die Nutzung für jeden Container im Pod anzuzeigen.
Warum: Erfordert die Installation des Metrics Servers. Es ist unerlässlich zur Identifizierung von ressourcenintensiven Anwendungen, Speicherlecks oder CPU-Engpässen.
Fehlerbehebung bei einem laufenden Container, der keine Shell oder Debugging-Tools besitzt.
Verwenden Sie `kubectl debug <pod-name> -it --image=busybox --share-processes --copy-to=debug-pod`. Dies erstellt einen neuen Pod mit einem Debug-Container, der denselben Prozess-Namespace teilt.
Warum: `kubectl debug` ist der moderne Weg, einen temporären "ephemeral container" mit Debugging-Tools an einen laufenden Pod anzuhängen, ohne die ursprüngliche Pod-Spezifikation zu ändern.