K8s Descheduler란?
Kubernetes 스케줄러는 Pod를 최초 배치할 때만 동작한다. 노드가 추가되거나, 리소스 사용 패턴이 변하거나, Taint/Label이 바뀌어도 이미 실행 중인 Pod는 재배치되지 않는다. 이 문제를 해결하는 것이 Descheduler다.
Descheduler는 실행 중인 Pod를 정책 기반으로 축출(evict)하여, 기본 스케줄러가 더 나은 노드에 재배치하도록 유도한다. 클러스터 리밸런싱, 노드 활용률 균등화, 정책 위반 Pod 정리 등에 필수적인 운영 도구다.
왜 Descheduler가 필요한가?
실제 운영 환경에서 흔히 발생하는 시나리오들이다:
- 노드 스케일 아웃 후 불균형: 새 노드가 추가되었지만 기존 Pod는 이동하지 않아 새 노드가 비어 있다
- Taint/Toleration 변경: 노드에 Taint를 추가했지만 기존 Pod는 Toleration 없이 계속 실행된다
- Anti-Affinity 위반: 스케줄링 시점에는 문제없었지만, 이후 변경으로 Anti-Affinity 규칙을 위반하는 상태가 된다
- 리소스 핫스팟: 특정 노드에 리소스 사용이 집중되어 성능 저하가 발생한다
설치 및 기본 구성
Helm으로 간단히 설치할 수 있다:
helm repo add descheduler https://kubernetes-sigs.github.io/descheduler/
helm repo update
helm install descheduler descheduler/descheduler
--namespace kube-system
--set schedule="*/5 * * * *"
기본적으로 CronJob으로 배포되며, 지정된 주기마다 정책을 평가하고 Pod를 축출한다. v0.28+부터는 Deployment 모드도 지원하여 지속적 모니터링이 가능하다.
핵심 Eviction 전략 6가지
Descheduler는 플러그인 기반 전략을 제공한다. 각 전략의 동작 원리와 설정법을 살펴보자.
1. RemoveDuplicates
동일 노드에서 같은 ReplicaSet/Deployment의 Pod가 여러 개 실행될 때, 중복 Pod를 축출하여 가용성을 높인다.
apiVersion: "descheduler/v1alpha2"
kind: "DeschedulerPolicy"
profiles:
- name: default
pluginConfig:
- name: RemoveDuplicates
args:
excludeOwnerKinds:
- "DaemonSet"
namespaces:
include:
- "production"
- "staging"
plugins:
balance:
enabled:
- RemoveDuplicates
운영 팁: DaemonSet은 반드시 제외하라. 노드당 1개가 의도된 배치이므로 중복으로 판단하면 안 된다.
2. LowNodeUtilization
노드 간 리소스 사용률 불균형을 해소한다. thresholds 이하인 노드를 “저활용”, targetThresholds 이상인 노드를 “과활용”으로 분류하고, 과활용 노드에서 Pod를 축출한다.
- name: LowNodeUtilization
args:
thresholds:
cpu: 20
memory: 20
pods: 15
targetThresholds:
cpu: 50
memory: 50
pods: 40
# 실제 사용량 기반 (requests 대신)
useDeviationThresholds: false
evictableNamespaces:
include:
- "default"
- "production"
CPU 20% 미만 노드가 있고 50% 이상 노드가 있을 때, 50% 이상 노드의 Pod를 축출하여 균형을 맞춘다.
3. HighNodeUtilization
LowNodeUtilization의 반대 전략이다. 저활용 노드의 Pod를 축출하여 다른 노드로 통합(bin-packing)한다. 클라우드 환경에서 노드 수를 줄여 비용을 절감할 때 유용하다.
- name: HighNodeUtilization
args:
thresholds:
cpu: 20
memory: 20
evictableNamespaces:
include:
- "default"
주의: Cluster Autoscaler와 함께 사용하면, 저활용 노드의 Pod를 이동시킨 후 빈 노드가 자동 축소되어 비용 최적화가 극대화된다.
4. RemovePodsViolatingNodeAffinity
노드의 Label이 변경되어 requiredDuringSchedulingIgnoredDuringExecution 규칙을 위반하게 된 Pod를 축출한다.
- name: RemovePodsViolatingNodeAffinity
args:
nodeAffinityType:
- requiredDuringSchedulingIgnoredDuringExecution
“IgnoredDuringExecution”이라는 이름처럼 Kubernetes가 기본적으로 무시하는 위반을 Descheduler가 감지하고 교정한다.
5. RemovePodsViolatingInterPodAntiAffinity
Pod 간 Anti-Affinity 규칙을 위반하는 Pod를 축출한다. 노드 장애 후 복구 시 같은 노드에 Pod가 몰리는 상황에서 특히 유용하다.
- name: RemovePodsViolatingInterPodAntiAffinity
6. RemovePodsViolatingTopologySpreadConstraint
TopologySpreadConstraints의 maxSkew를 위반하는 Pod를 축출한다.
- name: RemovePodsViolatingTopologySpreadConstraint
args:
constraints:
- DoNotSchedule
- ScheduleAnyway
실전 운영 설정: 프로덕션 DeschedulerPolicy
실제 프로덕션에서 사용할 수 있는 종합 정책이다:
apiVersion: "descheduler/v1alpha2"
kind: "DeschedulerPolicy"
profiles:
- name: production
pluginConfig:
- name: DefaultEvictor
args:
# PDB 존중 (필수!)
ignorePvcPods: false
evictLocalStoragePods: false
# 시스템 네임스페이스 보호
evictSystemCriticalPods: false
# 축출 비율 제한
maxNoOfPodsToEvictPerNode: 3
maxNoOfPodsToEvictPerNamespace: 5
- name: LowNodeUtilization
args:
thresholds:
cpu: 25
memory: 25
targetThresholds:
cpu: 60
memory: 60
- name: RemoveDuplicates
args:
excludeOwnerKinds:
- "DaemonSet"
- name: RemovePodsViolatingNodeAffinity
args:
nodeAffinityType:
- requiredDuringSchedulingIgnoredDuringExecution
- name: RemovePodsViolatingTopologySpreadConstraint
args:
constraints:
- DoNotSchedule
plugins:
balance:
enabled:
- LowNodeUtilization
- RemoveDuplicates
- RemovePodsViolatingTopologySpreadConstraint
deschedule:
enabled:
- RemovePodsViolatingNodeAffinity
PDB와의 연동: 안전한 축출
Descheduler는 PodDisruptionBudget(PDB)를 존중한다. PDB가 설정된 경우, minAvailable/maxUnavailable 제약을 초과하는 축출은 발생하지 않는다.
# PDB 설정 예시 - Descheduler 축출 시에도 적용됨
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: api-pdb
spec:
minAvailable: 2
selector:
matchLabels:
app: api-server
반드시 중요 워크로드에는 PDB를 설정하라. Descheduler가 한 번에 모든 Pod를 축출하여 서비스 중단이 발생하는 것을 방지한다.
DefaultEvictor 세부 설정
모든 전략에 공통 적용되는 축출 필터 설정이다:
| 파라미터 | 기본값 | 설명 |
|---|---|---|
evictLocalStoragePods |
false | emptyDir 사용 Pod 축출 여부 |
evictSystemCriticalPods |
false | system-critical Pod 축출 여부 |
ignorePvcPods |
false | PVC 마운트 Pod 무시 여부 |
maxNoOfPodsToEvictPerNode |
무제한 | 노드당 최대 축출 Pod 수 |
maxNoOfPodsToEvictPerNamespace |
무제한 | 네임스페이스당 최대 축출 Pod 수 |
minReplicas |
0 | 이 수 이하의 replica는 축출하지 않음 |
Deployment 모드 vs CronJob 모드
v0.28부터 두 가지 실행 모드를 지원한다:
# CronJob 모드 (기본) - 주기적 실행
helm install descheduler descheduler/descheduler
--set schedule="*/10 * * * *"
# Deployment 모드 - 지속 실행 + 간격 제어
helm install descheduler descheduler/descheduler
--set kind=Deployment
--set deschedulingInterval=5m
CronJob 모드는 리소스를 아끼고 싶을 때, Deployment 모드는 실시간에 가까운 리밸런싱이 필요할 때 사용한다.
모니터링: 메트릭 연동
Descheduler는 Prometheus 메트릭을 노출한다. Prometheus + Grafana와 연동하여 축출 현황을 추적하자.
# 주요 메트릭
descheduler_pods_evicted{result="success",strategy="LowNodeUtilization"}
descheduler_pods_evicted{result="error",strategy="RemoveDuplicates"}
descheduler_build_info
# Grafana PromQL 예시
# 전략별 축출 Pod 수 (5분 단위)
sum by (strategy) (
increase(descheduler_pods_evicted{result="success"}[5m])
)
# 축출 실패율 알림
sum(rate(descheduler_pods_evicted{result="error"}[10m])) /
sum(rate(descheduler_pods_evicted[10m])) > 0.3
Cluster Autoscaler와 조합
Descheduler + Cluster Autoscaler(또는 Karpenter)의 조합은 비용 최적화의 핵심이다:
- HighNodeUtilization 전략으로 저활용 노드의 Pod를 다른 노드로 통합
- 비게 된 노드를 Cluster Autoscaler가 자동 축소
- 클라우드 비용 절감
# HighNodeUtilization + Cluster Autoscaler 조합
- name: HighNodeUtilization
args:
thresholds:
cpu: 30 # CPU 30% 미만 노드의 Pod 축출
memory: 30
numberOfNodes: 1 # 최소 1개 저활용 노드가 있을 때만 동작
운영 주의사항과 베스트 프랙티스
- PDB 필수 설정: 모든 프로덕션 워크로드에 PDB를 설정하라. Descheduler의 축출은 PDB를 존중하지만, PDB가 없으면 모든 Pod가 한 번에 축출될 수 있다
- 점진적 도입:
maxNoOfPodsToEvictPerNode를 낮게 시작하고 (2~3), 안정성을 확인한 후 늘려라 - Dry-run 먼저:
--dry-run플래그로 어떤 Pod가 축출 대상인지 먼저 확인하라 - 네임스페이스 제한:
evictableNamespaces로 대상을 명확히 지정하라. kube-system은 제외하는 것이 안전하다 - StatefulSet 주의: PVC가 있는 StatefulSet Pod는 축출 후 동일 노드가 아니면 재스케줄링이 실패할 수 있다.
ignorePvcPods: true를 고려하라 - Spot 인스턴스 환경: Spot 노드 축소 시 Descheduler가 미리 Pod를 이동시켜 놓으면, 강제 종료 시 영향을 최소화할 수 있다
정리
Descheduler는 Kubernetes 클러스터의 런타임 리밸런싱 도구다. 기본 스케줄러가 “최초 배치”만 담당하는 한계를 보완하여, 운영 중 발생하는 불균형·정책 위반을 자동으로 교정한다. PDB와 함께 사용하면 서비스 안정성을 유지하면서도 리소스 효율을 극대화할 수 있다. Cluster Autoscaler/Karpenter와 조합하면 비용 최적화까지 달성할 수 있는 필수 운영 도구다.