Pod 토폴로지 분산 제약
Pod 토폴로지 분산 제약 (Pod Topology Spread Constraints)
토폴로지 분산 제약(topology spread constraints) 을 사용하면 region, zone, node, 기타 사용자 정의 토폴로지 도메인 같은 장애 도메인(failure-domain)에 걸쳐 Pod를 어떻게 분산할지 제어할 수 있어요. 이는 높은 가용성과 효율적인 리소스 활용을 달성하는 데 도움을 줘요.
클러스터 수준 제약을 기본값으로 설정할 수도 있고, 개별 워크로드에 대해 구성할 수도 있어요.
동기 (Motivation)
최대 20개 노드의 클러스터에서 replica 수를 자동 조정하는 워크로드를 실행한다고 상상해 보세요. Pod가 2개뿐일 때 둘 다 같은 노드에서 실행되는 건 피하고 싶어요. 단일 노드 장애가 워크로드를 오프라인으로 만들 위험이 있으니까요.
규모를 키우며 더 많은 Pod를 실행하면 다른 고려사항이 생겨요. 3개 노드가 각각 5개 Pod를 실행하고, 클라이언트가 3개의 다른 데이터센터(인프라 존)에 나뉘어 있다고 해보죠. 그러면 단일 노드 장애에 대한 걱정은 줄지만, zone 사이의 네트워크 비용과 지연이 높아져요. 정상 운영 중 각 인프라 존에 비슷한 수의 replica가 스케줄링되길 원한다면, Pod 토폴로지 분산 제약이 이를 선언적으로 구성하게 해줘요.
topologySpreadConstraints 필드
Pod API에는 spec.topologySpreadConstraints 필드가 있어요.
apiVersion: v1
kind: Pod
metadata:
name: example-pod
spec:
topologySpreadConstraints:
- maxSkew: <integer>
minDomains: <integer> # optional
topologyKey: <string>
whenUnsatisfiable: <string>
labelSelector: <object>
matchLabelKeys: <list> # optional; beta since v1.27
nodeAffinityPolicy: [Honor|Ignore] # optional; beta since v1.26
nodeTaintsPolicy: [Honor|Ignore] # optional; beta since v1.26
참고: 주어진
topologyKey와whenUnsatisfiable값에 대해topologySpreadConstraint는 하나만 있을 수 있어요.
분산 제약 정의
- maxSkew: Pod가 얼마나 고르지 않게 분산될 수 있는지 정도를 설명해요. 0보다 커야 해요.
whenUnsatisfiable값에 따라 의미가 달라져요.DoNotSchedule이면, maxSkew는 대상 토폴로지의 매칭 Pod 수와 전역 최소값(자격 있는 도메인의 최소 매칭 Pod 수 또는 자격 있는 도메인 수가 MinDomains보다 적으면 0) 사이의 최대 허용 차이를 정의해요.ScheduleAnyway면, 스케줄러는 skew를 줄이는 데 도움이 되는 토폴로지를 우선시해요.
- minDomains: 자격 있는 도메인의 최소 수를 나타내는 선택 필드.
DoNotSchedule과 함께만 지정할 수 있고 0보다 커야 해요. 자격 있는 도메인 수가minDomains보다 적으면 전역 최소값을 0으로 취급해요. 지정하지 않으면minDomains가 1인 것처럼 동작해요. - topologyKey: 노드 라벨의 키예요. 이 키를 가진 라벨과 동일한 값을 가진 노드들은 같은 토폴로지에 있는 것으로 간주돼요. 각 토폴로지 인스턴스(<key, value> 쌍)를 도메인이라 불러요.
- whenUnsatisfiable: Pod가 분산 제약을 충족하지 못할 때 처리 방법.
DoNotSchedule(기본값): 스케줄링하지 않음.ScheduleAnyway: skew를 최소화하는 노드를 우선시하며 여전히 스케줄링.
- labelSelector: 매칭할 Pod를 찾는 데 사용돼요.
- matchLabelKeys: 분산 skew를 계산할 Pod 그룹을 선택하는 pod label 키 목록. Pod 생성 시 kube-apiserver가 그 키들로 들어오는 Pod 라벨의 값을 조회하고, 그 key-value 라벨을 기존
labelSelector와 병합해요. - nodeAffinityPolicy: skew 계산 시 Pod의 nodeAffinity/nodeSelector 처리 방법.
Honor는 매칭 노드만 계산에 포함,Ignore는 무시. null이면 Honor와 동일. - nodeTaintsPolicy: skew 계산 시 노드 taint 처리 방법.
Honor는 taint 없는 노드와 toleration이 있는 taint 노드를 포함,Ignore는 무시. null이면 Ignore와 동일.
여러 topologySpreadConstraint를 정의하면 논리 AND로 결합돼요. kube-scheduler는 모든 제약을 충족하는 노드를 찾아요.
노드 라벨
분산 제약은 노드 라벨로 각 노드가 속한 토폴로지 도메인을 식별해요. 예를 들어 노드가 region: us-east-1, zone: us-east-1a 같은 라벨을 가질 수 있어요.
참고: 잘 알려진 라벨 키인
topology.kubernetes.io/zone과topology.kubernetes.io/region을 사용하는 것이 권장돼요. 비공개(비정규화) 라벨 키region/zone은 다른 맥락에서 의미를 신뢰할 수 없어요.
podAffinity / podAntiAffinity와 비교
podAffinity: Pod를 끌어당겨, 자격 있는 토폴로지 도메인에 원하는 수의 Pod를 패킹할 수 있어요.podAntiAffinity: Pod를 밀어내요.requiredDuringSchedulingIgnoredDuringExecution모드로 설정하면 하나의 토폴로지 도메인에 단일 Pod만 스케줄링할 수 있어요.
더 세밀한 제어를 위해 토폴로지 분산 제약으로 Pod를 서로 다른 토폴로지 도메인에 분산해 높은 가용성이나 비용 절감을 달성할 수 있어요. 이는 롤링 업데이트 워크로드와 replica 확장을 부드럽게 하는 데도 도움이 돼요.
알려진 한계
- Pod가 제거될 때 제약이 충족된 채 유지된다는 보장이 없어요. Deployment 축소 시 불균형한 Pod 분산이 생길 수 있어요. Descheduler 같은 도구로 재분산할 수 있어요.
- 스케줄러는 클러스터가 가진 모든 zone/토폴로지 도메인을 사전에 알지 못해요. 자동 확장 클러스터에서 노드 풀이 0으로 축소되면 그 토폴로지 도메인이 최소 하나의 노드가 생길 때까지 고려되지 않아요.
- 자신의 labelSelector와 매칭되지 않는 Pod는 "ghost pod"를 만들어요. 보통 Pod는 자신의 topology spread constraint 셀렉터와 매칭되어야 해요.