[Kubernetes] Scheduling (Taints, Affinity, Topology Spread)
정의
Kubernetes Scheduling 은 kube-scheduler 가 새 Pod 을 어느 노드에 배치할지 결정하는 과정입니다. 두 단계 (Filtering + Scoring), 여러 정책 (nodeSelector, Affinity, Taints/Tolerations, Topology Spread, PriorityClass) 을 조합해 세밀한 배치 제어를 제공합니다.
기본 흐름
flowchart LR P[새 Pod] --> F[Filtering] F -->|후보 노드| S[Scoring] S -->|최고 점수| N[선정 노드]
Filtering (predicates)
노드가 Pod 실행 조건 만족하는지 검사:
- 리소스 여유 (CPU, memory)
- nodeSelector / nodeAffinity 매치
- Taints 를 tolerate
- Volume affinity (AZ 매치)
- Port 충돌 없음
- 노드 상태 Ready
Scoring (priorities)
살아남은 노드에 점수 (0-100):
- LeastRequested: request 여유 많은 노드 선호
- BalancedResourceAllocation: CPU/memory 균형
- NodeAffinity preferred: 선호도 매치
- InterPodAffinity preferred
- ImageLocality: 이미지 이미 있는 노드
- TopologySpread: 균형 분산
nodeSelector (가장 단순)
apiVersion: v1
kind: Pod
metadata:
name: gpu-workload
spec:
nodeSelector:
accelerator: nvidia
disktype: ssd
containers: [...]
노드에 라벨이 있어야 매치. 정확히 이 라벨을 가진 노드에만 배치.
단점: AND 만 지원. 유연성 낮음. 신규 코드는 Node Affinity 권장.
Node Affinity
requiredDuringScheduling (hard)
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: topology.kubernetes.io/zone
operator: In
values: [us-east-1a, us-east-1b]
- key: node-type
operator: NotIn
values: [spot]
만족 못 하면 스케줄 안 됨. IgnoredDuringExecution 은 실행 중 노드 라벨 바뀌어도 evict 안 함.
preferredDuringScheduling (soft)
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
preference:
matchExpressions:
- key: instance-type
operator: In
values: [m5.large]
- weight: 50
preference:
matchExpressions:
- key: zone
operator: In
values: [us-east-1a]
선호도. 완벽 매치 못 해도 스케줄됨.
Operators
- In, NotIn: 값 목록
- Exists, DoesNotExist: 라벨 존재 여부
- Gt, Lt: 숫자 비교
Pod Affinity / Anti-Affinity
Pod Affinity (다른 Pod 옆에)
같은 노드/AZ 에 있는 다른 Pod 옆에 배치. 캐시 지역성, 통신 지연 최소화.
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
app: cache
topologyKey: kubernetes.io/hostname # 같은 노드
topologyKey: 어느 단위 (호스트, zone, region) 로 판단.
Pod Anti-Affinity (다른 Pod 피해)
같은 노드/AZ 에 없어야. HA 의 핵심.
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
app: web
topologyKey: kubernetes.io/hostname
app: web Pod 이 같은 노드에 있으면 스케줄 실패. Replica 를 여러 노드에 강제 분산.
AZ 분산:
topologyKey: topology.kubernetes.io/zone
각 AZ 에 최대 하나. 3 AZ + 3 replica 면 각 zone 1개.
주의: required anti-affinity 는 스케줄러가 O(N^2) 검사. 큰 클러스터에서 느림. 대안: Topology Spread.
Topology Spread Constraints
topologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app: web
각 zone 의 Pod 수 차이 (skew) 가 maxSkew 이하가 되도록. app: web Pod 이 zone A 에 5개, B 에 4개인데 새 pod 추가하면 A 에는 못 감 (skew 2 초과).
whenUnsatisfiable:
- DoNotSchedule (hard): 불만족이면 pending
- ScheduleAnyway (soft): 조건 안 맞아도 스케줄
Anti-affinity 보다 성능 좋고 유연. HA + 균형 분산의 표준.
Taints and Tolerations
Taint 는 노드에 붙이는 “특정 Pod 만 허용” 표시. Toleration 은 Pod 이 taint 를 견딜 수 있다는 선언.
Taint 부여
kubectl taint nodes node1 dedicated=gpu:NoSchedule
kubectl taint nodes node1 spot=true:PreferNoSchedule
kubectl taint nodes node1 out-of-service:NoExecute
Effect
NoSchedule: 매치 안 되는 Pod 은 스케줄 안 됨 (기존 Pod 은 유지)PreferNoSchedule: soft 버전NoExecute: 매치 안 되는 기존 Pod evict + 새 Pod 안 옴
Toleration
tolerations:
- key: dedicated
operator: Equal
value: gpu
effect: NoSchedule
- key: spot
operator: Exists # 값 무관, 키만 매치
effect: PreferNoSchedule
- key: out-of-service
operator: Exists
effect: NoExecute
tolerationSeconds: 300 # evict 유예 (초)
관용
dedicated=team-x:NoSchedule: 특정 팀 전용 노드nvidia.com/gpu:NoSchedule: GPU 노드 (Karpenter, GPU Operator 자동)node.kubernetes.io/unreachable:NoExecute: 시스템 taint, unreachable 노드node.kubernetes.io/not-ready:NoExecute: NotReady 노드
PodDisruptionBudget (PDB)
Voluntary disruption (Drain, PDB 존중 rolling update 등) 중 최소 실행 Pod 수 보장.
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: web-pdb
spec:
minAvailable: 2 # 항상 2개 이상 실행
# 또는
maxUnavailable: 1 # 최대 1개만 죽어도 됨
selector:
matchLabels:
app: web
kubectl drain 시 PDB 위반될 pod 은 evict 안 함.
주의: PDB 는 voluntary 만 적용. Node crash, kernel OOM 등 involuntary 는 못 막음.
Priority & Preemption
높은 priority Pod 이 낮은 priority Pod 을 evict.
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: prod-critical
value: 1000000
description: "Production critical workloads"
spec:
priorityClassName: prod-critical
- System critical:
system-cluster-critical(2 000 000 000),system-node-critical(2 000 001 000) - User: 0 ~ 1 000 000 000 권장
nodeName (강제 지정, 지양)
spec:
nodeName: node1
스케줄러 우회. 노드 이름 하드코딩 => 확장성 없음. 개발/디버깅만.
스케줄러 확장
- Scheduling Framework: 커스텀 plugin (필터, 스코어 등) 삽입
- Multiple Schedulers:
spec.schedulerName으로 다른 스케줄러 선택 - Volcano: 배치/ML 워크로드 스케줄러
- Karpenter (AWS/Azure): 노드 프로비저닝 스케줄러 (kube-scheduler 보완)
실전 패턴
HA 웹앱 (3 replica, 3 AZ 분산)
spec:
replicas: 3
template:
spec:
topologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app: web
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchLabels:
app: web
topologyKey: kubernetes.io/hostname
zone 균등 + 같은 노드 회피 (soft).
GPU 워크로드 (전용 노드)
spec:
nodeSelector:
accelerator: nvidia-tesla-t4
tolerations:
- key: nvidia.com/gpu
operator: Exists
effect: NoSchedule
containers:
- name: trainer
resources:
limits:
nvidia.com/gpu: 1
Spot 노드 (비용 절감)
spec:
nodeSelector:
node-type: spot
tolerations:
- key: spot
operator: Exists
effect: PreferNoSchedule
함정
WARNING
Anti-affinity required + 대규모 클러스터 = 스케줄러 성능 저하. Topology Spread 로 대체.
CAUTION
AZ 3개 + replica 4 개 에 maxSkew: 1 이면 균등 분산 불가. 조합 수학 확인.
WARNING
Taint 잘못 걸면 시스템 pod 도 못 뜸. NoExecute 는 특히 위험. Test cluster 에서 검증.
IMPORTANT
PDB 는 rolling update 를 막을 수도 있음. 항상 maxUnavailable 이 replica 총합보다 작아야 rolling 가능.
CAUTION
nodeName 하드코딩 지양. Pod 이 오직 그 노드에 만. 노드 죽으면 재스케줄 없음.
관련 위키
- Kubernetes - 상위 개요
- Architecture - kube-scheduler
- Pod
- Labels & Selectors - Selector 근간
- Namespace
- Resource Management - Request 는 스케줄러 기준
- PV / PVC - Volume AZ affinity
- Deployment
- StatefulSet
- DaemonSet - Taint tolerance
이 글의 용어 (10개)
- [K8s] DaemonSet: 모든 노드에 한 podkubernetes
- 정의 DaemonSet 은 클러스터의 각 노드에 정확히 1개의 Pod 을 보장하는 워크로드 리소스. 노드가 추가되면 자동으로 Pod 가 배포되고, 노드가 제거되면 자동으로 정리된…
- [K8s] Deployment: ReplicaSet, rolling update, rollbackkubernetes
- 정의 Deployment = stateless 워크로드를 위한 컨트롤러. 내부적으로 ReplicaSet 관리 + rolling update / rollback. 사용 시나리오 |…
- [K8s] Pod: 컨테이너의 최소 단위, sidecar, lifecyclekubernetes
- 정의 Pod = K8s 의 가장 작은 배포 단위. 1개 이상의 컨테이너 + 공유 네트워크 + 공유 스토리지. [!IMPORTANT] Pod 는 컨테이너의 wrapping 이 아니…
- [K8s] StatefulSet: 순서 보장, 고유 ID, 영속 스토리지kubernetes
- 정의 StatefulSet = 상태 있는 워크로드를 위한 컨트롤러. Deployment 와의 차이: | 항목 | Deployment | StatefulSet | |---|---|…
- [Kubernetes] Architecture (Control Plane + Node)kubernetes
- 정의 Kubernetes Architecture 는 Control Plane (제어) 과 Worker Node (실행) 두 계층으로 구성됩니다. Control Plane 은 원하…
- [Kubernetes] Labels & Selectorskubernetes
- 정의 Labels 는 리소스에 붙이는 key-value 분류 태그 입니다. 사람과 컨트롤러가 리소스를 조직하고 선택할 때 사용합니다. Selectors 는 label 조합으로 대…
- [Kubernetes] Namespacekubernetes
- 정의 Namespace 는 같은 물리 클러스터 안에서 리소스 (Pod, Service, ConfigMap 등) 를 논리적으로 격리 하는 단위입니다. 이름 충돌 회피, RBAC 스…
- [Kubernetes] Persistent Volumes (PV / PVC / StorageClass)kubernetes
- 정의 Kubernetes Storage 계층 은 세 리소스로 구성됩니다. - PersistentVolume (PV): 실제 스토리지 (EBS, GCE PD, NFS, iSCSI …
- [Kubernetes] Resource Management (Requests, Limits, QoS)kubernetes
- 정의 Kubernetes Resource Management 는 CPU, 메모리, ephemeral storage, hugepages 등의 리소스를 파드에 할당하고 제한하는 시스…
- Kuberneteskubernetes
- 정의 Kubernetes (k8s) 는 컨테이너화된 애플리케이션의 배포, 스케일링, 관리 를 자동화하는 오픈소스 오케스트레이터입니다. Google 이 2014년 발표하고 2015…
이 개념을 다룬 위키 페이지 (7)
- wiki[Kubernetes] Architecture (Control Plane + Node)
- wiki[K8s] DaemonSet: 모든 노드에 한 pod
- wiki[Kubernetes] Debugging (kubectl debug, Ephemeral Containers, Events)
- wiki[Kubernetes] Labels & Selectors
- wiki[Kubernetes] Persistent Volumes (PV / PVC / StorageClass)
- wiki[Kubernetes] Resource Management (Requests, Limits, QoS)
- wikiKubernetes
💬 댓글