OMNI52
Service Mesh Cheatsheet OMNI52™ GmbH

Istio Service Mesh
auf einem Blatt.

Dichte Referenz für Senior Platform Engineers und SREs. Traffic-Management, Security, Observability, Performance, Multi-Cluster und die häufigsten Fehlerbilder beim Betrieb. Keine Einsteiger-Folien.

Vorschau (3 Seiten A4 quer)

Cheatsheet Seite 1: Architektur, Traffic Management, Security
Cheatsheet Seite 2: Observability, Performance, Multi-Cluster, Diagnose
Cheatsheet Seite 3: Gateway API, Anti-Patterns, Kontakt & Lizenz

PDF herunterladen

Direkter Download, keine Mail-Adresse nötig. CC BY-SA 4.0 — kopieren, drucken, weiterverteilen ist ausdrücklich erlaubt, solange die Quellenangabe sichtbar bleibt.

Service Mesh Cheatsheet (PDF, ~100 KB)

Was drin steht

Traffic

Gateway, VirtualService, DestinationRule, ServiceEntry, Sidecar-Scoping — mit Outlier Detection und Connection-Pool-Defaults.

Security

PeerAuthentication, AuthorizationPolicy mit JWT-Claims, RequestAuthentication, SPIFFE-Identity, Migrations-Pattern für mTLS STRICT.

Observability

Telemetry-API, Pflicht-Metriken aus dem Envoy-Stack, Tracing-Header-Propagation, OTel-Logging mit Filter.

Performance

Sidecar-Sizing-Faustregeln, Pilot-Tuning für Push-Storms, Ambient-Mode (1.30 GA) als sidecar-less Option.

Multi-Cluster

Primary-Remote, Multi-Primary, External Control-Plane. Trust-Domain-Setup und Endpoint-Discovery in einem Block.

Diagnose

istioctl-Werkzeuge in Reihenfolge des Vorfalls. Typische 503-UC/NR/UF-Codes mit Ursache.

Cheatsheet im Volltext

Derselbe Inhalt wie im PDF — zum Mitlesen, Durchsuchen und direkten Kopieren der YAML-Snippets. Stand: Istio 1.30 (v1.30 · 2026.07).

Architektur

Datapath & Komponenten

Client → Ingress GW → Sidecar(src) → Sidecar(dst) → App. Hop ≈ 0,5–2 ms p99. mTLS-Handshake nur beim Connect.

istiod: Pilot/Citadel/Galley vereint, xDS-Push + CA. istio-proxy: Envoy-Sidecar (Mutating Webhook) oder Ambient ztunnel. Gateway: dedizierte Envoys, Deployment + LB-Service.

Envoy-Version = Istio-Version + 8. Istio 1.30 → Envoy 1.38.

Install-Profile

default (prod), minimal (nur istiod), ambient (sidecar-less), remote (MC-Workload-Cluster), demo (laut). Canary via --revision=1-30-1.

istioctl install --set profile=default \
  --set values.global.proxy.resources.requests.cpu=100m
istioctl verify-install

Traffic Management

Gateway

Bindet Ports/Hosts/TLS am Edge-Proxy. servers[].port + tls.mode: SIMPLE, MUTUAL, PASSTHROUGH, ISTIO_MUTUAL. credentialName verweist auf Secret im selben Namespace wie der Gateway-Pod.

apiVersion: networking.istio.io/v1
kind: Gateway
metadata: {name: web-gw, namespace: istio-system}
spec:
  selector: {istio: ingressgateway}
  servers:
  - port: {number: 443, name: https, protocol: HTTPS}
    hosts: ["www.istio-cheatsheet.de"]
    tls:
      mode: SIMPLE
      credentialName: web-cert

VirtualService

Routing-Regeln. Bindet hosts an gateways (oder mesh für Ost-West). Match-Reihenfolge ist signifikant — erste Treffer-Regel gewinnt. Header-Match case-insensitive, Pfad-Match case-sensitive.

apiVersion: networking.istio.io/v1
kind: VirtualService
metadata: {name: reviews}
spec:
  hosts: [reviews]
  http:
  - match:
    - headers: {end-user: {exact: jason}}
    route:
    - destination: {host: reviews, subset: v2}
  - route:
    - destination: {host: reviews, subset: v1}
      weight: 90
    - destination: {host: reviews, subset: v3}
      weight: 10
    retries:
      attempts: 3
      perTryTimeout: 2s
      retryOn: gateway-error,connect-failure,refused-stream
    timeout: 10s

DestinationRule

Subsets (Versionen) + Traffic-Policy (LB, Connection-Pool, Outlier Detection, TLS). Wirkt erst nach VirtualService-Routing. host muss FQDN oder Short-Name im selben Namespace sein.

apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata: {name: reviews}
spec:
  host: reviews
  trafficPolicy:
    connectionPool:
      tcp: {maxConnections: 100}
      http:
        http1MaxPendingRequests: 64
        http2MaxRequests: 1000
        maxRequestsPerConnection: 10
    outlierDetection:
      consecutive5xxErrors: 5
      interval: 30s
      baseEjectionTime: 60s
    loadBalancer:
      consistentHash:
        httpHeaderName: x-user-id
  subsets:
  - name: v1
    labels: {version: v1}
  - name: v2
    labels: {version: v2}

ServiceEntry

Externe Hosts in den Mesh-Registry holen (DB, SaaS, REST-APIs). MESH_EXTERNAL + DNS resolution sind die saubere Default-Kombi. Ohne ServiceEntry bleibt der Egress-Traffic BlackHoleCluster wenn outboundTrafficPolicy=REGISTRY_ONLY.

apiVersion: networking.istio.io/v1
kind: ServiceEntry
metadata: {name: stripe-api}
spec:
  hosts: ["api.stripe.com"]
  ports:
  - {number: 443, name: https, protocol: HTTPS}
  resolution: DNS
  location: MESH_EXTERNAL

Sidecar

Begrenzt was ein Workload aus der Mesh-Registry sieht — kritisch für Memory-Footprint und Push-Latenz in großen Clustern. Default: jeder Sidecar bekommt Config für alle Services. Auf > 200 Services Pflicht.

apiVersion: networking.istio.io/v1
kind: Sidecar
metadata: {name: default, namespace: prod}
spec:
  egress:
  - hosts:
    - "./*"             # nur eigener Namespace
    - "istio-system/*"
    - "shared/*"

Security

PeerAuthentication

mTLS-Modus zwischen Sidecars. STRICT, PERMISSIVE, DISABLE. Geltung: Mesh (in istio-system), Namespace, oder Workload via selector. Migration zu STRICT: zuerst Mesh-weit PERMISSIVE, dann namespace-weise umstellen.

apiVersion: security.istio.io/v1
kind: PeerAuthentication
metadata: {name: default, namespace: prod}
spec:
  mtls: {mode: STRICT}
---
# Port-Ausnahme: Health-Check vom NLB ohne mTLS
spec:
  selector: {matchLabels: {app: legacy}}
  mtls: {mode: STRICT}
  portLevelMtls:
    8080: {mode: PERMISSIVE}

AuthorizationPolicy

L7-Zugriffskontrolle. action: ALLOW (default), DENY (precedence), AUDIT, CUSTOM (ext authz). Leere rules: blockiert/erlaubt alles (je nach action). Mehrere Policies kombinieren AND innerhalb, OR über Policies.

apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata: {name: reviews-allow, namespace: prod}
spec:
  selector: {matchLabels: {app: reviews}}
  action: ALLOW
  rules:
  - from:
    - source:
        principals:
        - cluster.local/ns/prod/sa/productpage
    to:
    - operation:
        methods: [GET]
        paths: ["/reviews/*"]
    when:
    - key: request.auth.claims[groups]
      values: ["reader", "admin"]

RequestAuthentication (JWT)

Validiert JWT, füllt request.auth.* für AuthorizationPolicy. Wichtig: ohne zusätzliche DENY-Policy mit notRequestPrincipals=["*"] können unauthentifizierte Requests weiterhin durch.

apiVersion: security.istio.io/v1
kind: RequestAuthentication
metadata: {name: jwt, namespace: prod}
spec:
  selector: {matchLabels: {app: api}}
  jwtRules:
  - issuer: "https://auth.example.com"
    jwksUri: "https://auth.example.com/jwks"
    audiences: ["api.example.com"]
    forwardOriginalToken: true

Identity

SPIFFE-URI spiffe://<trust>/ns/<ns>/sa/<sa>. Trust-Domain default cluster.local, in Multi-Cluster pro Cluster eindeutig. Workload-Cert-Rotation 24 h, automatisch via Citadel.

Observability

Telemetry-API

Metriken/Logs/Traces pro Workload oder Namespace. Ersetzt EnvoyFilter-Telemetry-Mods und die alten values.telemetry.v2.*-Settings.

apiVersion: telemetry.istio.io/v1
kind: Telemetry
metadata: {name: trace-prod, namespace: prod}
spec:
  tracing:
  - providers: [{name: tempo}]
    randomSamplingPercentage: 5.0
  metrics:
  - providers: [{name: prometheus}]
    overrides:
    - match: {metric: REQUEST_COUNT}
      tagOverrides:
        request_protocol: {operation: REMOVE}
  accessLogging:
  - providers: [{name: otel}]
    filter:
      expression: "response.code >= 400"

Metriken & Tracing

RED-Counter: istio_requests_total, Latency: istio_request_duration_milliseconds_bucket. Label reporter = source/destination — in Dashboards immer auf destination aggregieren (sonst Doppelzählung).

Istio propagiert B3/W3C, generiert sie nicht. App muss eingehende Trace-Header (x-request-id, x-b3-*, traceparent) beim Ausgang erneut setzen.

Performance & Tuning

Sidecar-Sizing

Default 100m CPU / 128Mi RAM: nicht prod-tauglich bei hohem RPS. Faustregel: 1 mCore pro 100 RPS, +50 MiB pro 1000 Endpoints im Registry. Sidecar-Resource: schneidet Registry → -70 % Memory typisch.

Pilot-Tuning

PILOT_PUSH_THROTTLE: default 100. PILOT_DEBOUNCE_AFTER: default 100 ms. PILOT_DEBOUNCE_MAX: default 10 s. Bei Push-Storms (viele Pod-Restarts) Debounce hochziehen, Throttle hoch für schnellere Konvergenz auf > 5000 Workloads.

Ambient Mode (1.30 GA)

Kein Sidecar-Inject mehr. ztunnel: Node-DaemonSet, L4 mTLS. Waypoint Proxy: optional, Namespace-scoped, L7. Opt-in: Label istio.io/dataplane-mode=ambient pro Namespace. Spart RAM bei vielen Pods, kostet Komplexität beim Debugging.

Jobs & CronJobs (Sidecar-Lifecycle)

App vor proxy ready → Connect-Refused. App fertig, Sidecar läuft → Job hängt.

Native Sidecar (K8s 1.29+ Beta, Istio 1.19+): proxy als initContainer (restartPolicy: Always), proper Lifecycle. Mesh-weit via istiod-Env ENABLE_NATIVE_SIDECARS=true.

Per-Pod (Istio 1.24+, Vorrang vor Mesh-Flag): Annotation sidecar.istio.io/nativeSidecar: "true" im Pod-Template ("false" erzwingt klassischen Sidecar).

Pre-Native: holdApplicationUntilProxyStarts gegen Start-Race, trap mit POST :15020/quitquitquit auf EXIT gegen Shutdown-Hänger (feuert auch bei Crash/Signal, nicht nur bei Success).

# Native per-Pod (Istio 1.24+, schlaegt Mesh-Flag): Pod-Template
metadata:
  annotations:
    sidecar.istio.io/nativeSidecar: "true"
---
# Pre-Native-Fallback (ohne Native Sidecars):
metadata:
  annotations:
    proxy.istio.io/config: |                 # gegen Start-Race
      { "holdApplicationUntilProxyStarts": true }
spec:
  containers:
  - name: worker
    command: ["/bin/sh","-c"]
    args:
    - |
      trap 'curl -fsS -XPOST localhost:15020/quitquitquit||true' EXIT
      ./run-task

Graceful Drain: EXIT_ON_ZERO_ACTIVE_CONNECTIONS

Bei SIGTERM drainiert der Sidecar nur terminationDrainDuration (Default 5 s), dann Hard-Exit — lang lebende Verbindungen (gRPC-Streams, WebSockets, DB-Pools) werden mittendrin gekappt (503/Reset beim Rollout/Scale-Down).

Fix: EXIT_ON_ZERO_ACTIVE_CONNECTIONS=true (via proxyMetadata bzw. proxy.istio.io/config) — pilot-agent pollt aktive Envoy-Connections und beendet den Proxy sobald sie 0 erreichen statt nach fixem Timer.

Caveat: hängt eine Verbindung (Client schließt nie), blockt der Proxy bis terminationGracePeriodSeconds → SIGKILL. Grace-Period entsprechend hochsetzen. Mesh-weit via meshConfig.defaultConfig.proxyMetadata.

Multi-Cluster

Topologien & Setup

Primary-Remote: ein istiod, mehrere Workload-Cluster. Multi-Primary: istiod pro Cluster, gemeinsame Root-CA. External Control-Plane: istiod außerhalb.

Pflicht: gemeinsame trustDomain (oder trustDomainAliases), network-Label pro Cluster, Endpoint-Discovery via istioctl create-remote-secret.

istioctl create-remote-secret \
  --context=cluster-b \
  --name=cluster-b \
  | kubectl apply --context=cluster-a -f -

Diagnose

Erstes istioctl-Werkzeug bei Vorfall

istioctl proxy-status zeigt Sync-Stand jedes Sidecars. SYNCED = Config aktuell, STALE = Push läuft, NOT SENT = istiod hat nichts geschickt → Pilot-Logs prüfen.

istioctl proxy-status
istioctl proxy-config routes <pod>.<ns> -o json
istioctl proxy-config clusters <pod>.<ns>
istioctl proxy-config listeners <pod>.<ns>
istioctl proxy-config endpoints <pod>.<ns>
istioctl proxy-config secrets <pod>.<ns>

# Statisches Lint: VirtualService/DR-Konflikte etc.
istioctl analyze -n prod

# Vollstaendiger Bug-Report inkl. Konfig + Logs (anonymisiert)
istioctl bug-report

Live-Log eines Sidecars

istioctl proxy-config log <pod> --level debug setzt das Log-Level live ohne Pod-Restart. Komponenten-spezifisch z.B. --level rbac:debug,jwt:debug. Nach Diagnose zurück auf warning.

Häufige Fehlerbilder

503 UC: Upstream-Connect-Fail, App-Port stimmt nicht mit Service-Target überein.
503 NR: No Route, VirtualService greift nicht (Host-Match falsch).
503 UF: Upstream-Failure, TLS-Mismatch (PeerAuth STRICT vs. Client ohne Sidecar).
404: Path-Match nicht getroffen, Reihenfolge der http[] prüfen.

OUTPUT_CERTS-Scraping: read: connection reset by peer

App-originated mTLS (Prometheus/Alloy-Federate via ISTIO_META_OUTPUT_CERTS + /etc/istio-certs/{cert-chain,key,root-cert}.pem) bricht mit RST, obwohl Ziel-PeerAuthentication PERMISSIVE ist und Allow-all greift.

Ursache fast immer: Client-Sidecar wrapt den App-mTLS in einen zweiten ISTIO_MUTUAL-Tunnel. Eine DR mit host: "*.local" + exportTo: ["*"] (typisch STRICT-Migration-Helper in istio-system) matcht via EndpointSlice-Lookup auch direkte Pod-IP-Calls. Ergebnis: TLS-in-TLS. Ziel-15006 terminiert nur outer; inner TLS-Bytes landen als Klartext auf dem App-Port, Backend erwartet HTTP, schliesst.

PERMISSIVE ist Inbound-Entscheidung nach der Transport-Terminierung — heilt nichts, was outbound passiert.

Fix: excludeOutboundPorts am Scraper-Pod (port-scoped) oder eigene DR mit tls.mode: DISABLE auf den Ziel-Service (spezifischer als *.local, gewinnt).

# wraps der Client-Sidecar? alpn=istio* + sni=outbound_ = Beweis:
istioctl pc cluster <pod>.<ns> --fqdn <ziel> -o json \
  | jq '.[].transport_socket.typed_config|{sni,alpn_protocols}'
# welche *.local-DR greift?
kubectl get dr -A -o json | jq -r '.items[]|
  select(.spec.host|test("\\*\\.local"))|
  .metadata.namespace+"/"+.metadata.name'

Gateway API (v1, kubernetes-sigs)

Status in 1.30

Istio implementiert Gateway-API v1 (Gateway, HTTPRoute, GRPCRoute) als gleichberechtigte Alternative zu Gateway/VirtualService. Neue Projekte: Gateway-API. Bestand: networking.istio.io bleibt supportet, beide können koexistieren.

apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata: {name: web, namespace: istio-system}
spec:
  gatewayClassName: istio
  listeners:
  - name: https
    hostname: www.istio-cheatsheet.de
    port: 443
    protocol: HTTPS
    tls:
      certificateRefs:
      - {name: web-cert}
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata: {name: site, namespace: web}
spec:
  parentRefs: [{name: web, namespace: istio-system}]
  hostnames: ["www.istio-cheatsheet.de"]
  rules:
  - matches: [{path: {type: PathPrefix, value: /}}]
    backendRefs: [{name: nginx, port: 80}]

Anti-Patterns

Was du nicht tun solltest

Default-Sidecar-Resources in Prod: OOM, Push-Throttle.
Mesh-VirtualService ohne Sidecar-Resource: jeder Sidecar bekommt jede Regel, Push-Storm.
STRICT ohne Migration: nicht injizierte Workloads brechen (Jobs, externe Health-Checks).
EnvoyFilter als Default-Tool: erst Telemetry-API, WasmPlugin, AuthorizationPolicy. EnvoyFilter bricht zwischen Minors.
Tracing ohne App-Header-Propagation: Spans zerreißen.
Multi-Cluster ohne gemeinsame Root-CA: mTLS scheitert.
OUTPUT_CERTS ohne excludeOutboundPorts: Client-Sidecar wrapt App-mTLS doppelt (TLS-in-TLS) — read: connection reset by peer trotz PERMISSIVE PA.

Aus der OMNI52 Cheatsheet-Fabrik

Verwandte Sheets in dichter Senior-Qualität:
service-mesh-cheatsheet.de — Istio + Linkerd + Cilium im Vergleich
kubernetes-cheatsheet.de — Kubernetes Core
k8s-cheatsheet.de — Kubernetes-Kurzref (gleicher Inhalt, eigene Domain)
istio-spickzettel.de — Istio-Spickzettel (DE)
istio-quickref.de — Istio quick reference (EN)

Lizenz & Weiterverteilung

CC BY-SA 4.0. Du darfst dieses Cheatsheet kopieren, weiterverteilen, ausdrucken und in eigenen Materialien zitieren. Bedingung: Quellenangabe „Service Mesh Cheatsheet — OMNI52 GmbH, istio-cheatsheet.de“ bleibt sichtbar, und abgeleitete Werke stehen unter der gleichen Lizenz (Share-Alike).

Nicht erlaubt: Logo, Marken oder den Eindruck zu vermitteln, dass der Inhalt von dir/euch stammt oder dass OMNI52 GmbH die Weiterverwendung sponsort.

Volltext der Lizenz: creativecommons.org/licenses/by-sa/4.0/deed.de.

Istio is a registered trademark of The Linux Foundation. OMNI52™ is a trademark of OMNI52 GmbH (filed, not yet registered). This website is operated by OMNI52 GmbH and is not affiliated with, endorsed by, or sponsored by The Linux Foundation, the CNCF, or the Istio project. “Istio” is used in a descriptive sense to indicate the technology our consulting services focus on.