๐Ÿš€ Kubernetes Topology Aware Routing ์™„์ „์ •๋ณต ๊ฐ€์ด๋“œ

dongdorrongยท2025๋…„ 7์›” 20์ผ

Kubernetes

๋ชฉ๋ก ๋ณด๊ธฐ
9/13

์ฟ ๋ฒ„๋„คํ‹ฐ์Šค์—์„œ ๋„คํŠธ์›Œํฌ ํŠธ๋ž˜ํ”ฝ ์ตœ์ ํ™”์˜ ํ•ต์‹ฌ ๊ธฐ๋Šฅ์ธ Topology Aware Routing์— ๋Œ€ํ•ด ์‹ค๋ฌด ๊ด€์ ์—์„œ ์™„์ „ ์ •๋ณตํ•˜์ž

๐Ÿ“ ๊ฐœ์š”

Topology Aware Routing(์ด์ „๋ช…: Topology Aware Hints)๋Š” ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค 1.23์—์„œ ๋ฒ ํƒ€ ๊ธฐ๋Šฅ์œผ๋กœ ๋„์ž…๋˜์—ˆ์œผ๋ฉฐ, 1.27๋ถ€ํ„ฐ ํ˜„์žฌ์˜ ์ด๋ฆ„์œผ๋กœ ๋ณ€๊ฒฝ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. Amazon EKS์—์„œ๋Š” 1.24๋ถ€ํ„ฐ ์ง€์›ํ•˜๋Š” ๊ธฐ๋Šฅ์œผ๋กœ, ๋™์ผํ•œ ๊ฐ€์šฉ ์˜์—ญ(Availability Zone) ๋‚ด์—์„œ ํŠธ๋ž˜ํ”ฝ์„ ์œ ์ง€ํ•˜์—ฌ ๋„คํŠธ์›Œํฌ ์ง€์—ฐ ์‹œ๊ฐ„๊ณผ ๋น„์šฉ์„ ์ค„์ด๋Š” ๊ฒƒ์„ ๋ชฉํ‘œ๋กœ ํ•ฉ๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ๋ชจ๋“  ํ™˜๊ฒฝ์—์„œ ์ž‘๋™ํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋ฉฐ, ํŠน์ • ์กฐ๊ฑด์„ ๋งŒ์กฑํ•ด์•ผ ํšจ๊ณผ๋ฅผ ๋ฐœํœ˜ํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ฐ€์ด๋“œ์—์„œ๋Š” ์ด๋ก ์  ์„ค๋ช…๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์‹ค๋ฌด์—์„œ ๋งˆ์ฃผ์น˜๋Š” ๋‹ค์–‘ํ•œ ์ƒํ™ฉ๋“ค๊ณผ ํ•ด๊ฒฐ์ฑ…์„ ์ œ์‹œํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ”„ ์ด๋ฆ„ ๋ณ€ํ™” ํžˆ์Šคํ† ๋ฆฌ

  • Kubernetes 1.21~1.22: Topology Aware Hints (alpha)
  • Kubernetes 1.23~1.26: Topology Aware Hints (beta)
  • Kubernetes 1.27+: Topology Aware Routing์œผ๋กœ ๋ช…๋ช… ๋ณ€๊ฒฝ

๐ŸŽฏ ํ•ต์‹ฌ ๊ฐœ๋…

๊ธฐ๋ณธ ๋™์ž‘ ์›๋ฆฌ

Topology Aware Routing์€ kube-proxy๊ฐ€ Service์˜ ์—”๋“œํฌ์ธํŠธ๋ฅผ ์„ ํƒํ•  ๋•Œ ํ† ํด๋กœ์ง€ ์ •๋ณด๋ฅผ ํ™œ์šฉํ•˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

# Service ์˜ˆ์‹œ
apiVersion: v1
kind: Service
metadata:
  name: my-service
  annotations:
    service.kubernetes.io/topology-mode: "auto"
spec:
  selector:
    app: my-app
  ports:
  - port: 80
    targetPort: 8080

๐Ÿ’ก ์ฃผ์š” ์ด์ 

  1. ๋„คํŠธ์›Œํฌ ์ง€์—ฐ ์‹œ๊ฐ„ ๊ฐ์†Œ: ๋™์ผ AZ ๋‚ด ํ†ต์‹ ์œผ๋กœ ์ง€์—ฐ ์‹œ๊ฐ„ ์ตœ์†Œํ™”
  2. ๋ฐ์ดํ„ฐ ์ „์†ก ๋น„์šฉ ์ ˆ์•ฝ: ํฌ๋กœ์Šค-AZ ํŠธ๋ž˜ํ”ฝ ๋น„์šฉ ์ œ๊ฑฐ
  3. ์ž๋™ ์ตœ์ ํ™”: ์ˆ˜๋™ ์„ค์ • ์—†์ด ์ž๋™์œผ๋กœ ์ตœ์  ๋ผ์šฐํŒ…

โš™๏ธ ์ž‘๋™ ๋ฉ”์ปค๋‹ˆ์ฆ˜

EndpointSlice Controller์˜ ์—ญํ• 

EndpointSlice Controller๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ณผ์ •์œผ๋กœ ํžŒํŠธ๋ฅผ ํ• ๋‹นํ•ฉ๋‹ˆ๋‹ค:

  1. Pod ๋ถ„์‚ฐ ํ™•์ธ: ๊ฐ zone๋ณ„ Pod ์ˆ˜ ๊ณ„์‚ฐ
  2. ๋น„๋ก€ ํ• ๋‹น: ๊ฐ zone์˜ Pod ์ˆ˜์— ๋น„๋ก€ํ•˜์—ฌ ์—”๋“œํฌ์ธํŠธ ํ• ๋‹น
  3. ํžŒํŠธ ์ƒ์„ฑ: ๊ฐ ์—”๋“œํฌ์ธํŠธ์— hints.forZones ํ•„๋“œ ์ถ”๊ฐ€
# EndpointSlice ์˜ˆ์‹œ
apiVersion: discovery.k8s.io/v1
kind: EndpointSlice
metadata:
  name: my-service-abc123
endpoints:
- addresses:
  - "10.1.2.3"
  hints:
    forZones:
    - name: "zone-a"

kube-proxy ๋™์ž‘

kube-proxy๋Š” ํžŒํŠธ๊ฐ€ ์žˆ๋Š” ์—”๋“œํฌ์ธํŠธ๋ฅผ ์šฐ์„ ์ ์œผ๋กœ ์‚ฌ์šฉ:

# iptables ๊ทœ์น™ ์˜ˆ์‹œ (์‹ค์ œ๋กœ๋Š” ๋” ๋ณต์žก)
-A KUBE-SVC-XYZ -m comment --comment "zone-a endpoints only" \
  -j KUBE-SEP-LOCAL-ZONE

๐Ÿ“‹ ์‚ฌ์šฉ ์กฐ๊ฑด ๋ฐ ์ œํ•œ์‚ฌํ•ญ

โœ… ์‚ฌ์šฉ ๊ฐ€๋Šฅ ์กฐ๊ฑด

  1. ๊ท ๋“ฑ ๋ถ„์‚ฐ: ์›Œํฌ๋กœ๋“œ๊ฐ€ ๋ชจ๋“  zone์— ๊ท ๋“ฑํ•˜๊ฒŒ ๋ถ„์‚ฐ๋˜์–ด์•ผ ํ•จ
  2. ์ถฉ๋ถ„ํ•œ ์—”๋“œํฌ์ธํŠธ: ๊ฐ zone์— ์ตœ์†Œ 1๊ฐœ ์ด์ƒ์˜ ์—”๋“œํฌ์ธํŠธ ์กด์žฌ
  3. Service ํƒ€์ž…: ClusterIP, NodePort, LoadBalancer ์ง€์›

โŒ ์‚ฌ์šฉ ๋ถˆ๊ฐ€ ์กฐ๊ฑด

# ๋ถˆ๊ท ๋“ฑ ๋ถ„์‚ฐ ์˜ˆ์‹œ (๋™์ž‘ํ•˜์ง€ ์•Š์Œ)
# Zone A: 10 pods
# Zone B: 2 pods  
# Zone C: 1 pod

โš ๏ธ ์‹ค๋ฌด์—์„œ ํ”ํ•œ ์‹ค์ˆ˜๋“ค

1. ๊ฐœ๋ฐœ ํ™˜๊ฒฝ ๋‹จ์ผ ํŒŒ๋“œ (์ž‘๋™ ์•ˆํ•จ โŒ)

# ๊ฐœ๋ฐœํ™˜๊ฒฝ์—์„œ ํ”ํ•œ ์‹ค์ˆ˜
apiVersion: apps/v1
kind: Deployment
spec:
  replicas: 1  # โ† ํŒŒ๋“œ 1๊ฐœ๋งŒ ์žˆ์œผ๋ฉด TAR ๋น„ํ™œ์„ฑํ™”!
---
apiVersion: v1
kind: Service
metadata:
  annotations:
    service.kubernetes.io/topology-mode: "auto"  # โ† ์„ค์ •ํ•ด๋„ ๋ฌด์‹œ๋จ

2. ์ด์ค‘ํ™” 2๋Œ€ ๊ตฌ์„ฑ (๋Œ€๋ถ€๋ถ„ ์ž‘๋™ ์•ˆํ•จ โš ๏ธ)

# ๋น„์šฉ ์ ˆ์•ฝ์„ ์œ„ํ•œ 2๋Œ€ ์ด์ค‘ํ™” - TAR ์ œํ•œ์ 
spec:
  replicas: 2  # 3๊ฐœ zone์—์„œ๋Š” ๋ถˆ๊ท ๋“ฑ ๋ถ„์‚ฐ์œผ๋กœ TAR ๋น„ํ™œ์„ฑํ™”
  
# ์‹ค์ œ ๋ฐฐ์น˜ ์˜ˆ์‹œ:
# Zone A: 1๊ฐœ ํŒŒ๋“œ
# Zone B: 1๊ฐœ ํŒŒ๋“œ  
# Zone C: 0๊ฐœ ํŒŒ๋“œ โ† ๋นˆ zone์œผ๋กœ ์ธํ•ด TAR ๋น„ํ™œ์„ฑํ™”

์ œํ•œ์‚ฌํ•ญ

  • ExternalName Service: ์ง€์›ํ•˜์ง€ ์•Š์Œ
  • Headless Service: ๋ถ€๋ถ„์  ์ง€์›
  • ๋ถˆ๊ท ๋“ฑ ๋ถ„์‚ฐ: ์ž๋™์œผ๋กœ ํžŒํŠธ๊ฐ€ ์ œ๊ฑฐ๋จ
  • ํŒŒ๋“œ ์ˆ˜ < Zone ์ˆ˜: EndpointSlice controller๊ฐ€ ํžŒํŠธ ์ƒ์„ฑ ์•ˆํ•จ
  • Zone๋‹น ํŒŒ๋“œ 3๊ฐœ ๋ฏธ๋งŒ: 50% ํ™•๋ฅ ๋กœ ํžŒํŠธ ์ƒ์„ฑ ์‹คํŒจ

๐Ÿ”ง ๊ตฌ์„ฑ ๋ฐฉ๋ฒ•

1. Service ์–ด๋…ธํ…Œ์ด์…˜ ์„ค์ •

apiVersion: v1
kind: Service
metadata:
  name: my-service
  annotations:
    # ์ž๋™ ๋ชจ๋“œ (๊ถŒ์žฅ)
    service.kubernetes.io/topology-mode: "auto"
spec:
  selector:
    app: my-app
  ports:
  - port: 80

2. Deployment ๋ฐฐํฌ ์ „๋žต

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  replicas: 6  # zone๋‹น 2๊ฐœ์”ฉ ๊ท ๋“ฑ ๋ฐฐํฌ
  template:
    spec:
      # Zone ๊ฐ„ ๊ท ๋“ฑ ๋ถ„์‚ฐ์„ ์œ„ํ•œ ์„ค์ •
      topologySpreadConstraints:
      - maxSkew: 1
        topologyKey: topology.kubernetes.io/zone
        whenUnsatisfiable: DoNotSchedule
        labelSelector:
          matchLabels:
            app: my-app

๐Ÿ“Š ์„ฑ๋Šฅ ํšจ๊ณผ ๋ถ„์„

์ง€์—ฐ ์‹œ๊ฐ„ ๊ฐœ์„ 

์‹œ๋‚˜๋ฆฌ์˜ค๊ธฐ๋ณธ ์„ค์ •Topology Aware Hints๊ฐœ์„ ์œจ
๋™์ผ AZ ํ†ต์‹ ~1ms~0.5ms50%
ํฌ๋กœ์Šค AZ ํ†ต์‹ ~3-5ms~0.5ms80-90%

๋น„์šฉ ์ ˆ๊ฐ ํšจ๊ณผ

# AWS ๋ฐ์ดํ„ฐ ์ „์†ก ๋น„์šฉ ์˜ˆ์‹œ
# ํฌ๋กœ์Šค-AZ: $0.01/GB
# ๋™์ผ-AZ: $0.00/GB

# ์›” 1TB ๋ฐ์ดํ„ฐ ์ „์†ก ์‹œ
# ๊ธฐ์กด: $10.24 (ํฌ๋กœ์Šค-AZ)
# ์ ์šฉ ํ›„: $0 (๋™์ผ-AZ)
# ์ ˆ์•ฝ: 100%

๐Ÿ› ๏ธ ๋ชจ๋‹ˆํ„ฐ๋ง ๋ฐ ํŠธ๋Ÿฌ๋ธ”์ŠˆํŒ…

1. ํด๋Ÿฌ์Šคํ„ฐ Zone ๊ตฌ์„ฑ ํ™•์ธ

# Zone ์ˆ˜ ํ™•์ธ (๊ฐ€์žฅ ์ค‘์š”!)
kubectl get nodes -o jsonpath='{.items[*].metadata.labels.topology\.kubernetes\.io/zone}' | tr ' ' '\n' | sort -u | wc -l

# Zone ๋ชฉ๋ก ํ™•์ธ
kubectl get nodes -o custom-columns="NAME:.metadata.name,ZONE:.metadata.labels['topology\.kubernetes\.io/zone']"

# Zone๋ณ„ ๋…ธ๋“œ ๋ถ„ํฌ ํ™•์ธ
kubectl get nodes -o json | jq -r '.items[] | .metadata.labels["topology.kubernetes.io/zone"]' | sort | uniq -c

์ถœ๋ ฅ ์˜ˆ์‹œ:

   2 ap-northeast-2a
   2 ap-northeast-2b  
   2 ap-northeast-2c
# โ†’ 3๊ฐœ zone, TAR ์ ์šฉ ๊ฐ€๋Šฅ โœ…

2. Zone ์ •๋ณด ์ข…ํ•ฉ ํ™•์ธ ์Šคํฌ๋ฆฝํŠธ

#!/bin/bash
# zone-check.sh - TAR ์ ์šฉ ๊ฐ€๋Šฅ์„ฑ ์ž๋™ ํŒ๋‹จ

ZONE_COUNT=$(kubectl get nodes -o jsonpath='{.items[*].metadata.labels.topology\.kubernetes\.io/zone}' | tr ' ' '\n' | sort -u | wc -l)

echo "=== Topology Aware Routing ์ ์šฉ ๊ฐ€๋Šฅ์„ฑ ๋ถ„์„ ==="
echo "๐Ÿ“Š ์ด Zone ์ˆ˜: $ZONE_COUNT"

case $ZONE_COUNT in
    1)
        echo "โŒ TAR ์ ์šฉ ๋ถˆ๊ฐ€ (Single AZ)"
        echo "๐Ÿ’ก ๊ถŒ์žฅ: ๊ธฐ๋ณธ ๋กœ๋“œ๋ฐธ๋Ÿฐ์‹ฑ ์‚ฌ์šฉ"
        ;;
    2) 
        echo "โš ๏ธ TAR ์ œํ•œ์  ์ ์šฉ ๊ฐ€๋Šฅ"
        echo "๐Ÿ’ก ๊ถŒ์žฅ: ํŒŒ๋“œ 2๊ฐœ ์ด์ƒ + ๊ท ๋“ฑ ๋ถ„์‚ฐ ํ•„์ˆ˜"
        ;;
    3)
        echo "โœ… TAR ์ตœ์ ํ™” ๊ฐ€๋Šฅ"
        echo "๐Ÿ’ก ๊ถŒ์žฅ: ํŒŒ๋“œ ์ตœ์†Œ 3๊ฐœ (zone๋‹น 1๊ฐœ์”ฉ)"
        echo "๐Ÿš€ ์ด์ƒ์ : ํŒŒ๋“œ 9๊ฐœ ์ด์ƒ (zone๋‹น 3๊ฐœ์”ฉ)"
        ;;
    *)
        echo "โœ… TAR ์ตœ์ ํ™” ๊ฐ€๋Šฅ"
        echo "๐Ÿ’ก ๊ถŒ์žฅ: ํŒŒ๋“œ ์ตœ์†Œ ${ZONE_COUNT}๊ฐœ (zone๋‹น 1๊ฐœ์”ฉ)"
        ;;
esac

3. EndpointSlice ํžŒํŠธ ํ™•์ธ

# EndpointSlice ํžŒํŠธ ํ™•์ธ
kubectl get endpointslices -o yaml | grep -A5 hints

# ํŠน์ • ์„œ๋น„์Šค์˜ EndpointSlice ์ƒ์„ธ ํ™•์ธ
kubectl describe endpointslices -l kubernetes.io/service-name=my-service

2. Service ์ƒํƒœ ํ™•์ธ

# Service ์ด๋ฒคํŠธ ํ™•์ธ
kubectl describe service my-service

# ํžŒํŠธ ๊ด€๋ จ ๋กœ๊ทธ ํ™•์ธ
kubectl logs -n kube-system -l component=kube-proxy | grep topology

3. ์ผ๋ฐ˜์ ์ธ ๋ฌธ์ œ ํ•ด๊ฒฐ

ํžŒํŠธ๊ฐ€ ์ƒ์„ฑ๋˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ

# Pod ๋ถ„์‚ฐ ์ƒํƒœ ํ™•์ธ
kubectl get pods -o wide --show-labels | grep my-app

# Zone๋ณ„ Pod ์ˆ˜ ํ™•์ธ
kubectl get nodes --show-labels | grep topology.kubernetes.io/zone

๋ถˆ๊ท ๋“ฑ ๋ถ„์‚ฐ ํ•ด๊ฒฐ

# PodDisruptionBudget์„ ํ†ตํ•œ ์•ˆ์ •์  ๋ฐฐํฌ
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: my-app-pdb
spec:
  minAvailable: 1
  selector:
    matchLabels:
      app: my-app

โš ๏ธ ์ฃผ์˜์‚ฌํ•ญ ๋ฐ ์‹ค๋ฌด ๊ถŒ์žฅ์‚ฌํ•ญ

1. ํ™˜๊ฒฝ๋ณ„ TAR ์ ์šฉ ๊ฐ€์ด๋“œ

๐Ÿ”ฌ ๊ฐœ๋ฐœ/ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ

# ๋น„์šฉ ์šฐ์„  โ†’ TAR ๋น„ํ™œ์„ฑํ™” ๊ถŒ์žฅ
apiVersion: apps/v1
kind: Deployment
spec:
  replicas: 1-2  # ์ตœ์†Œ ๋ฆฌ์†Œ์Šค
---
apiVersion: v1
kind: Service  
metadata:
  annotations:
    # TAR ๋ช…์‹œ์  ๋น„ํ™œ์„ฑํ™” (๋ถˆํ•„์š”ํ•œ ์˜ค๋ฒ„ํ—ค๋“œ ๋ฐฉ์ง€)
    service.kubernetes.io/topology-mode: "disabled"

๐Ÿญ ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ

# ์„ฑ๋Šฅ + ๋น„์šฉ ์ ˆ์•ฝ โ†’ TAR ์ ๊ทน ํ™œ์šฉ
apiVersion: apps/v1
kind: Deployment
spec:
  replicas: 6  # zone ์ˆ˜(3) ร— 2 = ๊ท ๋“ฑ ๋ถ„์‚ฐ
  template:
    spec:
      topologySpreadConstraints:
      - maxSkew: 1
        topologyKey: topology.kubernetes.io/zone
        whenUnsatisfiable: DoNotSchedule
---
apiVersion: v1
kind: Service
metadata:
  annotations:
    service.kubernetes.io/topology-mode: "auto"

2. Zone ์ˆ˜์— ๋”ฐ๋ฅธ ์ตœ์  ๊ตฌ์„ฑ

Zone ์ˆ˜์ตœ์†Œ ํŒŒ๋“œ ์ˆ˜๊ถŒ์žฅ ํŒŒ๋“œ ์ˆ˜TAR ํšจ๊ณผ
1๊ฐœN/AN/AโŒ ๋ถˆ๊ฐ€๋Šฅ
2๊ฐœ2๊ฐœ4๊ฐœ ์ด์ƒโš ๏ธ ์ œํ•œ์ 
3๊ฐœ3๊ฐœ9๊ฐœ ์ด์ƒโœ… ์ตœ์ 
4๊ฐœ+zone ์ˆ˜zone ร— 3โœ… ์ตœ์ 

3. ๋น„์šฉ vs ์„ฑ๋Šฅ ๋ถ„์„

๐Ÿ’ฐ ๋น„์šฉ ๊ด€์ 

# ์‹œ๋‚˜๋ฆฌ์˜ค 1: TAR ๋ฏธ์ ์šฉ (2๋Œ€ ์ด์ค‘ํ™”)
์›” ์ธ์Šคํ„ด์Šค ๋น„์šฉ: $200 ร— 2 = $400
ํฌ๋กœ์Šค-AZ ๋ฐ์ดํ„ฐ ์ „์†ก: $10-50/์›” (ํŠธ๋ž˜ํ”ฝ์— ๋”ฐ๋ผ)
์ด๋น„์šฉ: $410-450/์›”

# ์‹œ๋‚˜๋ฆฌ์˜ค 2: TAR ์ ์šฉ (3๋Œ€ ๋ถ„์‚ฐ)  
์›” ์ธ์Šคํ„ด์Šค ๋น„์šฉ: $200 ร— 3 = $600
ํฌ๋กœ์Šค-AZ ๋ฐ์ดํ„ฐ ์ „์†ก: $0-5/์›” (๊ฑฐ์˜ ์ œ๊ฑฐ)
์ด๋น„์šฉ: $600-605/์›”

# ROI ๊ณ„์‚ฐ: ๋†’์€ ํŠธ๋ž˜ํ”ฝ์ผ์ˆ˜๋ก TAR์ด ์œ ๋ฆฌ!

4. ๊ฐ€์šฉ์„ฑ vs ์„ฑ๋Šฅ ํŠธ๋ ˆ์ด๋“œ์˜คํ”„

# ๋†’์€ ๊ฐ€์šฉ์„ฑ์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ ๋น„ํ™œ์„ฑํ™” ๊ณ ๋ ค
metadata:
  annotations:
    service.kubernetes.io/topology-mode: "disabled"

5. ๋™์  ์Šค์ผ€์ผ๋ง ๊ณ ๋ ค

# HPA ์‚ฌ์šฉ ์‹œ zone ๊ท ํ˜• ์œ ์ง€ ํ•„์ˆ˜!
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: my-app-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: my-app
  minReplicas: 3   # zone ์ˆ˜์™€ ๋™์ผํ•˜๊ฒŒ ์„ค์ •
  maxReplicas: 12  # zone ์ˆ˜์˜ ๋ฐฐ์ˆ˜๋กœ ์„ค์ •

๐Ÿš€ ์‹ค์Šต ์˜ˆ์ œ

์ „์ฒด ๊ตฌ์„ฑ ์˜ˆ์‹œ

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app
  labels:
    app: web-app
spec:
  replicas: 6
  selector:
    matchLabels:
      app: web-app
  template:
    metadata:
      labels:
        app: web-app
    spec:
      containers:
      - name: web
        image: nginx:alpine
        ports:
        - containerPort: 80
        resources:
          requests:
            cpu: 100m
            memory: 128Mi
          limits:
            cpu: 200m
            memory: 256Mi
      # ๊ท ๋“ฑ ๋ถ„์‚ฐ ๋ณด์žฅ
      topologySpreadConstraints:
      - maxSkew: 1
        topologyKey: topology.kubernetes.io/zone
        whenUnsatisfiable: DoNotSchedule
        labelSelector:
          matchLabels:
            app: web-app

---
apiVersion: v1
kind: Service
metadata:
  name: web-service
  annotations:
    service.kubernetes.io/topology-mode: "auto"
spec:
  selector:
    app: web-app
  ports:
  - name: http
    port: 80
    targetPort: 80
  type: ClusterIP

๊ฒ€์ฆ ์Šคํฌ๋ฆฝํŠธ

#!/bin/bash
# topology-check.sh

echo "=== Topology Aware Hints ๊ฒ€์ฆ ==="

# 1. Service ํžŒํŠธ ๋ชจ๋“œ ํ™•์ธ
echo "1. Service ์–ด๋…ธํ…Œ์ด์…˜ ํ™•์ธ:"
kubectl get service web-service -o jsonpath='{.metadata.annotations}' | jq

# 2. EndpointSlice ํžŒํŠธ ํ™•์ธ
echo "2. EndpointSlice ํžŒํŠธ ํ™•์ธ:"
kubectl get endpointslices -l kubernetes.io/service-name=web-service -o yaml | grep -A10 hints

# 3. Pod ๋ถ„์‚ฐ ์ƒํƒœ ํ™•์ธ
echo "3. Pod zone๋ณ„ ๋ถ„์‚ฐ ์ƒํƒœ:"
kubectl get pods -l app=web-app -o wide | awk '{print $7}' | sort | uniq -c

# 4. kube-proxy ๋กœ๊ทธ ํ™•์ธ (์„ ํƒ์‚ฌํ•ญ)
echo "4. kube-proxy ํ† ํด๋กœ์ง€ ๊ด€๋ จ ๋กœ๊ทธ:"
kubectl logs -n kube-system -l component=kube-proxy --tail=50 | grep -i topology || echo "๋กœ๊ทธ ์—†์Œ"

๐Ÿ“ˆ ์„ฑ๋Šฅ ์ธก์ •

๋ฒค์น˜๋งˆํฌ ํ…Œ์ŠคํŠธ

# ์„ฑ๋Šฅ ์ธก์ •์šฉ Pod ๋ฐฐํฌ
kubectl run perf-test --image=busybox --rm -it --restart=Never -- sh

# ์„œ๋น„์Šค ์‘๋‹ต ์‹œ๊ฐ„ ์ธก์ •
for i in {1..100}; do
  time wget -qO- http://web-service/health
done | grep real | awk '{sum+=$2} END {print "ํ‰๊ท :", sum/NR "์ดˆ"}'

๐ŸŽฏ ๊ฒฐ๋ก  ๋ฐ ์‹ค๋ฌด ์˜์‚ฌ๊ฒฐ์ • ๊ฐ€์ด๋“œ

Topology Aware Routing๋Š” ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ํด๋Ÿฌ์Šคํ„ฐ์˜ ๋„คํŠธ์›Œํฌ ์„ฑ๋Šฅ๊ณผ ๋น„์šฉ ํšจ์œจ์„ฑ์„ ํฌ๊ฒŒ ๊ฐœ์„ ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ•๋ ฅํ•œ ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋ชจ๋“  ํ™˜๊ฒฝ์— ์ ํ•ฉํ•œ ๊ฒƒ์€ ์•„๋‹ˆ๋ฉฐ, ์‹ ์ค‘ํ•œ ๊ฒ€ํ† ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿš€ TAR ๋„์ž… ๊ฒฐ์ • ํ”Œ๋กœ์šฐ์ฐจํŠธ

1. ํด๋Ÿฌ์Šคํ„ฐ Zone ์ˆ˜๋Š”?
   โ””โ”€ 1๊ฐœ Zone โ†’ โŒ TAR ๋ถˆ๊ฐ€, ๋
   โ””โ”€ 2๊ฐœ Zone โ†’ ๋‹ค์Œ ๋‹จ๊ณ„
   โ””โ”€ 3๊ฐœ+ Zone โ†’ ๋‹ค์Œ ๋‹จ๊ณ„

2. ํ™˜๊ฒฝ ์„ฑ๊ฒฉ์€?
   โ””โ”€ ๊ฐœ๋ฐœ/ํ…Œ์ŠคํŠธ โ†’ โŒ TAR ๋ถˆํ•„์š” (๋น„์šฉ ์šฐ์„ )
   โ””โ”€ ํ”„๋กœ๋•์…˜ โ†’ ๋‹ค์Œ ๋‹จ๊ณ„

3. ํŠธ๋ž˜ํ”ฝ ํŠน์„ฑ์€?
   โ””โ”€ ์ €ํŠธ๋ž˜ํ”ฝ โ†’ โ–ณ TAR ํšจ๊ณผ ๋ฏธ๋ฏธ
   โ””โ”€ ๊ณ ํŠธ๋ž˜ํ”ฝ โ†’ ๋‹ค์Œ ๋‹จ๊ณ„

4. ํŒŒ๋“œ ํ™•์žฅ ๊ฐ€๋Šฅ์„ฑ?
   โ””โ”€ 2๋Œ€ ๊ณ ์ • โ†’ โŒ TAR ์ œํ•œ์ 
   โ””โ”€ 3๋Œ€+ ๊ฐ€๋Šฅ โ†’ โœ… TAR ๋„์ž…!

๐Ÿ’ก ํ™˜๊ฒฝ๋ณ„ ์ตœ์ข… ๊ถŒ์žฅ์‚ฌํ•ญ

๐Ÿ”ฌ ๊ฐœ๋ฐœ/ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ

# ๊ฒฐ๋ก : TAR ์ ์šฉ ๋ถˆํ•„์š”
replicas: 1-2
service.kubernetes.io/topology-mode: "disabled"
# ์ด์œ : ๋น„์šฉ ์ ˆ์•ฝ > ์„ฑ๋Šฅ ์ตœ์ ํ™”

๐Ÿข ์Šคํ…Œ์ด์ง• ํ™˜๊ฒฝ

# ๊ฒฐ๋ก : TAR ํ…Œ์ŠคํŠธ ๋ชฉ์ ์œผ๋กœ๋งŒ ์ ์šฉ
replicas: 3-6
service.kubernetes.io/topology-mode: "auto"
# ์ด์œ : ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ ์‚ฌ์ „ ๊ฒ€์ฆ

๐Ÿญ ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ

# ๊ฒฐ๋ก : ์ ๊ทน์  TAR ๋„์ž…
replicas: zone_count ร— 3  # ์ตœ์ ํ™”
service.kubernetes.io/topology-mode: "auto"
# ์ด์œ : ์„ฑ๋Šฅ + ๋น„์šฉ ์ ˆ์•ฝ ํšจ๊ณผ ๊ทน๋Œ€ํ™”

ํ•ต์‹ฌ ์š”์•ฝ

โœ… ๋„์ž…ํ•˜๋ฉด ์ข‹์€ ๊ฒฝ์šฐ

  • 3๊ฐœ ์ด์ƒ Zone์„ ๊ฐ€์ง„ ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ
  • ๋†’์€ ํŠธ๋ž˜ํ”ฝ๊ณผ ์žฆ์€ ์„œ๋น„์Šค ๊ฐ„ ํ†ต์‹ 
  • ํŒŒ๋“œ๋ฅผ zone ์ˆ˜์˜ ๋ฐฐ์ˆ˜๋กœ ํ™•์žฅ ๊ฐ€๋Šฅ
  • ๋„คํŠธ์›Œํฌ ์ง€์—ฐ ์‹œ๊ฐ„๊ณผ ๋น„์šฉ์— ๋ฏผ๊ฐํ•œ ์›Œํฌ๋กœ๋“œ

โŒ ๋„์ž…ํ•˜์ง€ ๋ง์•„์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ

  • ๋‹จ์ผ Zone ํด๋Ÿฌ์Šคํ„ฐ
  • ๊ฐœ๋ฐœ/ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ (๋น„์šฉ ์šฐ์„ )
  • ํŒŒ๋“œ 1-2๊ฐœ๋กœ ๊ณ ์ •๋œ ๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค
  • ํŠธ๋ž˜ํ”ฝ์ด ๋งค์šฐ ์ ์€ ์„œ๋น„์Šค

โš ๏ธ ์‹ ์ค‘ํžˆ ๊ฒ€ํ† ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ

  • 2๊ฐœ Zone ํด๋Ÿฌ์Šคํ„ฐ (์ œํ•œ์  ํšจ๊ณผ)
  • ๋™์  ์Šค์ผ€์ผ๋ง์ด ์ค‘์š”ํ•œ ์„œ๋น„์Šค
  • ๋†’์€ ๊ฐ€์šฉ์„ฑ์ด ์ ˆ๋Œ€์ ์œผ๋กœ ํ•„์š”ํ•œ ์„œ๋น„์Šค

์‹ค๋ฌด ์ฒดํฌ๋ฆฌ์ŠคํŠธ

๋„์ž… ์ „ ํ™•์ธ์‚ฌํ•ญ:

  • kubectl get nodes Zone ์ˆ˜ ํ™•์ธ (3๊ฐœ+ ๊ถŒ์žฅ)
  • ํ˜„์žฌ ํŒŒ๋“œ ์ˆ˜์™€ ํ™•์žฅ ๊ณ„ํš ๊ฒ€ํ† 
  • ํŠธ๋ž˜ํ”ฝ ํŒจํ„ด ๋ฐ ๋น„์šฉ ๋ถ„์„
  • HPA ์„ค์ • ์‹œ zone ๊ท ํ˜• ๊ณ ๋ ค
  • ๋ชจ๋‹ˆํ„ฐ๋ง ๋ฐ ์•Œ๋žŒ ์„ค์ • ๊ณ„ํš

๋„์ž… ํ›„ ๊ฒ€์ฆ์‚ฌํ•ญ:

  • EndpointSlice hints ํ•„๋“œ ์ƒ์„ฑ ํ™•์ธ
  • ํฌ๋กœ์Šค-AZ ํŠธ๋ž˜ํ”ฝ ๊ฐ์†Œ ์ธก์ •
  • ๋„คํŠธ์›Œํฌ ์ง€์—ฐ ์‹œ๊ฐ„ ๊ฐœ์„  ํ™•์ธ
  • ๋ฐ์ดํ„ฐ ์ „์†ก ๋น„์šฉ ์ ˆ๊ฐ ํ™•์ธ

๊ถŒ์žฅ์‚ฌํ•ญ

  1. ๋‹จ๊ณ„์  ๋„์ž…: ๋น„์ฆˆ๋‹ˆ์Šค ์ž„ํŒฉํŠธ๊ฐ€ ๋‚ฎ์€ ์„œ๋น„์Šค๋ถ€ํ„ฐ ์‹œ์ž‘
  2. ์ถฉ๋ถ„ํ•œ ํ…Œ์ŠคํŠธ: ์Šคํ…Œ์ด์ง• ํ™˜๊ฒฝ์—์„œ ๋จผ์ € ๊ฒ€์ฆ
  3. ์ง€์†์  ๋ชจ๋‹ˆํ„ฐ๋ง: ํžŒํŠธ ์ƒ์„ฑ ์ƒํƒœ์™€ ํšจ๊ณผ ์ธก์ •
  4. ํŒ€ ๊ต์œก: ์šด์˜ํŒ€ ๋Œ€์ƒ TAR ์›๋ฆฌ์™€ ํŠธ๋Ÿฌ๋ธ”์ŠˆํŒ… ๋ฐฉ๋ฒ• ๊ณต์œ 
  5. ๋ฌธ์„œํ™”: ์˜์‚ฌ๊ฒฐ์ • ๊ณผ์ •๊ณผ ์„ค์ • ๊ธฐ์ค€ ๋ฌธ์„œํ™”

๐ŸŽฏ ํ•ต์‹ฌ ๋ฉ”์‹œ์ง€: "๋ชจ๋“  ํ™˜๊ฒฝ์— ์ ์šฉํ•˜๋Š” ๋งŒ๋Šฅ ํ•ด๊ฒฐ์ฑ…์ด ์•„๋‹ˆ๋ผ, ์ ์ ˆํ•œ ์กฐ๊ฑด์—์„œ ํฐ ํšจ๊ณผ๋ฅผ ๋ฐœํœ˜ํ•˜๋Š” ์ „๋ฌธ ๋„๊ตฌ"


๐Ÿ“š ์ฐธ๊ณ  ์ž๋ฃŒ

  1. Kubernetes Official Documentation - Topology Aware Hints
  2. AWS Blog - Exploring the effect of Topology Aware Hints on network traffic in Amazon EKS
  3. Kubernetes Enhancement Proposal - Topology Aware Routing
  4. Amazon EKS User Guide - Topology Aware Hints

์ด ๊ธ€์ด Topology Aware Hints ์ดํ•ด์— ๋„์›€์ด ๋˜์—ˆ๋‹ค๋ฉด ์ข‹์•„์š”์™€ ๊ณต์œ  ๋ถ€ํƒ๋“œ๋ ค์š”! ๐Ÿš€

profile
DevOps ์—”์ง€๋‹ˆ์–ด / ์—ด์‹ฌํžˆ ํ•ด์„œ ์ž˜ํ•˜์ž

0๊ฐœ์˜ ๋Œ“๊ธ€