Cheatsheet im Volltext
Derselbe Inhalt wie im PDF, zum Mitlesen, Durchsuchen und direkten Kopieren der Snippets. Stand: Kubernetes/kubectl v1.37 (Edition 2026.11).
Kontexte & kubeconfig
Kontext = Cluster + User + Namespace
kubectl config get-contexts zeigt alle,
use-context wechselt, set-context --current
setzt den Default-Namespace.
Merge: KUBECONFIG nimmt eine
Pfad-Liste (:-getrennt), erste Definition gewinnt.
config view --flatten schreibt daraus eine Datei.
--kubeconfig pinnt pro Aufruf.
Version-Skew
kubectl ist innerhalb einer Minor-Version
(älter oder neuer) zum kube-apiserver supported: ein
v1.37-Client deckt v1.36 bis v1.38 ab. Bei HA-Clustern mit
gemischten API-Server-Versionen wird das Fenster enger.
kubectl version zeigt beide Seiten, bei
Cluster-Flotten mit Versions-Spread den Client bewusst
wählen.
kuberc: CLI-Verhalten, nicht Cluster-Zugriff
~/.kube/kuberc (Beta seit v1.34, Pfad per
KUBERC oder --kuberc) hält Aliase
und Default-Flags getrennt von der kubeconfig.
credentialPluginPolicy: Allowlist begrenzt, welche
exec-Credential-Plugins laufen dürfen. KUBERC=off
schaltet die Datei ab, etwa in CI.
kubectl config get-contexts kubectl config use-context prod-admin kubectl config set-context --current --namespace=payments export KUBECONFIG=~/.kube/prod.yaml:~/.kube/lab.yaml kubectl config view --flatten > ~/.kube/merged.yaml kubectl version # Client- vs. Server-Version (Skew) kubectl kuberc set --section defaults --command delete \ --option interactive=true
Output-Formate
-o: von wide bis go-template
-o wide|yaml|json|name für den Alltag.
kyaml (stable seit v1.37): strikte
YAML-Teilmenge, nicht whitespace-sensitiv, String-Werte immer
quotiert (kein no → false),
Maps und Listen in {}/[].
jsonpath: Feld-Extraktion mit
range/Filter, Script-Futter statt
grep-Kaskaden.
custom-columns: eigene Tabellen direkt aus dem
API-Objekt.
go-template: volle Template-Logik inkl.
base64decode für Secrets.
Sortieren & Filtern
--sort-by nimmt einen JSONPath.
-l filtert nach Labels
(app=web,tier!=cache),
--field-selector nach Objektfeldern
(status.phase=Running). -A = alle
Namespaces.
kubectl get pods -o jsonpath='{.items[*].spec.containers[*].image}'
kubectl get pods -o jsonpath='{range .items[*]}{.metadata.name} {.status.podIP}{"\n"}{end}'
cols='NAME:.metadata.name,TAINT:.spec.taints[*].key'
kubectl get nodes -o custom-columns="$cols"
kubectl get secret db -o go-template='{{index .data "ca.crt" | base64decode}}'
kubectl get pods -A --sort-by=.metadata.creationTimestamp
kubectl get deploy web -o kyaml
Apply, Diff & Server-Side Apply
diff & dry-run
kubectl diff -f zeigt den Diff gegen den
Live-Stand vor dem Apply (Exit-Code 1 = Unterschiede,
CI-tauglich).
--dry-run=client sendet keinen Schreib-Request
und fängt deshalb keine falschen Feldnamen ab, die
Feldvalidierung macht der API-Server;
--dry-run=server lässt
Admission-Webhooks + Defaulting am API-Server
laufen, ohne zu persistieren, das ehrlichere Preflight.
Server-Side Apply, Field-Ownership
apply --server-side (GA seit v1.22) merged am
API-Server. Ownership steht pro Feld in
metadata.managedFields, jeder Writer trägt
einen --field-manager.
Conflict (HTTP 409), wenn ein anderer Manager
das Feld hält: --force-conflicts
übernimmt die Ownership, bewusst einsetzen, das
entzieht dem anderen Controller das Feld.
kubectl diff -f deploy.yaml kubectl apply -f deploy.yaml --dry-run=server kubectl apply --server-side --field-manager=ci -f deploy.yaml kubectl apply --server-side --force-conflicts -f deploy.yaml kubectl get deploy web --show-managed-fields -o yaml
Patch-Strategien
strategic, merge, json
strategic (Default): kennt Merge-Keys aus dem
Schema, patcht z.B. containers per
name statt die Liste zu ersetzen.
--type=merge (RFC 7386): simpel, aber Listen
werden komplett ersetzt.
--type=json (RFC 6902): Op-Liste
(add/replace/remove) mit
präzisen Pfaden.
CRDs: kein strategic-Support,
merge oder json verwenden.
--subresource (stable seit v1.33) mit
status, scale oder resize
bei get/patch/edit/replace und apply --server-side;
resize ändert
Pod-Ressourcen in place (GA seit v1.35).
kubectl patch deploy web -p '{"spec":{"replicas":4}}'
kubectl patch deploy web --type=merge \
-p '{"metadata":{"labels":{"team":"pay"}}}'
kubectl patch deploy web --type=json -p '[{"op": "replace",
"path": "/spec/template/spec/containers/0/image",
"value": "web:2.0"}]'
kubectl patch pod api --subresource=resize -p \
'{"spec":{"containers":[{"name":"api",
"resources":{"requests":{"cpu":"500m"}}}]}}'
Debug & Ephemeral Containers
Pod-Debug, distroless-tauglich
kubectl debug -it pod/x --image=... hängt
einen Ephemeral Container an (stable seit
v1.25), Debug-Tools für Images ohne Shell.
--target teilt den Prozess-Namespace des
Ziel-Containers.
Ephemeral Containers sind nicht entfernbar;
aufräumen heißt Pod löschen. Alternativ
--copy-to=dbg (teilt den Prozess-Namespace per
Default): Kopie debuggen, Original bleibt unangetastet.
Node-Debug & Profile
kubectl debug node/<n> startet einen Pod
auf dem Node, Host-Dateisystem unter /host. Der Pod
bleibt danach stehen, von Hand löschen.
--profile steuert die Rechte:
general (Default seit v1.36), baseline,
restricted, netadmin,
sysadmin; legacy ist deprecated
(Removal geplant für v1.39).
kubectl debug -it pod/api --image=nicolaka/netshoot --target=api kubectl debug pod/api --copy-to=api-dbg -it --image=busybox kubectl debug node/worker-3 -it --image=busybox --profile=sysadmin chroot /host # im Node-Debug-Pod
Rollout
status, history, undo
rollout status blockt bis Ready bzw.
progressDeadline, das Gate für Pipelines.
history listet Revisionen
(--revision=N zeigt Details; CHANGE-CAUSE kommt aus
der Annotation kubernetes.io/change-cause).
undo --to-revision=N rollt gezielt zurück.
restart erzwingt ein neues Rollout (z.B. nach
ConfigMap-Änderung). Gilt für Deployments, DaemonSets,
StatefulSets; pause/resume nur für
Deployments.
kubectl rollout status deploy/web --timeout=120s kubectl rollout history deploy/web --revision=3 kubectl rollout undo deploy/web --to-revision=2 kubectl rollout restart deploy/web kubectl rollout pause deploy/web # und: resume
Auth, Events & Wait
can-i, whoami
auth can-i prüft RBAC vor dem
Incident; --as / --as-group testet
fremde Identitäten (ServiceAccounts als
system:serviceaccount:<ns>:<sa>).
--list zeigt alle Rechte im Namespace.
auth whoami (GA seit v1.28,
SelfSubjectReview-API): UserInfo inkl. Gruppen, wie der
API-Server sie nach Authentifizierung sieht.
events, top, wait
kubectl events --for pod/x --types=Warning:
chronologisch, gefiltert, ergonomischer als
get events + --sort-by.
top pod|node braucht den metrics-server.
wait --for=condition=..., =create,
=delete oder =jsonpath=...:
deklaratives Warten mit --timeout statt
sleep-Schleifen. Mehrere --for werden seit v1.36
UND-verknüpft.
kubectl auth can-i create deploy -n prod kubectl auth can-i --list -n prod kubectl auth can-i get secrets --as system:serviceaccount:ci:builder kubectl auth whoami kubectl events --for pod/api --types=Warning kubectl top pods --containers -n prod kubectl wait --for=condition=Ready pod -l app=web --timeout=90s kubectl wait --for=create --for=condition=Ready pod/web-0
Port-Forward, Exec & cp
port-forward, exec, proxy, cp
port-forward tunnelt über den API-Server,
kein Ingress, kein NodePort nötig; svc/x pinnt
beim Start einen Pod dahinter, kein Load-Balancing, der
Tunnel endet mit diesem Pod. --address ist per
Default localhost; 0.0.0.0 öffnet
den Tunnel fürs Netz.
proxy legt die REST-API authentifiziert auf
127.0.0.1:8001, zum Explorieren und für
curl-Debugging. cp braucht ein
tar-Binary im Container, bei distroless nicht
vorhanden. Unter Windows schreibt cp aus einem
manipulierten Container beliebige lokale Pfade
(CVE-2026-19444), behoben ab v1.34.12, v1.35.9 und v1.36.5,
v1.37 ist nicht betroffen.
exec verlangt seit v1.35 -- vor dem
Kommando, die alte Form bricht mit Fehler ab.
kubectl port-forward svc/web 8080:80 kubectl port-forward pod/db 15432:5432 # lokal:remote kubectl proxy --port=8001 & curl localhost:8001/api/v1/namespaces/prod/pods kubectl cp prod/api-6d5f7:/var/log/app.log ./app.log kubectl exec -it deploy/web -c app -- sh
Explain, Kustomize & Plugins
explain & API-Discovery
explain deploy.spec.strategy: Feld-Doku aus dem
OpenAPI-Schema des Clusters, inkl. CRDs.
--recursive zeigt den ganzen Teilbaum,
--max-depth=N (seit v1.37) kappt ihn,
--api-version pinnt die Version.
api-resources / api-versions: was
der Cluster kann, inkl. Shortnames.
Kustomize (-k)
Kustomize ist in kubectl integriert:
apply|diff|delete -k <dir> rendert Base +
Overlay und wendet an; kubectl kustomize <dir>
rendert nur. Eingebettete Version:
kubectl version --client (v1.37: Kustomize v5.8.1);
GitOps-Controller rendern mit ihrer eigenen.
Plugins & Krew
Jedes Binary kubectl-<name> im
PATH wird Subcommand;
kubectl plugin list zeigt sie.
Plugin-Manager: Krew (kubernetes-sigs) mit
krew search|install|upgrade, über 400 Plugins
im Index. Die Plugins sind nicht auf Sicherheit geprüft,
eingebaute Kommandos überschreiben können sie nicht.
kubectl explain deploy.spec --recursive --max-depth=2 kubectl api-resources --namespaced=false kubectl kustomize overlays/prod | kubectl diff -f - kubectl apply -k overlays/prod kubectl krew install ctx ns tree
Completion & Alias
kubectl completion bash|zsh|fish|powershell
erzeugt das Completion-Skript, unter bash mit dem Paket
bash-completion. Unter zsh greift es auch für einen Alias,
unter bash braucht der Alias eine eigene
complete-Zeile.
source <(kubectl completion bash) alias k=kubectl complete -o default -F __start_kubectl k
Fehlerbilder & erste Kommandos
STATUS ist nicht Phase
Die STATUS-Spalte von get pods ist eine Anzeige:
CrashLoopBackOff oder Terminating sind
keine Phase, status.phase bleibt etwa
Running. Erster Blick: describe pod.
describe zeigt Events seit v1.36 nur beim Einzelobjekt, für
mehrere --show-events.
CrashLoopBackOff: Neustart mit Backoff 10 s,
20 s, 40 s bis 5 min; logs --previous
zeigt den Absturz. OOMKilled steht nach dem Neustart in
lastState.terminated.reason.
ImagePullBackOff: das Event nennt die
Registry-Antwort. Pending: ist der Pod noch nicht eingeplant, nennt
FailedScheduling den Grund.
kubectl get pods -A --field-selector=status.phase=Pending
kubectl describe pod api-7c9f
kubectl events -n prod --types=Warning
kubectl get pod api-7c9f -o jsonpath=\
'{.status.containerStatuses[*].lastState.terminated.reason}'
kubectl debug pod/api-7c9f -it --copy-to=api-dbg \
--container=app -- sh
Logs
Was logs liefert
--previous: die zuletzt beendete Instanz, der
kubelet hält per Default eine vor. Nach Eviction oder
Pod-Löschung sind die Logs weg; nach Rotation liefert logs nur
die jüngste Datei.
deploy/web liest einen Pod,
--all-pods alle (setzt --prefix). Mit
-l ist --tail per Default 10, ohne
Selektor alles. -f über mehr als 5
Container-Streams bricht ab, --max-log-requests hebt
das Limit.
kubectl logs api-7c9f -c app --previous kubectl logs deploy/web --all-pods --since=15m kubectl logs -l app=web --tail=200 --prefix kubectl logs -f -l app=web --max-log-requests=10 kubectl logs api-7c9f --timestamps \ --since-time=2026-10-30T06:00:00Z
Node-Wartung
cordon, drain, uncordon
cordon sperrt den Node für neue Pods,
laufende bleiben. drain = cordon + Eviction aller
Pods außer Mirror- und DaemonSet-Pods. Abbruch, wenn
--ignore-daemonsets (DaemonSet-Pods),
--delete-emptydir-data (emptyDir-Daten gehen
verloren) oder --force (Pods ohne Controller kommen
nicht wieder) fehlt.
Eviction respektiert PodDisruptionBudgets: die
API antwortet 429, drain versucht es weiter.
--timeout ist per Default 0, also unbegrenzt, in
Pipelines setzen. --disable-eviction löscht per
DELETE und umgeht PDBs.
taint: NoSchedule wirkt nur auf
neue Pods, NoExecute evictet laufende ohne
Toleration, key- entfernt alle Taints mit diesem Key.
kubectl cordon worker-3 kubectl drain worker-3 --ignore-daemonsets \ --delete-emptydir-data --timeout=15m kubectl get pdb -A # ALLOWED DISRUPTIONS 0 blockt kubectl uncordon worker-3 kubectl taint nodes worker-3 maint=true:NoSchedule kubectl taint nodes worker-3 maint-
Manifeste erzeugen & ändern
Generator statt Handarbeit
create … --dry-run=client -o yaml erzeugt
ein Gerüst ohne Cluster-Kontakt. Ein Secret steht darin nur
base64-kodiert, nicht verschlüsselt. Per Pipe an kubectl apply -f - wiederholbar anlegen
oder aktualisieren.
create job --from=cronjob/x startet einen CronJob
sofort. create token holt ein kurzlebiges
ServiceAccount-Token, der Server darf die Laufzeit abweichend
setzen.
set image/set env ändern das
Pod-Template eines Workloads und lösen ein Rollout aus.
label/annotate brauchen
--overwrite für bestehende Keys,
key- löscht.
kubectl create deploy web --image=web:2.0 --replicas=2 \ --dry-run=client -o yaml > deploy.yaml kubectl create secret generic db --from-env-file=db.env \ --dry-run=client -o yaml | kubectl apply -f - kubectl create job backup-now --from=cronjob/backup kubectl create token ci-deployer --duration=10m kubectl set image deploy/web app=web:2.1 kubectl label pod api-7c9f team=pay --overwrite
API-Zugriff & Credential-Plugins
Verbosity & Rohzugriff
-v=6 zeigt Methode, URL, Status und Latenz jedes
Requests, -v=7 die Header, -v=8 und
-v=9 auch die Bodies, gekürzt auf 1 bzw.
10 KiB. Ab -v=8 können Secret-Inhalte in der
Ausgabe stehen, nicht in Tickets kopieren.
get --raw ruft beliebige API-Pfade mit der Auth
aus der kubeconfig auf. --request-timeout ist per
Default 0, also ohne Timeout.
exec-Credential-Plugins
users[].user.exec startet ein Binary, das ein
ExecCredential liefert (OIDC, Cloud-Anbieter). Mit
client.authentication.k8s.io/v1 ist
interactiveMode Pflicht: Never,
IfAvailable oder Always. Welche Plugins
laufen dürfen, begrenzt kuberc.
kubectl get pods -v=6 kubectl get --raw='/readyz?verbose' --request-timeout=5s kubectl config set-credentials sso \ --exec-api-version=client.authentication.k8s.io/v1 \ --exec-command=cred-helper --exec-interactive-mode=Never
Anti-Patterns
Was du nicht tun solltest
edit in Prod: unversionierter
Live-Drift; der nächste Apply/GitOps-Sync überschreibt
still. Änderung ins Repo, dann apply.
delete --force --grace-period=0:
entfernt nur das API-Objekt, der Prozess kann am Node
weiterlaufen, bei StatefulSets Risiko doppelter
Identitäten.
Apply-Modi mischen: der Wechsel
client-side → server-side ist nur mit dem
Default-Manager kubectl konfliktfrei. Felder, die
per scale/edit statt Apply gesetzt
wurden, und ein eigener --field-manager laufen bei
abweichenden Werten in Conflicts. Pro Objekt einen Modus und
einen Manager festlegen.
:latest + rollout
restart als Deployment-Ersatz: nicht
reproduzierbar, kein Rollback-Ziel; stattdessen unveränderliche
Tags oder Digests.
Blind im falschen Kontext: destruktive
Kommandos ohne config current-context-Check;
Prod-Kontexte explizit benennen und im Prompt markieren.
scale gegen HPA: der Autoscaler
setzt den Wert zurück, Min/Max am HPA ändern
statt manuell zu skalieren.