Kubernetes Cheatsheet

Kubernetes CheatsheetAlle Kapitel

Kubernetes Cheatsheet im Volltext

Stand Kubernetes 1.37 · Edition 2026.11

Cheatsheet im Volltext

Derselbe Inhalt wie im PDF, zum Mitlesen, Durchsuchen und direkten Kopieren der YAML-Snippets. Stand: Kubernetes 1.37 (Edition 2026.11).

Architektur

Control Plane

kube-apiserver: REST-Front, einzige etcd-Schreibstelle, Admission-Plugins.

etcd: konsistenter KV-Store (Raft), 3/5/7 Nodes, fsync-Latenz ist der Bottleneck.

kube-scheduler: Bind-Phase Pod → Node, Filter + Score.

controller-manager: Reconcile-Loops (Deployment, ReplicaSet, Endpoints, Node, …).

cloud-controller-manager: provider-spezifisch (LB, Routes, Node-Lifecycle).

Node

kubelet: Pod-Spec → CRI-Calls, Probes, Volume-Mounts, Status-Report.

kube-proxy: Service-VIP → Pod-IP. mode explizit setzen: Linux-Default wechselt künftig von iptables auf nftables (GA 1.33), ipvs ist deprecated (Default-off ab 1.40 geplant).

CRI (containerd, CRI-O), CNI (Cilium, Calico), CSI (Treiber pro Storage).

kubectl version
kubectl get --raw='/readyz?verbose'

Workloads

Pod & Wahl der Workload-Resource

Deployment: stateless, rolling, austauschbare Replicas. StatefulSet: ordinale Namen (web-0…N), stabile Netz-IDs, geordneter Start/Stop, eigene PVCs.

DaemonSet: ein Pod je Node (CNI, Log-Shipper, Node-Exporter). Job / CronJob: einmalig/periodisch, completions + parallelism, backoffLimit.

Sidecar: initContainers[] mit restartPolicy: Always (GA 1.33), startet vor der App, endet nach ihr, blockiert Job-Ende nicht. Pod direkt nur für Debug.

Deployment: Rolling Update

strategy.rollingUpdate.maxUnavailable + maxSurge steuern Tempo. Default 25 % / 25 %. Für Singletons: strategy.type: Recreate. Pause: kubectl rollout pause, dann mehrere Patches, dann resume.

apiVersion: apps/v1
kind: Deployment
metadata: {name: api}
spec:
  replicas: 3
  strategy:
    type: RollingUpdate
    rollingUpdate: {maxUnavailable: 0, maxSurge: 1}
  selector: {matchLabels: {app: api}}
  template:
    metadata: {labels: {app: api}}
    spec:
      containers:
      - name: api
        image: ghcr.io/acme/api:1.4.2
        resources:
          requests: {cpu: 100m, memory: 128Mi}
          limits:   {memory: 256Mi}
        readinessProbe:
          httpGet: {path: /readyz, port: 8080}
          periodSeconds: 5

StatefulSet: Eigenheiten

serviceName = Headless-Service (clusterIP: None), DNS pro Pod: web-0.<svc>.<ns>.svc.cluster.local. volumeClaimTemplates legt PVC pro Replica an, per Default bleibt es auch bei Scale-down und Löschen; persistentVolumeClaimRetentionPolicy (whenDeleted/whenScaled: Retain | Delete, GA 1.32). podManagementPolicy: Parallel bricht Ordnung auf, schneller bei zustandslosen Workloads, die StatefulSet nur wegen stabiler DNS brauchen. updateStrategy.rollingUpdate.maxUnavailable (Beta, seit 1.37 per Default an) rollt mehrere Replicas gleichzeitig, bei OrderedReady erst, wenn das Set voll hochskaliert ist.

Job-Pattern

completions: N, parallelism: M, N Tasks, M parallel. activeDeadlineSeconds hartes Timeout (Pod-Kill). ttlSecondsAfterFinished, Aufräumen ohne Cron.

CronJob concurrencyPolicy: Forbid | Replace | Allow, startingDeadlineSeconds gegen Backlog nach Cluster-Pause. timeZone: Europe/Berlin (GA 1.27), sonst gilt die Zeitzone des kube-controller-managers.

Networking

Service-Typen

ClusterIP (default): VIP im Cluster. NodePort: + Port 30000–32767 auf jedem Node. LoadBalancer: + externer LB via cloud-controller. ExternalName: DNS-CNAME, kein Proxy. Headless (clusterIP: None): A-Records pro Endpoint, für StatefulSets + Client-side LB.

spec.externalIPs: seit 1.36 deprecated (CVE-2020-8554), kube-proxy-Support frühestens ab 1.40 per Default aus, Entfernung frühestens 1.43. Admission DenyServiceExternalIPs aktivieren.

apiVersion: v1
kind: Service
metadata: {name: api}
spec:
  selector: {app: api}
  ports:
  - {name: http, port: 80, targetPort: 8080}
  internalTrafficPolicy: Cluster  # Local: nur Client-Node
  trafficDistribution: PreferSameZone

EndpointSlice (seit 1.21)

Löst Endpoints ab (v1-API seit 1.33 deprecated, wird nicht entfernt). Slices à 100 Endpoints (Default, --max-endpoints-per-slice bis 1000), skaliert auf >1000 Pods. Zonen-Routing: spec.trafficDistribution: PreferSameZone (GA 1.35, auch PreferSameNode). Die Annotation service.kubernetes.io/topology-mode ist seit 1.33 deprecated.

Ingress vs. Gateway API

Ingress ist eingefroren, HTTP/L7-only, vendor-Annotations explodieren. Die API bleibt im Core.

Gateway API (eigene CRDs, v1.0 GA seit 31.10.2023, aktuell v1.7.0 vom 29.10.2026) trennt Rollen: Infrastructure (GatewayClass, Gateway) vs. App-Team (HTTPRoute, GRPCRoute, TLSRoute, seit v1.6 auch TCPRoute/UDPRoute GA). Cross-Namespace via ReferenceGrant. CRDs gelten clusterweit: eine Version für alle Controller. Die VAP safe-upgrades.gateway.networking.k8s.io (seit v1.5) lehnt CRD-Bundles unter der eigenen Minor-Version ab (v1.7.0: alles vor v1.7.0), ebenso Experimental- über Standard-CRDs. HTTPRoute-retry ist seit v1.7 Standard.

ingress-nginx ist retired

kubernetes/ingress-nginx wurde am 24.03.2026 archiviert: keine Releases, keine Bugfixes, keine CVE-Patches mehr. Bestand läuft weiter, ein EOL-Controller im L7-Datenpfad ist aber ein Audit-Fund.

Nicht verwechseln: der NGINX Ingress Controller von F5/NGINX ist ein anderes Projekt und nicht betroffen.

Migration: ingress2gateway (1.0 seit 20.03.2026, aktuell 1.2.0 vom 07.07.2026) übersetzt Ingress samt gängiger Annotations nach Gateway API.

NetworkPolicy (Default-Deny)

Allowlist-Modell, ohne Policy: alles offen. Pattern: default-deny pro Namespace, dann Ingress/Egress explizit öffnen. podSelector: {} = alle Pods, policyTypes: [Ingress, Egress] ohne egress:-Block = total dicht, auch für DNS: UDP+TCP 53 zu CoreDNS explizit freigeben.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata: {name: default-deny, namespace: prod}
spec:
  podSelector: {}
  policyTypes: [Ingress, Egress]
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata: {name: allow-api, namespace: prod}
spec:
  podSelector: {matchLabels: {app: api}}
  ingress:
  - from:
    - namespaceSelector:
        matchLabels: {kubernetes.io/metadata.name: ingress}
    ports: [{port: 8080}]

Storage

PV / PVC / StorageClass

StorageClass: Treiber + Parameter (provisioner, reclaimPolicy: Delete | Retain, volumeBindingMode: WaitForFirstConsumer → Topology-Aware).

PVC: Anforderung der App (accessModes, storage: 20Gi). Dynamic Provisioning erzeugt PV.

PV: Cluster-Resource, an PVC gebunden.

AccessModes & Erweitern

ReadWriteOnce (RWO, Node-exklusiv), ReadOnlyMany (ROX), ReadWriteMany (RWX, NFS/CephFS), ReadWriteOncePod (RWOP, ein Pod).

Online-Expand: StorageClass mit allowVolumeExpansion: true, PVC patchen (nicht schrumpfen). Treiber muss Expansion können (Controller- und/oder Node-Seite). Schlägt sie fehl, darf ein kleinerer Wert über der bisherigen Größe angefordert werden (GA 1.34).

VolumeMode & Snapshots

volumeMode: Filesystem (Default) oder Block (Raw-Device, DB-Storage).

VolumeSnapshot / VolumeSnapshotClass (CSI; CRDs und snapshot-controller bringt die Distribution mit, nicht der Core) für Point-in-Time-Restore. Snapshot → neues PVC via dataSource.

Security

RBAC

Role / ClusterRole: rules[].{apiGroups, resources, verbs}.

RoleBinding / ClusterRoleBinding: bindet Subject (User, Group, ServiceAccount) an Role.

Aggregation: aggregationRule.clusterRoleSelectors sammelt mehrere ClusterRoles, view, edit, admin sind so gebaut.

kubectl auth can-i delete pods --as=alice -n prod
kubectl auth can-i --list -n prod \
  --as=system:serviceaccount:prod:api

ServiceAccount-Token (seit 1.24)

Projected, bounded: audience- und Pod-gebunden, kubelet rotiert. Das automatisch gemountete kube-api-access (3607 s) verlängert der API-Server per Default auf bis zu 1 Jahr (--service-account-extend-token-expiration=false für harte 1 h). Eigene Projected-Tokens (Default 3600 s) sind nicht betroffen.

Klassische Secret-Tokens werden nicht mehr automatisch angelegt, explizit via kubernetes.io/service-account-token oder besser: TokenRequest-API + projected Volume.

Pod Security Admission

Ersetzt PodSecurityPolicy. Label am Namespace: pod-security.kubernetes.io/{enforce | audit | warn}: {privileged | baseline | restricted}. restricted verlangt runAsNonRoot: true, allowPrivilegeEscalation: false, capabilities.drop: [ALL], Seccomp RuntimeDefault oder Localhost. Profilstand pinnen: …/enforce-version.

SecurityContext (Pflicht-Set)

runAsNonRoot: true, runAsUser: 1000, readOnlyRootFilesystem: true, allowPrivilegeEscalation: false, capabilities.drop: [ALL], seccompProfile.type: RuntimeDefault. Pod-Ebene: hostUsers: false (User Namespaces, GA 1.36), Container-Root ist auf dem Host unprivilegiert. Braucht idmap-Mounts (Linux ≥ 6.3), containerd ≥ 2.0 oder CRI-O ≥ 1.25, runc ≥ 1.2 oder crun ≥ 1.9.

Secrets at Rest

etcd-Klartext per Default. KMS v2 (GA 1.29, v1 seit 1.29 per Default aus) via EncryptionConfiguration + externer KMS (Vault, Cloud-KMS) für Envelope-Encryption. Nach Aktivierung oder Key-Rotation bleiben Altdaten unverändert: StorageVersionMigration (storagemigration.k8s.io/v1, GA 1.37) schreibt sie neu.

Alternativ: External Secrets Operator.

Scheduling

Requests / Limits / QoS

Guaranteed: requests = limits (CPU + Memory, jeder Container), nie wegen fremder Pods evicted, oom_score_adj −997. Eviction-Reihenfolge: Nutzung > requests, dann Priority. QoS ist nur Näherung.

Burstable: mindestens ein request/limit, aber nicht Guaranteed. BestEffort: weder requests noch limits, erste Opfer bei Eviction.

CPU-Limits drosseln (CFS-throttle, Latenz-Spitzen). Memory-Limit-Hit ⇒ OOMKill. Faustregel: Memory-Limit ja, CPU-Limit nur wenn Multi-Tenant-Schutz nötig.

Affinity / Anti-Affinity

podAntiAffinity.requiredDuringSchedulingIgnoredDuringExecution mit topologyKey: kubernetes.io/hostname verteilt Replicas auf Nodes. preferred… ist Hint, kein harter Constraint. topologyKey: topology.kubernetes.io/zone = Zone-Spread.

Taints / Tolerations

Taint am Node: kubectl taint node n1 gpu=true:NoSchedule.

Toleration im Pod erlaubt Scheduling auf getainted Node, erzwingt es aber nicht (dafür nodeSelector/Affinity).

Topology Spread Constraints

maxSkew + topologyKey + whenUnsatisfiable: DoNotSchedule | ScheduleAnyway. Modernerer Ersatz für viele Anti-Affinity-Regeln: Pod-(Anti-)Affinity bremst laut Doku den Scheduler in Clustern ab einigen hundert Nodes. matchLabelKeys: [pod-template-hash] (Beta, Default an seit 1.27) rechnet den Skew je Revision, sonst verzerren alte Pods den Rollout.

PriorityClass & Preemption

preemptionPolicy: PreemptLowerPriority | Never und value je PriorityClass. system-*-critical ist reserviert.

DRA (GA seit 1.34)

GPUs/NICs über ResourceClaim + DeviceClass (resource.k8s.io/v1) statt Device Plugin. Seit 1.37 GA: Extended-Resource-Mapping (bestehende nvidia.com/gpu-Requests laufen unverändert über DRA, wenn eine DeviceClass extendedResourceName setzt) und Device Taints.

Autoscaling & Resource-Schutz

HPA

metrics.k8s.io (CPU/Mem; v1 GA seit 1.37, der HPA fragt weiter v1beta1 ab) oder custom/external (Prometheus-Adapter, KEDA). minReplicas≥2 für Verfügbarkeit, 0 nur mit Object-/External-Metrik (Beta 1.37). Gegen Flapping: behavior.scaleDown.stabilizationWindowSeconds (Default 300 s), Toleranz je Richtung über behavior.scaleUp|scaleDown.tolerance (GA 1.37, Default 10 %).

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata: {name: api}
spec:
  scaleTargetRef:
    {apiVersion: apps/v1, kind: Deployment, name: api}
  minReplicas: 2
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target: {type: Utilization, averageUtilization: 70}

VPA

recommender: schlägt requests vor (updateMode: Off, sicher).

updater + admission: Recreate (Eviction) oder InPlaceOrRecreate (GA seit VPA 1.6, nutzt In-Place-Resize, GA in K8s 1.35). Auto ist seit VPA 1.5 deprecated.

Achtung: VPA mit Updates + HPA auf CPU/Mem kollidieren.

PDB / ResourceQuota / LimitRange

PodDisruptionBudget: minAvailable oder maxUnavailable, Drains, Upgrades respektieren das. unhealthyPodEvictionPolicy: AlwaysAllow (GA 1.31), sonst blockieren nicht-Ready-Pods bei ausgeschöpftem Budget den Drain.

ResourceQuota: Namespace-Limit für Summen (requests.cpu, count/pods, persistentvolumeclaims).

LimitRange: Default + Min/Max pro Container, erzwingt, dass jeder Pod requests trägt.

Observability & Probes

Probe-Sequenz

startupProbe: blockt liveness/readiness bis App hochfährt (Java, .NET). failureThreshold · periodSeconds = Max-Boot-Zeit.

readinessProbe: bestimmt Service-Endpoint-Inclusion. Failt → aus dem LB raus, Pod läuft weiter.

livenessProbe: failt → Container-Restart. Vorsicht: Liveness ist nicht für Dependency-Health (DB unten ⇒ Pod kreist).

Probe-Pflicht

initialDelaySeconds ist starres Raten (nicht deprecated), startupProbe wartet adaptiv.

Host-based-Routing: httpHeaders mit Host setzen, sonst falsche 200.

kubectl-Werkzeuge

logs --previous für gerade gecrashte Pods. logs -f --tail=100 --since=10m -l app=api. top pod -A --sort-by=memory. events --for pod/api-xxx (seit 1.26, zeitlich sortiert, auch nach eventTime).

Diagnose

kubectl debug

kubectl debug -it pod/api-xxx --image=busybox --target=api, ephemeral Container im Pod-Namespace (Process+Network).

--copy-to=api-debug --set-image=api=busybox: Pod-Kopie mit getauschtem Image, ohne Probes und Labels.

node/n1: Host-PID/-Net/-IPC, Node-Root unter /host, privilegiert erst mit --profile=sysadmin. Default-Profil seit 1.36 general, legacy soll in 1.39 entfallen.

Häufige Fehlerbilder

CrashLoopBackOff: App stürzt direkt nach Start, logs --previous + describe.

ImagePullBackOff: Registry, Tag, imagePullSecret.

OOMKilled: Memory-Limit zu tief, Reason in lastState.

Pending (Scheduling): describe sagt warum (Insufficient cpu/memory, no nodes match selector, taints).

Init:0/1: InitContainer hängt, logs -c <init>.

ContainerCreating (lange): CSI-mount, image-pull, CNI.

kubectl get pod api-xxx -o json \
  | jq '.status.containerStatuses[].state'
kubectl describe node n1 | grep -A5 Allocatable
kubectl events -A | tail -40

Release-Zug

Kadenz & Support

Drei Minor-Releases pro Jahr. Aktuell: 1.37 (26.08.2026, zuletzt 1.37.2 vom 27.10.2026), daneben 1.36 und 1.35. 1.34 ist seit 27.10.2026 EOL (letzter Patch 1.34.13). 1.35 geht am 28.12.2026 in den Maintenance-Mode, EOL 28.02.2027.

CVE-2026-2270 (kube-controller-manager): Schreibrecht auf StatefulSet und ControllerRevision reicht für Pods in fremden Namespaces. Fix ab 1.37.1, 1.36.5, 1.35.9. Empfohlen: 1.37.2, 1.36.6, 1.35.10, gebaut mit Go 1.26.10 (sperrt kompromittierte eMudhra-Intermediates, CVE-2026-111943).

1.38 ist für den 16.12.2026 geplant (Code-Freeze 16.11.2026 AoE).

Patch-Support je Minor: rund 14 Monate (12 Monate regulär, danach zwei Monate Maintenance-Mode). Gepflegt werden die drei jüngsten Minors, im Überlappungsfenster kurz vier.

Upgrade-Falle: seit 1.35 startet das kubelet auf cgroup-v1-Nodes nicht mehr (failCgroupV1: true per Default). failCgroupV1: false nur als Übergang, die Entfernung von v1 hat noch keinen Termin, frühestens 1.38 (KEP-5573).

Vor 1.38 prüfen: containerd 1.7 ist seit 30.09.2026 EOL. Laut KEP-4033 soll das kubelet ohne den CRI-Aufruf RuntimeConfig (containerd 1.7) nicht mehr starten, geplant für 1.38, Umsetzung offen. Mindestens containerd 2.0 oder CRI-O 1.28, betroffene Nodes meldet kubelet_cri_losing_support.

Anti-Patterns

Was du nicht tun solltest

image: foo:latest: nicht reproduzierbar, Rolling Update merkt nichts.

Keine requests: ohne requests und limits BestEffort, erste Opfer bei Eviction; HPA ohne CPU-request liefert keine Metrik.

CPU-Limit gleich requests bei latenz-kritischen Apps: CFS-throttle erzeugt p99-Spitzen.

hostNetwork: true aus Bequemlichkeit: Port-Konflikte, NetworkPolicy umgangen.

Liveness als Health-of-Dependencies: DB unten ⇒ Cluster restartet sich selbst tot.

kubectl apply ohne --server-side: Client-side Apply überschreibt Werte anderer Manager (HPA, Controller) ohne Konflikt. SSA prüft je Feld und bricht bei Konflikt ab.