AKS 클러스터 상에서 Bookinfo 샘플 애플리케이션을 배포하여 다음 테스트를 진행하고자 한다.

  • Ingress Add-on 방식의 외부 노출 테스트
  • Topology Spread Constraints 적용 및 zone 장애 대응 실험

구성 요소

Namespace bookinfo 앱 리소스를 분리 배포하기 위한 전용 네임스페이스
Service productpage, reviews, ratings, details 각 마이크로서비스 간 통신용 클러스터 내부 서비스
Deployment 각 서비스별 버전 (v1~v3) 실제 실행되는 앱 Pod를 정의
Ingress bookinfo-ingress productpage를 외부에 노출 (webapprouting.kubernetes.azure.com)
Ingress Host bookinfo.xxx.nip.io .nip.io 도메인을 활용한 외부 접근 URL

 

외부 접근 방법

Ingress Type AKS Web App Routing Add-on (nginx)
External IP xxx
Hostname bookinfo.xxx.nip.io
테스트 명령어 curl http://bookinfo.xxx.nip.io

공식 문서(Topology Spread Constraints - Kubernetes)를 기반으로, 지금 Bookinfo 앱에 Topology Spread Constraints를 적용해보고자 한다.

Topology Spread Constraints 구성 설명

필드 설명

maxSkew 가장 많은 zone과 가장 적은 zone 간 Pod 수 차이 허용값
topologyKey 기준이 되는 topology 레이블 (예: zone)
whenUnsatisfiable 조건 미충족 시 행동 (DoNotSchedule or ScheduleAnyway)
labelSelector 이 Spread가 적용될 Pod 셀렉터 조건
apiVersion: apps/v1
kind: Deployment
metadata:
  name: reviews-v1
  labels:
    app: reviews
    version: v1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: reviews
      version: v1
  template:
    metadata:
      labels:
        app: reviews
        version: v1
    spec:
      containers:
      - name: reviews
        image: docker.io/istio/examples-bookinfo-reviews-v1:1.20.2
        imagePullPolicy: IfNotPresent
        env:
        - name: LOG_DIR
          value: "/tmp/logs"
        ports:
        - containerPort: 9080
        volumeMounts:
        - name: tmp
          mountPath: /tmp
        - name: wlp-output
          mountPath: /opt/ibm/wlp/output
      volumes:
      - name: wlp-output
        emptyDir: {}
      - name: tmp
        emptyDir: {}

replicas: 3 이상이어야 의미있기에 replicas:3 으로 변경합니다.
 

# nodeSelector:
#   - reviews-v1 Pod는 SRE Node Pool에만 배포되도록 제한합니다
# 
# topologySpreadConstraints:
#   - maxSkew: zone 간 Pod 개수 차이를 1개 이하로 유지합니다
#   - topologyKey: "topology.kubernetes.io/zone" 레이블 기준으로 분산합니다
#   - whenUnsatisfiable: "DoNotSchedule" → 조건이 안 맞으면 아예 배포하지 않음
#   - labelSelector: app=reviews 에만 적용됩니다


apiVersion: apps/v1
kind: Deployment
metadata:
  name: reviews-v1
  labels:
    app: reviews
    version: v1
spec:
  replicas: 3  # replicas: 3 이상이어야 Topology Spread Constraints 실험 의미 있음
  selector:
    matchLabels:
      app: reviews
      version: v1
  template:
    metadata:
      labels:
        app: reviews
        version: v1
    spec:
      nodeSelector:
        agentpool: sre  # SRE Node Pool에만 배포되도록 지정
      topologySpreadConstraints:
        - maxSkew: 1  # zone 간 최대 1개 차이만 허용
          topologyKey: topology.kubernetes.io/zone
          whenUnsatisfiable: DoNotSchedule
          labelSelector:
            matchLabels:
              app: reviews
      containers:
      - name: reviews
        image: docker.io/istio/examples-bookinfo-reviews-v1:1.20.2
        imagePullPolicy: IfNotPresent
        env:
        - name: LOG_DIR
          value: "/tmp/logs"
        ports:
        - containerPort: 9080
        volumeMounts:
        - name: tmp
          mountPath: /tmp
        - name: wlp-output
          mountPath: /opt/ibm/wlp/output
      volumes:
      - name: wlp-output
        emptyDir: {}
      - name: tmp
        emptyDir: {}

 

  • replicas: 3 으로 설정
  • nodeSelector로 sre node pool에만 배포
  • topologySpreadConstraints로 zone 간 균등 분산 시도

 
현재 분포 상태 확인

kubectl get pods -n bookinfo -l app=reviews -o wide

NAME                          READY   STATUS    RESTARTS   AGE     IP             NODE                             NOMINATED NODE   READINESS GATES
reviews-v1-84f648c8cb-ds5ct   1/1     Running   0          4m51s   172.20.3.142   aks-sre-57935366-vmss000001      <none>           <none>
reviews-v1-84f648c8cb-xnc8w   1/1     Running   0          5m2s    172.20.2.22    aks-sre-57935366-vmss000000      <none>           <none>
reviews-v1-84f648c8cb-zpllt   1/1     Running   0          4m40s   172.20.3.215   aks-sre-57935366-vmss000001      <none>           <none>

 

kubectl get nodes -L topology.kubernetes.io/zone,agentpool
NAME                              STATUS   ROLES    AGE     VERSION   ZONE             AGENTPOOL
aks-default-34042230-vmss000001   Ready    <none>   29h     v1.29.7   0                default
aks-devops-17720728-vmss000001    Ready    <none>   29h     v1.29.7   0                devops
aks-sre-57935366-vmss000000       Ready    <none>   6m31s   v1.29.7   koreacentral-2   sre
aks-sre-57935366-vmss000001       Ready    <none>   6m25s   v1.29.7   koreacentral-3   sre

현재 분포 요약

reviews-v1-ds5ct aks-sre-vmss000001 koreacentral-3
reviews-v1-zpllt aks-sre-vmss000001 koreacentral-3
reviews-v1-xnc8w aks-sre-vmss000000 koreacentral-2

특정 zone 노드 장애 시 Pod 재분산 확인

목표

  • koreacentral-2 노드 하나 drain 시,
  • Pod가 koreacentral-3 로 재스케줄되는지 확인

1. drain 실행

kubectl drain aks-sre-57935366-vmss000000 \
  --ignore-daemonsets --delete-emptydir-data --force

주의

  • --force 붙이면 system-critical Pod 없음 조건 무시
  • --ignore-daemonsets: Cilium 등 데몬셋 영향 무시
  • --delete-emptydir-data: emptyDir 볼륨 제거 허용
kubectl get pods -n bookinfo -l app=reviews -o wide

NAME                          READY   STATUS    RESTARTS   AGE    IP             NODE                             NOMINATED NODE   READINESS GATES
reviews-v1-84f648c8cb-cbw9r   0/1     Pending   0          55s    <none>         <none>                           <none>           <none>
reviews-v1-84f648c8cb-ds5ct   1/1     Running   0          10m    172.20.3.142   aks-sre-57935366-vmss000001      <none>           <none>
reviews-v1-84f648c8cb-zpllt   1/1     Running   0          10m    172.20.3.215   aks-sre-57935366-vmss000001      <none>           <none>
reviews-v2-bdb6df55f-2lkj4    1/1     Running   0          163m   172.20.1.189   aks-devops-17720728-vmss000001   <none>           <none>
reviews-v3-8fcb4697f-6j82g    1/1     Running   0          163m   172.20.1.10    aks-devops-17720728-vmss000001   <none>           <none>
  • zone koreacentral-3: Pod 2개 (남아 있음)
  • zone koreacentral-2: Pod 0개
  • 새 Pod는 koreacentral-2에만 갈 수 있어야 maxSkew ≤ 1 만족
  • 그런데 koreacentral-2 노드는 drain 안 했기 때문에 Pod가 뜨지 못하고 있는 상태는 아님
  • 오히려 koreacentral-3 노드가 drain 안 되어 여전히 Pod 2개 유지 중

배포 구성 요약

replicas: 3
nodeSelector:
  agentpool: sre
topologySpreadConstraints:
  - maxSkew: 1
    topologyKey: topology.kubernetes.io/zone
    whenUnsatisfiable: ScheduleAnyway

 

  • agentpool: sre → SRE 노드 풀로만 스케줄
  • topologyKey: zone → zone 기준 분산
  • ScheduleAnyway → 조건 위반 시에도 배포 진행
~ kubectl get pods -n bookinfo -l app=reviews -o wide

NAME                         READY   STATUS    RESTARTS   AGE     IP             NODE                             NOMINATED NODE   READINESS GATES
reviews-v1-5d4b6b75f-6cwk2   1/1     Running   0          2m14s   172.20.3.130   aks-sre-57935366-vmss000001      <none>           <none>
reviews-v1-5d4b6b75f-cttfl   1/1     Running   0          2m13s   172.20.2.22    aks-sre-57935366-vmss000000      <none>           <none>
reviews-v1-5d4b6b75f-n9qvk   1/1     Running   0          2m11s   172.20.2.136   aks-sre-57935366-vmss000000      <none>           <none>

 

특정 zone 장애 시 스케줄링 확인

테스트: koreacentral-2 노드 Drain

kubectl drain aks-sre-57935366-vmss000000 \
  --ignore-daemonsets --delete-emptydir-data --force

목적

zone-2 Pod 삭제 시, 나머지 Pod가 조건을 위반하면서도 배포되는지 확인

drain 이후 결과

➜  ~ kubectl get pods -n bookinfo -l app=reviews -o wide

NAME                         READY   STATUS    RESTARTS   AGE     IP             NODE                             NOMINATED NODE   READINESS GATES
reviews-v1-5d4b6b75f-6cwk2   1/1     Running   0          3m29s   172.20.3.130   aks-sre-57935366-vmss000001      <none>           <none>
reviews-v1-5d4b6b75f-vtwhz   1/1     Running   0          32s     172.20.3.148   aks-sre-57935366-vmss000001      <none>           <none>
reviews-v1-5d4b6b75f-w2p7w   1/1     Running   0          32s     172.20.3.108   aks-sre-57935366-vmss000001      <none>           <none>

 
 

 

  • topologySpreadConstraints는 단순 권장 설정이 아니라, 설정 값에 따라 스케줄링 자체를 결정하는 핵심 조건이 될 수 있음
  • maxSkew: 1 은 분산 기준을 엄격히 적용하므로, Pod 간의 위치 차이를 1개 이하로 유지해야 함
  • whenUnsatisfiable: ScheduleAnyway 옵션은 조건 위반 시에도 배포를 허용하므로, 장애 대응이나 고가용성 측면에서 유용
  • 반면 DoNotSchedule은 시스템 안정성은 확보되지만, 조건이 맞지 않으면 서비스가 멈출 수 있음 → 운영 상황에 따라 전략 선택 필요

 

항목 DoNotSchedule ScheduleAnyway
조건 위반 시 동작 ❌ Pod 스케줄 금지 (Pending 발생) ✅ 조건 위반해도 스케줄 강행
maxSkew 기준 적용 여부 강제 적용 권고 수준 (스케줄은 강행)
장애 상황 대응력 낮음 (서비스 중단 발생 가능) 높음 (서비스 지속성 확보 가능)
실험 결과 요약 Pod 배포 중단 → Pending 모든 Pod 정상 Running 상태 유지