惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

云风的 BLOG
云风的 BLOG
Security Archives - TechRepublic
Security Archives - TechRepublic
V
Vulnerabilities – Threatpost
C
CXSECURITY Database RSS Feed - CXSecurity.com
P
Proofpoint News Feed
G
GRAHAM CLULEY
P
Privacy International News Feed
The Hacker News
The Hacker News
Forbes - Security
Forbes - Security
U
Unit 42
N
News and Events Feed by Topic
D
Darknet – Hacking Tools, Hacker News & Cyber Security
C
Cyber Attacks, Cyber Crime and Cyber Security
C
Cisco Blogs
A
About on SuperTechFans
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
D
Docker
I
Intezer
Spread Privacy
Spread Privacy
The Last Watchdog
The Last Watchdog
V2EX - 技术
V2EX - 技术
S
Security @ Cisco Blogs
F
Full Disclosure
S
Secure Thoughts
M
MIT News - Artificial intelligence
Microsoft Security Blog
Microsoft Security Blog
G
Google Developers Blog
aimingoo的专栏
aimingoo的专栏
W
WeLiveSecurity
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Project Zero
Project Zero
Recorded Future
Recorded Future
Cyberwarzone
Cyberwarzone
S
Security Affairs
AWS News Blog
AWS News Blog
H
Help Net Security
The GitHub Blog
The GitHub Blog
Hacker News: Ask HN
Hacker News: Ask HN
Vercel News
Vercel News
P
Proofpoint News Feed
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
The Register - Security
The Register - Security
S
Schneier on Security
F
Fortinet All Blogs
C
CERT Recently Published Vulnerability Notes
L
LINUX DO - 最新话题
T
Tor Project blog
T
The Exploit Database - CXSecurity.com
MongoDB | Blog
MongoDB | Blog
Webroot Blog
Webroot Blog

Devoriales - DevOps and Python Tutorials

Cloud & DevOps & AI Digest: The Week of Jun 28, 2026 Cloud & DevOps & AI Digest: The Week of Jun 20, 2026 Ansible for DevOps Engineers: Architecture, Core Concepts, and Hands-On Lab Login Must-Have Kubernetes CLI Tools Every Platform Engineer Should Know Login Login Login Why Your Best Engineers Are Quitting (And How to Stop It) Login ArgoCD Vulnerability: How the ServerSideDiff Feature Exposes Kubernetes Secrets Login How Kubernetes Controls What Your Containers Can Do Login Multi-AZ Is Not Disaster Recovery: What the AWS Bahrain Outage Finally Proved Trivy Supply Chain Attack: When Your Security Scanner Becomes the Threat Is Claude Opus 4.6 Fast Mode Really Worth 6× the Price? Login Unlocking Higher Pod Density in EKS with Prefix Delegation AWS Regional NAT Gateway: What It Is and Why You Should Care Kubernetes 1.35 Timbernetes Release AWS re:Invent 2025: The Future of Kubernetes on EKS Debate Series: How Do We Control Deployment Order in Kubernetes? Debate Series: Should We Eliminate Kubernetes Secrets Entirely? Kubernetes CRDs Explained: A Beginner-Friendly Guide to Extending the Kubernetes API Building Custom Bitnami Images: A Guide for Self-Hosted Container Images New Features in Kubernetes 1.34: An Overview From Free to Fee: How Broadcom's Bitnami Monetization Disrupts DevOps Infrastructure Claude Code Cheat Sheet: The Reference Guide Kubernetes Loses Enterprise Slack Status: Discord Among Platforms Being Considered Understanding Container Security: A Guide to Docker and Pod Security Container Patterns in Kubernetes: Init Containers, Sidecars, and Co-located Containers Explained AWS Launches Serverless MCP Server: AI-Powered Development Gets a Serverless Boost Valve Responds to Alleged Steam Data Breach Reports: What Users Need to Know ArgoCD 3.0: The Evolution Toward Secure GitOps Redis Returns to Open Source: The AGPLv3 Licensing Decision New Features in Kubernetes 1.33: An Overview Prometheus: How We Slashed Memory Usage IngressNightmare: Critical Ingress-NGINX Vulnerabilities and How to Check Your Exposure New Features in Kubernetes 1.32: An Overview What to Consider If You're Not Signing Up for Bitnami Premium Certified Kubernetes Administrator (CKA) Exam Updates for 2025 DeepSeek AI and the Question of the AI Bubble Python Tops the Tiobe Index: The Most Popular Programming Languages - January 2025 2024 in Review: IT Trends, Startups, and What’s Next Inside Argo: The Open-Source Journey Captured in a CNCF Documentary Running Docker on macOS Without Docker Desktop - updated with Kubernetes installation HashiCorp Rolls Out Terraform 2.0 at HashiConf, Keeps IBM Acquisition in the Shadows Is the EU Falling Behind in the Global AI Race? Prometheus Essentials: Node Exporter And System Monitoring Prometheus Essentials: Install and Start Monitoring Your App Prometheus Essentials: Introduction To Metric Types Kubernetes Pod Scheduling Explained: Taints, Tolerations, and Node Affinity Retrieval Augmented Generation (RAG) Explained for Beginners Like Me Using Sealed Secrets with Your Kubernetes Applications
Reduce Cloud Cross-Zone Data Transfer Costs with Kubernetes 1.33 trafficDistribution
Aleksandro Matejic · 2025-08-30 · via Devoriales - DevOps and Python Tutorials

Kubernetes - Cut Cross-zone

As an engineer managing Kubernetes clusters, I've learned that cloud costs can sneak up on you in unexpected ways.

One expense that often goes unnoticed is AWS's cross-availability zone data transfer charges.

Many organizations discover they're paying significant amounts for internal traffic between zones - costs that could be redirected to infrastructure improvements or new features. And make your CFO happy.

Cross-zone data transfer fees can become substantial for platforms with heavy inter-service communication.

Consider a platform with 30 microservices deployed across 3 availability zones - in a default Kubernetes setup, approximately 67% of inter-service traffic will cross zone boundaries due to random endpoint selection.

📘 After reading this article, if you’re a registered user, you’ll have the opportunity to take a challenge. See at the bottom

Zone A        Zone B        Zone C
┌─────┐      ┌─────┐      ┌─────┐
│ Pod │────▶ │     │      │     │  ← 33% stay local
│  X  │      │     │      │     │
└─────┘      └─────┘      └─────┘
   │           ▲             ▲
   └───────────┼─────────────┼─── ← 67% cross zones
               │             │
         (33% to B)    (33% to C)

Here's what this looks like in practice:

  • 8TB monthly internal traffic: ~5.4TB crosses zones = $1,080/month
  • 15TB monthly internal traffic: ~10TB crosses zones = $2,000/month
  • 25TB monthly internal traffic: ~16.7TB crosses zones = $3,340/month

The following is how I calculated the cost:

Total internal traffic: 8TB = 8,000 GB Cross-zone percentage: 67% (2/3 of traffic crosses zones) Cross-zone traffic: 8,000 GB × 0.67 = 5,360 GB ≈ 5.4TB

AWS rate: $0.02/GB (bi-directional: $0.01 out + $0.01 in) Monthly cost: 5,360 GB × $0.02 = $1,072 ≈ $1,080/month

Reference transfer cost

AWS charges $0.01/GB for data transfer OUT of an availability zone, and another $0.01/GB for data transfer IN to a different availability zone, making the effective rate $0.02/GB for cross-AZ communication.

These calculations are based on AWS's bi-directional charging model where both ingress and egress across availability zones incur $0.01/GB charges, as documented in the AWS Cost and Usage documentation.

These numbers might seem high, but I've worked with platforms handling massive user uploads, downloads, and heavy data processing. For high-traffic applications dealing with media, analytics, or real-time data processing, this level of data per service isn't unrealistic.

This cost reality led me to explore Kubernetes 1.33's new trafficDistribution field, specifically the PreferClose option. This feature can significantly optimize both costs and performance for multi-zone deployments.

The Cross-Zone Data Transfer Challenge

AWS charges $0.01 per GB for data that crosses availability zone boundaries. This applies to all inter-AZ communication, including:

  • Service-to-service API calls
  • Database queries from different zones
  • Load balancer health checks
  • Service mesh sidecar communication

Let me show you some examples for a 30-microservice platform:

Setup: 30 microservices, 8TB per microservice 
Cross-zone volume: 240TB × 0.67 = 160.8TB per month
Convert to GB: 160.8TB = 160,800GB
Monthly cost: 160,800GB × $0.02 = $3,216 per month
Annual cost: $38,592

The traffic pattern could be like the following:

Service A → Service B                    Monthly Traffic
order-service → payment-service          1.2TB
order-service → inventory-service        800GB
user-service → auth-service              900GB
product-service → pricing-service        600GB
cart-service → inventory-service         500GB
search-service → product-service         700GB
recommendation → user-service            400GB
notification → user-service              300GB
reporting → analytics-service            200GB
[... 20+ other service pairs]           2.4TB
                                        --------
Total                                   8.0TB

The calculation uses AWS's bi-directional pricing model where cross-AZ data transfer incurs charges for both ingress ($0.01/GB) and egress ($0.01/GB), totaling $0.02/GB for each transferred gigabyte.

Understanding trafficDistribution: PreferClose

The PreferClose traffic distribution policy instructs kube-proxy to route traffic to endpoints within the same availability zone when possible. This happens transparently at the networking layer without requiring application changes.

How it works:

  1. Endpoint Discovery: kube-proxy identifies available service endpoints
  2. Zone Classification: It groups endpoints by their zone labels (topology.kubernetes.io/zone)
  3. Local Preference: Traffic from a pod preferentially routes to endpoints in the same zone
  4. Automatic Failover: If no local endpoints are available, traffic automatically fails over to other zones

The implementation is straightforward - here is an example:

apiVersion: v1
kind: Service
metadata:
  name: payment-processor
spec:
  trafficDistribution: PreferClose
  selector:
    app: payment-processor
  ports:
  - port: 8080
    targetPort: 8080

Hands-On Implementation in EKS

Let me walk you through implementing this feature in a real EKS environment. I'll use a practical example based on a fictional payment processing system.

Setting Up the Test Environment

In this example, I'll set up an AWS EKS cluster with three nodes in three different AZs:

eksctl create cluster \
  --name zone-demo-cheap \
  --version 1.33 \
  --region eu-west-1 \
  --zones eu-west-1a,eu-west-1b,eu-west-1c \
  --nodegroup-name workers \
  --node-type t3.large \
  --nodes 3 \
  --nodes-min 3 \
  --nodes-max 3 \
  --spot

The progress:

AWS zone-demo

Verify zone distribution:

kubectl get nodes --show-labels | grep topology.kubernetes.io/zone

Example Output:

 kubectl get nodes --show-labels | grep topology.kubernetes.io/zone

ip-192-168-11-219.eu-west-1.compute.internal   Ready    <none>   6m54s   v1.33.3-eks-3abbec1   alpha.eksctl.io/cluster-name=zone-demo-cheap,alpha.eksctl.io/nodegroup-name=workers,beta.kubernetes.io/arch=amd64,beta.kubernetes.io/instance-type=t3.small,beta.kubernetes.io/os=linux,eks.amazonaws.com/capacityType=SPOT,eks.amazonaws.com/nodegroup-image=ami-0b4f0090458caff9b,eks.amazonaws.com/nodegroup=workers,eks.amazonaws.com/sourceLaunchTemplateId=lt-0fde03862beedcf85,eks.amazonaws.com/sourceLaunchTemplateVersion=1,failure-domain.beta.kubernetes.io/region=eu-west-1,failure-domain.beta.kubernetes.io/zone=eu-west-1a,k8s.io/cloud-provider-aws=29a9998df18271fac1e7912fa1cf3124,kubernetes.io/arch=amd64,kubernetes.io/hostname=ip-192-168-11-219.eu-west-1.compute.internal,kubernetes.io/os=linux,node.kubernetes.io/instance-type=t3.small,topology.k8s.aws/zone-id=euw1-az1,topology.kubernetes.io/region=eu-west-1,topology.kubernetes.io/zone=eu-west-1a
ip-192-168-57-15.eu-west-1.compute.internal    Ready    <none>   6m55s   v1.33.3-eks-3abbec1   alpha.eksctl.io/cluster-name=zone-demo-cheap,alpha.eksctl.io/nodegroup-name=workers,beta.kubernetes.io/arch=amd64,beta.kubernetes.io/instance-type=t3.small,beta.kubernetes.io/os=linux,eks.amazonaws.com/capacityType=SPOT,eks.amazonaws.com/nodegroup-image=ami-0b4f0090458caff9b,eks.amazonaws.com/nodegroup=workers,eks.amazonaws.com/sourceLaunchTemplateId=lt-0fde03862beedcf85,eks.amazonaws.com/sourceLaunchTemplateVersion=1,failure-domain.beta.kubernetes.io/region=eu-west-1,failure-domain.beta.kubernetes.io/zone=eu-west-1b,k8s.io/cloud-provider-aws=29a9998df18271fac1e7912fa1cf3124,kubernetes.io/arch=amd64,kubernetes.io/hostname=ip-192-168-57-15.eu-west-1.compute.internal,kubernetes.io/os=linux,node.kubernetes.io/instance-type=t3.small,topology.k8s.aws/zone-id=euw1-az2,topology.kubernetes.io/region=eu-west-1,topology.kubernetes.io/zone=eu-west-1b
ip-192-168-73-253.eu-west-1.compute.internal   Ready    <none>   6m54s   v1.33.3-eks-3abbec1   alpha.eksctl.io/cluster-name=zone-demo-cheap,alpha.eksctl.io/nodegroup-name=workers,beta.kubernetes.io/arch=amd64,beta.kubernetes.io/instance-type=t3.small,beta.kubernetes.io/os=linux,eks.amazonaws.com/capacityType=SPOT,eks.amazonaws.com/nodegroup-image=ami-0b4f0090458caff9b,eks.amazonaws.com/nodegroup=workers,eks.amazonaws.com/sourceLaunchTemplateId=lt-0fde03862beedcf85,eks.amazonaws.com/sourceLaunchTemplateVersion=1,failure-domain.beta.kubernetes.io/region=eu-west-1,failure-domain.beta.kubernetes.io/zone=eu-west-1c,k8s.io/cloud-provider-aws=29a9998df18271fac1e7912fa1cf3124,kubernetes.io/arch=amd64,kubernetes.io/hostname=ip-192-168-73-253.eu-west-1.compute.internal,kubernetes.io/os=linux,node.kubernetes.io/instance-type=t3.small,topology.k8s.aws/zone-id=euw1-az3,topology.kubernetes.io/region=eu-west-1,topology.kubernetes.io/zone=eu-west-1c

Multi-Service Application Architecture

This section demonstrates architecture of a microservices-based payment system across multiple availability zones in Kubernetes.

We'll deploy two complementary services that work together to process payments securely while ensuring high availability through zone distribution:

┌────────────────────────────────────────────────────────────┐
│                          Payment System Namespace          │
├────────────────────────────────────────────────────────────┤
│                                                            │
│ ┌─────────────────┐                    ┌─────────────────┐ │
│ │   Payment API   │────────────────────│ Fraud Detection │ │
│ │                 │   Transaction      │                 │ │
│ │ • Process txns  │   Analysis         │ • Risk analysis │ │
│ │ • User requests │◄───────────────────│ • Pattern detect│ │
│ │ • Validation    │   Risk Score       │ • ML algorithms │ │
│ └─────────────────┘                    └─────────────────┘ │
│          │                                       │         │
│          │                                       │         │
│          ▼                                       ▼         │
│ ┌─────────────────────────────────────────────────────────┐│
│ │                Zone Distribution                        ││
│ │  ┌─────────────────────────────────────────────────────┐││
│ │  │         Topology Spread Constraints                 │││
│ │  │         maxSkew: 1 across zones                     │││
│ │  └─────────────────────────────────────────────────────┘││
│ └─────────────────────────────────────────────────────────┘│
│                                                            │
└────────────────────────────────────────────────────────────┘

For simplicity, the live demo focuses on payment-api. Fraud Detection is included to illustrate a realistic multi-service architecture, but not exercised in the test. We'll create a small test client.

The distribution will look like this:

┌──────────────────┬──────────────────┬──────────────────┐
│    Zone A        │    Zone B        │    Zone C        │
│  eu-west-1a      │  eu-west-1b      │  eu-west-1c      │
├──────────────────┼──────────────────┼──────────────────┤
│ Payment API:     │ Payment API:     │ Payment API:     │
│ ┌───┐ ┌───┐ ┌───┐│ ┌───┐ ┌───┐ ┌───┐│ ┌───┐ ┌───┐ ┌───┐│
│ │ P │ │ P │ │ P ││ │ P │ │ P │ │ P ││ │ P │ │ P │ │ P ││
│ └───┘ └───┘ └───┘│ └───┘ └───┘ └───┘│ └───┘ └───┘ └───┘│
│                  │                  │                  │
│ Fraud Detection: │ Fraud Detection: │ Fraud Detection: │
│ ┌───┐ ┌───┐ ┌───┐│ ┌───┐ ┌───┐ ┌───┐│ ┌───┐ ┌───┐ ┌───┐│
│ │ F │ │ F │ │ F ││ │ F │ │ F │ │ F ││ │ F │ │ F │ │ F ││
│ └───┘ └───┘ └───┘│ └───┘ └───┘ └───┘│ └───┘ └───┘ └───┘│
└──────────────────┴──────────────────┴──────────────────┘
     3P + 3F           3P + 3F           3P + 3F
   (6 pods total)    (6 pods total)    (6 pods total)

The request flow:

Internet                                   Kubernetes Cluster
   │                                      ┌─────────────────────────────┐
   │                                      │     payment-system          │
   ▼                                      │        namespace            │
┌─────────┐     ┌─────────────────┐       │                             │
│  User   │────▶│  Load Balancer/ │       │  ┌─────────────────────┐    │
│ Request │     │  Ingress        │──────▶│  │   Payment API       │    │
└─────────┘     └─────────────────┘       │  │                     │    │
                                          │  │ ┌─────┐ ┌─────┐     │    │
                        ┌─────────────────│──│─│Pod 1│ │Pod 2│ ... │    │
                        │                 │  │ └─────┘ └─────┘     │    │
                        │                 │  └─────────┬───────────┘    │
                        │                 │            │                │
                        │                 │            │ Transaction    │
                        │                 │            │ Analysis       │
                        │                 │            ▼                │
                        │                 │  ┌─────────────────────┐    │
                        │                 │  │  Fraud Detection    │    │
                        │                 │  │                     │    │
                        │                 │  │ ┌─────┐ ┌─────┐     │    │
                        │ Risk Score      │  │ │Pod 1│ │Pod 2│ ... │    │
                        └─────────────────│──│ └─────┘ └─────┘     │    │
                                          │  └─────────────────────┘    │
                                          └─────────────────────────────┘

Build and Deploy Payment System Application

In this section we'll build and deploy our Payment System Application.

We add a label app: payment-api (shared by all) and a zone label (zone: a|b|c) so Services can select all endpoints, and we humans can see which zone each pod represents.

We also use a nodeSelector on topology.kubernetes.io/zone to pin each Deployment to one AWS AZ. This guarantees that endpoints exist in all three zones, making the effect of locality obvious and reproducible in the demo(In production, you’d usually prefer topologySpreadConstraints over hard pinning)

cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Namespace
metadata:
  name: payment-system
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: payment-api-a
  namespace: payment-system
spec:
  replicas: 3
  selector:
    matchLabels: { app: payment-api, zone: a }
  template:
    metadata:
      labels: { app: payment-api, zone: a }
    spec:
      nodeSelector:
        topology.kubernetes.io/zone: eu-west-1a
      containers:
      - name: echo
        image: hashicorp/http-echo:1.0.0
        args: ["-text=zone-a", "-listen=:8080"]
        ports: [{ containerPort: 8080 }]
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: payment-api-b
  namespace: payment-system
spec:
  replicas: 3
  selector:
    matchLabels: { app: payment-api, zone: b }
  template:
    metadata:
      labels: { app: payment-api, zone: b }
    spec:
      nodeSelector:
        topology.kubernetes.io/zone: eu-west-1b
      containers:
      - name: echo
        image: hashicorp/http-echo:1.0.0
        args: ["-text=zone-b", "-listen=:8080"]
        ports: [{ containerPort: 8080 }]
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: payment-api-c
  namespace: payment-system
spec:
  replicas: 3
  selector:
    matchLabels: { app: payment-api, zone: c }
  template:
    metadata:
      labels: { app: payment-api, zone: c }
    spec:
      nodeSelector:
        topology.kubernetes.io/zone: eu-west-1c
      containers:
      - name: echo
        image: hashicorp/http-echo:1.0.0
        args: ["-text=zone-c", "-listen=:8080"]
        ports: [{ containerPort: 8080 }]
---
apiVersion: v1
kind: Service
metadata:
  name: payment-api-standard
  namespace: payment-system
spec:
  selector:
    app: payment-api
  ports:
  - name: http
    port: 80
    targetPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: payment-api-optimized
  namespace: payment-system
spec:
  trafficDistribution: PreferClose
  selector:
    app: payment-api
  ports:
  - name: http
    port: 80
    targetPort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: test-client-zone-a
  namespace: payment-system
spec:
  replicas: 1
  selector:
    matchLabels: { app: test-client-zone-a }
  template:
    metadata:
      labels: { app: test-client-zone-a }
    spec:
      nodeSelector:
        topology.kubernetes.io/zone: eu-west-1a
      containers:
      - name: client
        image: curlimages/curl:8.10.1
        command: ["/bin/sh","-lc","sleep infinity"]
EOF

We've created two services:

  • Payment-api-standard (ClusterIP):

    • Selector: app: payment-api → targets all nine pods (3 per zone).

    • Port mapping: 80 → targetPort 8080 to match the container.

    • Behavior: default, random(ish) endpoint selection across zones.

  • payment-api-optimized (ClusterIP + trafficDistribution: PreferClose):

    • Same selector and ports as above.

    • Behavior: kube-proxy prefers endpoints in the client’s own AZ, only spilling over to other zones if locals aren’t available.

    • That’s the only change—same pods, different traffic policy.

By setting trafficDistribution: PreferClosein the service definition, kube-proxy prefers endpoints in the client’s own AZ

Testing Traffic Distribution With Test Client

We'll spin up one tiny client pod per Availability Zone to make the source AZ explicit and repeatable:

  • Deterministic source location. By pinning each client with nodeSelector: topology.kubernetes.io/zone: eu-west-1{a,b,c}, we know exactly which AZ each request originates from. That lets us verify whether trafficDistribution: PreferClose actually keeps traffic in-zone.

  • Apples-to-apples comparison. We run the same request loop from zone-a, zone-b, and zone-c against two Services:

    • a standard ClusterIP Service (default, random-ish endpoint selection),

    • and an optimized Service with PreferClose.

      This isolates the effect of the traffic policy—everything else (endpoints, app, cluster) is identical.

  • Noise reduction. Each client uses curlimages/curl and just sleeps (sleep infinity). We exec into it to run short bursts of requests with -H "Connection: close" so every call opens a fresh TCP connection and gets load-balanced independently (keep-alive would bias to a single pod).

  • Simple, observable outputs. Our backend replies with zone-a|b|c, so counting responses immediately shows cross-AZ vs local routing. With one replica per client and per-AZ backends, the distribution patterns are easy to read.

  • Demo pragmatism vs production reality. We pin clients here for a predictable demo. In production, you typically rely on topologySpreadConstraints to keep workloads balanced across AZs and let PreferClose handle locality—no hard pinning required.

Create one test client per AZ:

cat <<EOF | kubectl apply -f -
# test-clients.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: test-client-zone-a
  namespace: payment-system
spec:
  replicas: 1
  selector:
    matchLabels: { app: test-client-zone-a }
  template:
    metadata:
      labels: { app: test-client-zone-a }
    spec:
      # Pin to eu-west-1a so we can prove PreferClose keeps traffic local
      nodeSelector:
        topology.kubernetes.io/zone: eu-west-1a
      containers:
      - name: client
        image: curlimages/curl:8.10.1
        command: ["/bin/sh","-lc","sleep infinity"]
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: test-client-zone-b
  namespace: payment-system
spec:
  replicas: 1
  selector:
    matchLabels: { app: test-client-zone-b }
  template:
    metadata:
      labels: { app: test-client-zone-b }
    spec:
      nodeSelector:
        topology.kubernetes.io/zone: eu-west-1b
      containers:
      - name: client
        image: curlimages/curl:8.10.1
        command: ["/bin/sh","-lc","sleep infinity"]
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: test-client-zone-c
  namespace: payment-system
spec:
  replicas: 1
  selector:
    matchLabels: { app: test-client-zone-c }
  template:
    metadata:
      labels: { app: test-client-zone-c }
    spec:
      nodeSelector:
        topology.kubernetes.io/zone: eu-west-1c
      containers:
      - name: client
        image: curlimages/curl:8.10.1
        command: ["/bin/sh","-lc","sleep infinity"]
EOF

We should get:

deployment.apps/test-client-zone-a created

We now have pods up and running:

➜  ~ kubectl get pods
NAME                                  READY   STATUS    RESTARTS   AGE
payment-api-a-66fcdbfd9f-fqmmm        1/1     Running   0          13m
payment-api-a-66fcdbfd9f-mwmrg        1/1     Running   0          13m
payment-api-a-66fcdbfd9f-zvfnm        1/1     Running   0          13m
payment-api-b-869f5b8c76-r7kd4        1/1     Running   0          13m
payment-api-b-869f5b8c76-sc4jw        1/1     Running   0          13m
payment-api-b-869f5b8c76-v5jhc        1/1     Running   0          13m
payment-api-c-845dc697c7-flmch        1/1     Running   0          13m
payment-api-c-845dc697c7-sbhjz        1/1     Running   0          13m
payment-api-c-845dc697c7-xdcx6        1/1     Running   0          13m
test-client-zone-a-7899b897db-m5hxm   1/1     Running   0          10m
test-client-zone-b-c575f9b76-cnxxn    1/1     Running   0          10m
test-client-zone-c-7cbb4b9dfd-jlk5k   1/1     Running   0          10m

Test the traffic

The goal of this experiment is to observe how Kubernetes distributes Service traffic across Availability Zones (AZs) under two scenarios:

  • Standard Service (default behavior):

    Kubernetes Services route traffic to any healthy endpoint.

    Result: roughly even distribution (~33% per AZ in a 3-zone cluster), regardless of client location. Downside: most calls cross AZ boundaries, incurring AWS transfer costs.

  • Optimized Service (trafficDistribution: PreferClose):

    With this policy, kube-proxy routes traffic to endpoints in the same AZ whenever possible.

    Expectation: requests from a client in zone-a should hit pods in zone-a nearly 100% of the time. Only if no local endpoints exist will traffic spill over.

To measure this, we send 150 requests from each zone-pinned test client. We also add -H "Connection: close" so each request opens a new connection, ensuring kube-proxy load-balances each call independently:

for Z in a b c; do
  echo "=== From zone-$Z → Standard ==="
  kubectl exec -n payment-system deploy/test-client-zone-$Z -- sh -lc '
    for i in $(seq 1 150); do
      curl -sS -H "Connection: close" http://payment-api-standard.payment-system/ || echo ERR
    done' | grep -Eo "zone-[abc]" | sort | uniq -c

  echo "=== From zone-$Z → PreferClose ==="
  kubectl exec -n payment-system deploy/test-client-zone-$Z -- sh -lc '
    for i in $(seq 1 150); do
      curl -sS -H "Connection: close" http://payment-api-optimized.payment-system/ || echo ERR
    done' | grep -Eo "zone-[abc]" | sort | uniq -c
done

The astonishing result:

=== From zone-a → Standard ===
  46 zone-a
  54 zone-b
  50 zone-c
=== From zone-a → PreferClose ===
 150 zone-a
=== From zone-b → Standard ===
  51 zone-a
  43 zone-b
  56 zone-c
=== From zone-b → PreferClose ===
 150 zone-b
=== From zone-c → Standard ===
  58 zone-a
  45 zone-b
  47 zone-c
=== From zone-c → PreferClose ===
 150 zone-c

The distribution looks like this:

Client zone

Service

zone-a

zone-b

zone-c

a

Standard

52 (34.7%)

54 (36.0%)

44 (29.3%)

a

PreferClose

150 (100%)

0

0

b

Standard

44 (29.3%)

57 (38.0%)

49 (32.7%)

b

PreferClose

0

150 (100%)

0

c

Standard

53 (35.3%)

53 (35.3%)

44 (29.3%)

c

PreferClose

0

0

150 (100%)

Suppose your platform generates 20 TB of internal traffic per month. With this implementation the result is:

  • With the Standard Service, ~67% (≈13.4 TB) crosses zones. At $0.02/GB, that’s ≈ $268 per TB$3,580/month.

  • With PreferClose, almost all traffic stays in-zone. Assuming just 15% spillover due to failovers or pod imbalance (≈3 TB), the monthly bill drops to ≈ $600/month.

  • Annual savings:$36,000 for one high-traffic workload.

A tiny YAML change (trafficDistribution: PreferClose) can mean five-figure annual savings, plus lower latency for users.

Monitoring and Observability Example

We could set up monitoring to track the effectiveness of our optimization.

Once you roll this out in production, it’s important to detect when traffic starts drifting unevenly across zones

In the following example, the alert will trigger if ANY zone is handling more than 40% of total traffic. The reason is, each zone should handle: 100% ÷ 3 = 33.3% of traffic

# monitoring/service-monitor.yaml
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: zone-traffic-monitor
spec:
  selector:
    matchLabels:
      monitor: zone-traffic
  endpoints:
  - port: metrics
---
# Prometheus rule for cross-zone traffic alerting
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: zone-traffic-alerts
spec:
  groups:
  - name: cross-zone-traffic
    rules:
    - alert: HighCrossZoneTraffic
      expr: |
        (
          sum(rate(container_network_transmit_bytes_total{pod=~".*"}[5m])) by (zone) 
          / sum(rate(container_network_transmit_bytes_total[5m]))
        ) > 0.4
      for: 15m
      annotations:
        summary: "Excessive cross-zone traffic detected"
        description: "{{ $value | humanizePercentage }} of traffic is crossing zones"

Before PreferClose:
Zone A: 33% of traffic ✅
Zone B: 33% of traffic ✅  
Zone C: 34% of traffic ✅

After PreferClose (with pod imbalance):
Zone A: 60% of traffic 🚨 Alert triggered!
Zone B: 25% of traffic
Zone C: 15% of traffic

This would indicate you have too many pods in Zone A, causing clients to route most traffic there.

When PreferClose May Not Be Suitable

  • High Availability requirements: PreferClose does not reduce Kubernetes’ ability to fail over across zones, but it does change the failure dynamics. Instead of losing only a fraction of traffic, an entire zone’s traffic may shift all at once if local pods go down. For highly HA-sensitive workloads, that sudden surge can be riskier than a steady multi-AZ distribution.

  • Uneven pod distribution: If pods are not evenly spread across zones, locality preference can overload one AZ while underutilizing others.

  • Cost vs resilience trade-off: Some organizations value the simplicity of balanced distribution more than the cost savings.

Wrapping Up

A small YAML change can mean five-figure annual savings. 🚀

The trafficDistribution: PreferClose feature represents a really great advancement in Kubernetes cost optimization capabilities. Organizations implementing this feature across their services could typically expect cross-zone data transfer cost reductions between 75-85%, translating to substantial annual savings.

For example, a 30-microservice platform with 20TB monthly internal traffic could potentially save $10,000-$12,000 annually by implementing PreferClose across their services.

The implementation is straightforward, the risk is pretty minimal with proper testing, and the benefits compound as your platform scales. For DevOps teams managing cost-conscious environments, this feature should be a standard part of your optimization toolkit.

Start with your highest-traffic, most stable services and gradually expand coverage. Monitor the impact closely, and adjust your approach based on observed traffic patterns and cost reductions.

Your finance team will appreciate the reduced cloud bills, and your applications will benefit from the locality improvements.