ctx: prod
back to posts
$kubectl describepost/k8s-trafficdistribution-cross-az

One field in Kubernetes 1.34 vs your cross-AZ bill

Kubernetes 1.34 landed with the usual sweep of release-notes coverage, and the traffic-distribution change got filed where these always get filed: under "networking refinements." Lower latency, less bandwidth, same-node routing for DNS caches. All true.

It's also a FinOps lever, and almost nobody is reading it that way. On AWS, "keep traffic in the same zone" is a latency win and also money you stop handing to the cross-AZ data-transfer meter.

Here's the honest version of what changed, what didn't, and how to actually use it.

The 60-second version — flip through the deck8 slides · swipe →
The charge

Cross-AZ, every hop

3 AZs "for HA" + default routing = $0.01/GB each way, all day.

The knob

One line on the Service

trafficDistribution: PreferSameZone. kube-proxy used to spread blind to cost.

Be honest

In-zone isn't new

PreferClose is GA since 1.31. 1.34 adds a clearer name + PreferSameNode.

Safety

A preference, not a pin

No local endpoint? Traffic falls back cross-zone. HA intact.

takeaway

Stop paying to leave the zone

It won't fix a bad topology — it stops the tax on traffic that never needed to cross.

The charge nobody put on the slide

Spread your workloads across three Availability Zones (the default advice for resilience) and you've also signed up for a running cost. Inside AWS, data crossing an AZ boundary costs $0.01/GB in each direction. A request from a pod in us-east-1a to a Service endpoint that happens to live in us-east-1b pays on the way out and on the way back.

On AWS, "keep it in the same zone" is a latency optimization and a line-item on your bill.

For a chatty internal architecture (service mesh, sidecars, high-QPS internal APIs) that's not a rounding error. And historically, kube-proxy made it worse by design: it load-balanced a Service's traffic across all healthy endpoints equally, in every zone, with no awareness that some of those endpoints were on the expensive side of an AZ boundary.

What 1.34 actually changed (and what it didn't)

This is where most write-ups overclaim, so let me be precise. Keeping traffic in-zone is not new. The trafficDistribution field with value PreferClose has been GA since Kubernetes 1.31. If you're on 1.31+ you could already ask for zone-local routing.

What KEP-3015 does in 1.34 (beta, and its feature gate is on by default) is two things: it gives PreferClose a clearer name, and it adds a sharper tool.

the three values, honestly
PreferCloseGA since 1.31. Keep traffic in the caller's zone. Now deprecated in favor of the clearer name.old
PreferSameZoneSame semantics as PreferClose, unambiguous name. The one to reach for on zone-spread services.1.34
PreferSameNodePrefer an endpoint on the same node as the caller. Zero cross-AZ and zero cross-node hop.1.34

PreferSameNode is the genuinely new capability. It's built for workloads where a local replica exists on every node: a node-local DNS cache, a per-node sidecar, a DaemonSet-shaped service. In those cases you don't just avoid crossing zones; you don't leave the node at all.

Using it

The change is a single field on the Service:

apiVersion: v1
kind: Service
metadata:
  name: internal-api
spec:
  selector:
    app: internal-api
  trafficDistribution: PreferSameZone   # or PreferSameNode
  ports:
    - port: 8080

That's the whole change. kube-proxy on each node now prefers endpoints in its own zone (or on its own node) and only reaches across when it has to.

The safety net that makes it shippable

The reason you can set this without a 3 a.m. incident is that it's a preference, not a pin.

how it degrades
Local endpoint healthystay in-zone → cut cost
Local endpoints gonefall back cross-zone
Availability preservedno dropped traffic

If the zone-local endpoints are unhealthy or simply absent, traffic routes to another zone as it always did. You cut cost when there's a local option and keep availability when there isn't. That asymmetry is exactly what you want from a cost optimization: it never trades away uptime to save a dollar.

Where it bites

Two honest caveats:

  • It only helps if endpoints are actually distributed. If all replicas of a Service sit in one zone, PreferSameZone does nothing useful for callers elsewhere, and can create hotspots. Pair it with a sane spread of replicas.
  • PreferSameNode needs a replica per node to be worth it. It shines for DaemonSet-style workloads and node-local caches; for a 3-replica Deployment on a 40-node cluster, most nodes have no local endpoint and you're back to zonal or cross-zonal routing.

Where I've landed

This is a small feature with an unglamorous payoff, which is exactly why it's worth a second look. It won't rescue a badly spread architecture, and it isn't a substitute for measuring your data-transfer costs in the first place. But for the very common case (services spread across AZs for resilience, chatting all day, paying cross-AZ on traffic that had a perfectly good local endpoint) it turns a silent recurring charge into a one-line decision.

Read the 1.34 networking notes again with the invoice open next to them. The "refinement" everyone skimmed is a cost knob.


Are you setting trafficDistribution on your Services, or letting kube-proxy spread across zones by default? And has anyone actually put a number on their cross-AZ line? I'd love to hear real before/after figures. I collect these.