들어가기 앞서
앞서 NodeSelector, NodeAffinity 및 Taint/Tolerance 와 같은 파드 스케줄링 방식에 대해 확인했습니다. 현재 운영중인 서비스의 개발 및 품질 환경의 EKS 는 매우 낮은 스펙의 인스턴스를 사용하고 있습니다. 또한, 저희는 비용최적화를 위해 Instance Scheduler 를 적용해 매일 22시에 모든 노드 인스턴스가 종료되고 08시에 노드 인스턴스가 새로 생성됩니다.
이러한 과정에서 파드가 재배포되는 과정에서 Replica 가 2개 이상인 Deployment 파드들이 한개의 노드에 몰려서 배치되는 현상이 발생하였고 특정 노드의 리소스 Request 가 할당가능한 양을 초과하여 DaemonSet 파드가 배치되지 않는 결과가 되었습니다. 이를 해결하기 위해 CronJob을 통해 특정 시간대에 Deployment 를 재배포하여 Rebalancing을 수행할 수 있겠으나, 더욱 효과적인 방법으로 topologySpreadConstraints 정책을 적용하기로 했습니다.
topologySpreadConstraints 란?
만약 'Replica = 2' 인 Pod A 가 Node 1에 모두 스케줄되어있습니다. 이 때 Node 1에 장애가 생긴다면, 다른 워커 노드에는 Pod A replica가 없기 때문에 서비스 A는 정상 동작을 할 수 없게됩니다. 반면에 Node 1 , Node 2에 분산되어있다면 Node 1에 장애가 발생하더라도 Node 2에서 계속 서비스됩니다.
이 때문에 Pod의 replica를 여러 워커 노드에 적절하게 분산하여 스케줄하는 것은 안정적인 서비스 제공에 필수적인 요소입니다. 이전에 포스팅했듯 쿠버네티스에는 유사한 문제를 해결하기 위해 Affinity, AntiAffinity 를 제공하고 있습니다. 그러나 이 기능은 Pod를 원하는 노드에 배치하는데 있어서 일부적인 해결일 뿐, Pod를 적절하게 분산시켜서 스케줄링해준다고는 말하기 어렵습니다.
그렇기 때문에 Pod를 워커 노드에 적절히 분산하기 위한 설정인 topologySpreadConstraints 가 필요합니다
topologySpreadConstraints (토폴로지 분재 제약조건)
topologySpreadConstraints 를 설정하면 노드(Node), 지역(region), 존(zone) 및 기타 사용자 정의 토폴로지를 기반으로 쿠버네티스 클러스터에 걸쳐 파드가 분배되는 방식을 제어할 수 있습니다. 이를 설정함으로써 고가용성뿐만 아니라 효율적인 리소스 활용의 목적을 이루는 데에도 도움을 줄 수 있습니다.
topologySpreadConstraints는 클러스터 레벨에서 기본값으로 설정할 수도 있고(EKS는 불가능), 개별 애플리케이션마다 각각의 topologySpreadConstraints를 설정하는 것도 가능합니다(EKS 가능).
하나 또는 여러개의 topologySpreadConstraint 를 정의할 수 있으며, kube-scheduler는 이 조건들을 함께 고려하여 클러스터의 어떤 노드에 새로운 파드를 배치할지 결정합니다.
주요 속성
- maxSkew : 하나의 topology 도메인에 배포될 수 있는 최대 편차
- topologyKey : 토폴로지를 구분하는 key (예: topology.kubernetes.io/zone)
- whenUnsatisfiable : 제약 조건을 충족할 수 없는 경우의 동작 (ScheduleAnyway 또는 DoNotSchedule)
- labelSelector : 특정 파드를 선택하기 위한 레이블
- minDomains (선택)
- 최소 분산이 필요한 topology 도메인의 수를 설정할 수 있으며, 최소 분산 필요한 노드 또는 존의 수를 설정하는데 활용할 수 있음(현재 kubernetes 버전이 v1.25 이상이라면 사용 가능)
- nodeAffinityPolicy (선택)
- nodeAffinity/nodeSelector를 기반으로 매칭되는 노드만 고려하여 파드 분산 skew를 계산할지 말지에 대한 설정
- nodeTaintsPolicy (선택)
- taint가 없는 노드와 taint가 있더라도 파드의 toleration이 있어 스케쥴링이 가능한 노드만 고려하여 파드 분산 skew를 계산할지 말지에 대한 설정
- matchLabelKeys (선택)
- labelSelector에 설정하지 않은 파드의 label을 추가적으로 고려하여 분산 대상 파드를 선택할 때 사용
- deployment 등에 변경사항이 있어 rollingupdate가 필요할 때, rollingupdate 이후에도 파드의 분산을 고르게 하기 위해 사용할 수 있음(현재 kubernetes 버전이 v1.27 이상이라면 사용 가능)
동작 방식
- 균등 분배(maxSkew): 같은 레이블을 가진 파드가 topologyKey를 기준으로 최대 maxSkew 차이를 두고 분산되도록 스케줄링됨. 작게 설정할수록 고르게 분산됩니다.
- 여러 노드가 있을 때 최종적으로 노드에 배포된 파드의 수의 차이가 maxSkew를 넘지 않는 것을 의도하는 것이 아님.
- 파드 스케줄링 당시에 모든 topology 중 매칭되는 파드의 수가 가장 적은 topology 와의 파드 수 차이가 maxSkew를 만족하는 노드를 선택해 파드 배포
- 제약 조건 위반 시 동작(whenUnsatisfiable)
- DoNotSchedule: 조건을 만족할 수 없으면 파드를 스케줄하지 않음.
- ScheduleAnyway: 조건을 만족할 수 없더라도 파드를 배치함.
(추가) Skew 동작 방식

위 사진과 같은 조건에서 추가로 새로운 파드 한 개 생성이 필요할 때 상황을 가정합니다.
- nodeA에 배치할 때 :
- node skew : 1(nodeA) - 0(nodeY)
- zone skew : 4(Zone 1) - 2(Zone 2) -> 정책 위반
- nodeY에 배치할 때 :
- node skew : 1(nodeY) - 0(nodeA)
- zone skew : 3(Zone 2) - 3(Zone 1)
- nodeB에 배치할 때 :
- node skew : 4(nodeB) - 0(nodeA or nodeY) -> 정책 위반
- zone skew : 4(Zone 1) - 2(Zone 2) -> 정책 위반
- nodeX에 배치할 때 :
- node skew : 3(nodeX) - 0(nodeA or nodeY) -> 정책 위반
- zone skew : 3(Zone 1) - 1(Zone 1) -> 정책 위반
즉, NodeY 에 배치되게 됩니다!
예제: EKS 환경에서 가용 영역(Availability Zone, AZ) 기반 분배
AWS EKS에서 특정 파드를 가용 영역(AZ)에 균등하게 배포하도록 topologySpreadConstraints를 설정하는 예제입니다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: az-aware-deployment
spec:
replicas: 6
selector:
matchLabels:
app: test-app
template:
metadata:
labels:
app: test-app
spec:
topologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app: test-app
containers:
- name: test-container
image: nginx
- topologyKey: topology.kubernetes.io/zone: 가용 영역(AZ) 단위로 균등 분배.
- maxSkew: 1: 하나의 AZ에서 다른 AZ보다 최대 1개 이상의 파드만 추가 배치될 수 있음.
- whenUnsatisfiable: DoNotSchedule: 스케줄러가 규칙을 지킬 수 없으면 배포하지 않음.
- replicas: 6: 6개의 파드를 배포하면, 3개의 AZ(A, B, C)가 있을 경우 {2,2,2}로 균등 분배됨.
예제: 노드 기반 분배 예제
특정 노드 풀(Node Group) 간 균등하게 파드를 배포하고 싶다면 topologyKey를 kubernetes.io/hostname으로 설정하면 됩니다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: node-aware-deployment
spec:
replicas: 4
selector:
matchLabels:
app: node-aware-app
template:
metadata:
labels:
app: node-aware-app
spec:
topologySpreadConstraints:
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: ScheduleAnyway
labelSelector:
matchLabels:
app: node-aware-app
containers:
- name: node-aware-container
image: nginx
- topologyKey: kubernetes.io/hostname → 노드 단위로 파드 분배
- whenUnsatisfiable: ScheduleAnyway → 스케줄링이 불가능할 경우 불균형을 허용
예제: 가용영역 및 노드 기반 분배 예제
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-server
spec:
selector:
matchLabels:
app: web-store
replicas: 3
template:
metadata:
labels:
app: web-store
spec:
topologySpreadConstraints:
- labelSelector:
matchLabels:
app: web-store
maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: DoNotSchedule
nodeAffinityPolicy: Honor
nodeTaintsPolicy: Honor
minDomains: 3 # 3개의 AZ 사용을 위한 설정
matchLabelKeys:
- pod-template-hash
- labelSelector:
matchLabels:
app: web-store
maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: DoNotSchedule
nodeAffinityPolicy: Honor
nodeTaintsPolicy: Honor
minDomains: 3 # 최소 3개의 노드 사용을 위한 설정
matchLabelKeys:
- pod-template-hash
containers:
- name: web-app
image: nginx:1.16-alpine
- AZ 단위로 분산 → AZ별로 최대 1개 차이까지만 허용
- 노드 단위로 분산 → 특정 노드에 파드가 몰리지 않도록 균등 배포
- AZ와 노드 제약을 동시에 적용 → 특정 AZ나 노드에 과도하게 배치되지 않도록 조정
- 불균형 발생 시 추가 배포 차단 → DoNotSchedule 설정으로 인해 조건을 만족하지 않으면 새로운 파드를 생성하지 않음
제약 사항
- 스케쥴러는 클러스터가 가진 topology 도메인에 대해 미리 알지 못하며, 해당 topology 도메인에 노드가 있을 때 인식할 수 있음(어떤 topology 도메인이 있는지 모두 알 수 없음)
- 노드 수가 적을 때 해당 노드에 집중되어 파드가 생성될 수 있으며, 최소 분산이 필요한 노드 또는 존이 있다면 minDomains를 설정하여 어느 정도 분산을 보장할 수 있음
- 파드 삭제 시(scale-in/evict 등) 분산 조건을 고려하지 않음
- scale-in 시 특정 노드나 존에 파드가 아예 없을 수도 있음
podAntiAffinity vs topologySpreadConstraints 차이점
podAntiAffinity와 topologySpreadConstraints는 모두 Kubernetes에서 Pod의 배치를 제어하는 데 사용됩니다. 하지만 각기 다른 방식으로 동작합니다.
- podAntiAffinity
- 특정 노드 또는 특정 조건을 만족하는 다른 Pod와 함께 배치되지 않도록 합니다.
- podAntiAffinity는 topology 하나에 파드 하나만 배포하게 됩니다.
- topologySpreadConstraints
- 클러스터의 다양한 토폴로지(예: 노드, 영역)에 걸쳐 Pods를 분배하는 규칙을 정의합니다.
- Pod의 분포를 보다 균형 있게 만들기 위해 사용되며, 예를 들어 여러 가용 영역에 Pod를 분배하거나 특정 노드 그룹에 너무 많은 Pod가 배치되지 않도록 할 수 있습니다.
podAntiAffinity는 다른 Pod와의 배치 관계를 기준으로 제어하지만, topologySpreadConstraints는 Pod의 분포를 보다 넓은 관점에서 제어합니다. 즉, podAntiAffinity는 특정 Pod가 다른 Pod와 함께 배치되지 않도록 하지만, topologySpreadConstraints는 Pod들이 클러스터의 다양한 토폴로지에 걸쳐 균등하게 배치되도록 합니다.
'Kubernetes & EKS > k8s 공부 기록' 카테고리의 다른 글
| [kubernetes] Authentication & Authorization 02 (0) | 2025.04.19 |
|---|---|
| [kubernetes] Authentication & Authorization 01 (0) | 2025.04.18 |
| [kubernetes] EKS 파드 스케줄링: podAntiAffinity (0) | 2025.03.31 |
| [kubernetes] Taint and Tolerance (0) | 2025.03.31 |
| [kubernetes] Resource Requirements and Limits (0) | 2025.03.14 |