External Traffic Cluster vs Local

When external traffic lands on a Node, may that Node hand it to a Pod on another Node? With externalTrafficPolicy Cluster it may, so load spreads over every ready Pod, but SNAT replaces the client source IP even when the Node serves it itself. With Local a Node serves only its own Pods and keeps the client IP, drops traffic where it has none until a health check steers the balancer away, and an unweighted balancer splits load per Node, not per Pod.

Play the animation 5 steps, animated, best on a wide screen

External Traffic Cluster vs Local diagram: externalTrafficPolicy Cluster versus Local

External Traffic Cluster vs Local, step by step

  1. Service web is a LoadBalancer under the default externalTrafficPolicy Cluster, so every Node accepts its traffic. The balancer picks Node-3, which runs no Pod web. Node-3 SNATs the connection to its own address and forwards it across the cluster network to Pod web-3 on Node-2. Spread at random over all ready Pods, each takes about a third.

    Play from step 1
  2. The SNAT is not only for forwarded traffic. The next connection lands on Node-1 and Pod web-1 on that same Node serves it, yet under Cluster its source is still replaced with a Node-1 address. The Pod never sees 198.51.100.9, so source IP allowlists and access logs lose the client, and a forwarded connection also pays an extra hop.

    Play from step 2
  3. With externalTrafficPolicy Local a Node serves only its own Pods, forwards nothing to other Nodes and does no SNAT: Pod web-2 sees 198.51.100.9. The API server allocates healthCheckNodePort 32021, but until the balancer acts on it Node-3 still gets a third of connections and, with no local Pod, drops them. Pods web-1 and web-2 split a third.

    Play from step 3
  4. The balancer probes /healthz on port 32021 of every Node. A healthy kube-proxy answers from its count of ready local endpoints: 200 from Node-1 with two and from Node-2 with one, 503 from Node-3 with none. The balancer marks Node-3 unhealthy and sends new connections only to Node-1 and Node-2.

    Play from step 4
  5. A balancer that cannot weight its targets spreads connections per Node, not per Pod. Node-1 and Node-2 get about half each, so the two Pods on Node-1 take a quarter apiece while Pod web-3 alone takes half. That uneven load is the second cost of Local. Spreading Pods evenly across Nodes, for example with topology spread constraints, reduces it.

    Play from step 5

Sources