Sidecar sizing
Default requests 100m / 128Mi, limits 2 CPU / 1Gi: not prod-grade at high RPS.
Istio benchmark (1.24, 1000 RPS, 1 KB, 2 workers): sidecar ≈ 0.20 vCPU + 60 MB, waypoint ≈ 0.25 vCPU + 60 MB, ztunnel ≈ 0.06 vCPU + 12 MB.
Memory scales with the config the proxy holds:
Sidecar/exportTo trim it.
Pilot tuning
PILOT_PUSH_THROTTLE: default 0 = auto,
min(15 + 5 × GOMAXPROCS, 100).
PILOT_DEBOUNCE_AFTER: default 100 ms.
PILOT_DEBOUNCE_MAX: default 10 s. On push storms
(many pod restarts) raise debounce; for faster convergence raise
throttle together with istiod CPU.
Ambient mode (GA since 1.24)
No sidecar injection. ztunnel:
node DaemonSet, L4 mTLS (HBONE). Waypoint: optional
Envoy for L7, per namespace, service or pod
(istio.io/use-waypoint). Opt-in: label
istio.io/dataplane-mode=ambient (namespace or pod).
1.31: weighted waypoint canaries
(istio.io/use-waypoint-canary +
...-canary-weight).
Not in ambient: EnvoyFilter on waypoints, the
Sidecar resource, PeerAuthentication
DISABLE (ignored). VirtualService on waypoints is alpha:
use HTTPRoute, never mix both.
Saves RAM at high pod counts, costs complexity when debugging.
Jobs & CronJobs (sidecar lifecycle)
App before proxy ready → connection refused. App done, sidecar still running → the job hangs.
Native sidecar (K8s 1.33+ GA): proxy as an
initContainer (restartPolicy: Always),
proper lifecycle. Default since Istio 1.27:
ENABLE_NATIVE_SIDECARS=auto, native only when every node
runs kubelet ≥ 1.33 (mixed clusters during a node upgrade get the
classic sidecar).
Per pod (1.24+, beats the mesh setting):
sidecar.istio.io/nativeSidecar: "false" forces the
classic sidecar, "true" forces native.
Pre-native:
holdApplicationUntilProxyStarts against the start race,
trap with POST :15020/quitquitquit
on EXIT against shutdown hangs (fires on
crash/signal too, not only on success).
# Pre-native fallback (without native sidecars):
metadata:
annotations:
proxy.istio.io/config: | # 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
Classic sidecar: on SIGTERM the sidecar only drains for
terminationDrainDuration (default 5 s), then
hard-exits, long-lived connections (gRPC streams, WebSockets,
DB pools) are cut mid-flight (503/reset on rollout/scale-down).
Fix:
EXIT_ON_ZERO_ACTIVE_CONNECTIONS=true (via
proxyMetadata or proxy.istio.io/config):
pilot-agent waits MINIMUM_DRAIN_DURATION (default
5 s), then polls active Envoy connections and stops the
proxy as soon as they reach 0 instead of on a fixed
timer; terminationDrainDuration no longer applies.
Caveat: if a connection hangs (client never
closes), the proxy blocks until
terminationGracePeriodSeconds → SIGKILL. Raise the
grace period accordingly. Mesh-wide via
meshConfig.defaultConfig.proxyMetadata.
Native sidecar (default since 1.27): kubelet stops the proxy only after the app has exited, so the race mostly applies to the classic mode.