PriorityClass란?
Kubernetes PriorityClass는 Pod에 우선순위를 부여하여, 클러스터 리소스가 부족할 때 어떤 Pod를 먼저 스케줄링하고 어떤 Pod를 퇴출(Preemption)할지 결정하는 메커니즘입니다. 프로덕션 워크로드와 배치 작업이 혼재된 환경에서, PriorityClass 없이는 중요한 서비스가 리소스 부족으로 Pending 상태에 빠질 수 있습니다.
Kubernetes 1.14부터 GA(정식)로 지원되며, kube-scheduler의 핵심 스케줄링 전략 중 하나입니다. 이 글에서는 PriorityClass 설정부터 Preemption 동작 원리, 운영 전략까지 깊이 있게 다루겠습니다.
PriorityClass 기본 구조
# 클러스터 레벨 리소스 (네임스페이스 없음)
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: critical-production
value: 1000000 # 높을수록 우선순위 높음 (최대 10억)
globalDefault: false # true면 모든 Pod의 기본값
preemptionPolicy: PreemptLowerPriority # 프리엠션 정책
description: "프로덕션 핵심 서비스 전용"
| 필드 | 설명 | 기본값 |
|---|---|---|
value |
정수 우선순위 값 (높을수록 중요) | 0 |
globalDefault |
PriorityClass 미지정 Pod에 적용 | false |
preemptionPolicy |
PreemptLowerPriority 또는 Never | PreemptLowerPriority |
시스템 기본 PriorityClass
Kubernetes는 두 개의 내장 PriorityClass를 제공합니다. 이를 사용자 워크로드에 사용하면 안 됩니다.
# 시스템 예약 PriorityClass
$ kubectl get priorityclasses
NAME VALUE GLOBAL-DEFAULT
system-cluster-critical 2000000000 false # etcd, kube-apiserver 등
system-node-critical 2000001000 false # kubelet, kube-proxy 등
# 사용자 PriorityClass value 범위: -2,147,483,648 ~ 1,000,000,000
# 10억 초과는 시스템 전용 (system-cluster-critical, system-node-critical)
실전 PriorityClass 계층 설계
운영 환경에서는 워크로드 특성에 따라 3~5단계 우선순위 체계를 설계하는 것이 좋습니다.
# 1단계: 핵심 인프라 (모니터링, 로깅)
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: infrastructure
value: 900000
description: "Prometheus, Fluentd 등 관측 인프라"
---
# 2단계: 프로덕션 서비스
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: production
value: 700000
description: "사용자 트래픽을 직접 처리하는 서비스"
---
# 3단계: 내부 서비스
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: internal
value: 500000
description: "내부 API, 관리 도구"
---
# 4단계: 배치/크론잡
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: batch
value: 100000
description: "배치 처리, 데이터 파이프라인"
---
# 5단계: 기본값 (개발/테스트)
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: default
value: 0
globalDefault: true
description: "개발, 테스트, 실험 워크로드"
Pod에 PriorityClass 적용
apiVersion: apps/v1
kind: Deployment
metadata:
name: payment-api
spec:
replicas: 3
selector:
matchLabels:
app: payment-api
template:
metadata:
labels:
app: payment-api
spec:
priorityClassName: production # PriorityClass 지정
containers:
- name: payment-api
image: payment-api:v2.1.0
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: "1"
memory: 1Gi
Preemption 동작 원리
Preemption(프리엠션)은 높은 우선순위 Pod가 스케줄링될 수 없을 때, 낮은 우선순위 Pod를 퇴출하여 리소스를 확보하는 메커니즘입니다.
# Preemption 흐름:
# 1. 고우선순위 Pod 생성 → 스케줄 불가 (리소스 부족)
# 2. Scheduler가 각 노드에서 퇴출 후보를 계산
# 3. 최소 퇴출로 스케줄 가능한 노드 선택
# 4. 저우선순위 Pod에 graceful termination 시작
# 5. terminationGracePeriodSeconds 경과 후 강제 종료
# 6. 고우선순위 Pod 스케줄링
# Preemption 비활성화 (대기만 하고 퇴출 안 함)
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: batch-no-preempt
value: 100000
preemptionPolicy: Never # 퇴출 없이 대기
description: "높은 우선순위지만 다른 Pod를 퇴출하지 않음"
preemptionPolicy: Never는 배치 작업처럼 스케줄링 순서는 앞서되 다른 서비스를 방해하면 안 되는 경우에 유용합니다.
PDB와 Preemption의 관계
Preemption은 PodDisruptionBudget(PDB)를 존중하지만, 완벽하게 보장하지는 않습니다.
# PDB가 있어도 Preemption이 발생할 수 있는 경우:
# - PDB를 존중하면서 퇴출 가능한 조합이 존재할 때
# - PDB 위반 없이는 스케줄 불가능할 때 (최후 수단으로 PDB 무시)
# 핵심 서비스는 반드시 PDB + 높은 PriorityClass 조합
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: payment-api-pdb
spec:
minAvailable: 2
selector:
matchLabels:
app: payment-api
---
# payment-api는 production PriorityClass (700000)
# → 퇴출 대상이 될 확률 자체가 극히 낮음
ResourceQuota와 PriorityClass 연동
ResourceQuota에 scopeSelector를 사용하면 PriorityClass별로 리소스 제한을 걸 수 있습니다.
apiVersion: v1
kind: ResourceQuota
metadata:
name: production-quota
namespace: team-a
spec:
hard:
cpu: "20"
memory: 40Gi
pods: "50"
scopeSelector:
matchExpressions:
- scopeName: PriorityClass
operator: In
values:
- production
- infrastructure
---
apiVersion: v1
kind: ResourceQuota
metadata:
name: batch-quota
namespace: team-a
spec:
hard:
cpu: "8"
memory: 16Gi
pods: "100"
scopeSelector:
matchExpressions:
- scopeName: PriorityClass
operator: In
values:
- batch
- default
운영 모니터링
# Preemption 발생 이벤트 확인
kubectl get events --field-selector reason=Preempted -A
# PriorityClass별 Pod 현황
kubectl get pods -A -o custom-columns=
"NAMESPACE:.metadata.namespace,
NAME:.metadata.name,
PRIORITY:.spec.priority,
CLASS:.spec.priorityClassName,
STATUS:.status.phase"
| sort -t' ' -k3 -rn | head -20
# Pending Pod 중 Preemption 대기 확인
kubectl get pods -A --field-selector status.phase=Pending
-o custom-columns="NAME:.metadata.name,PRIORITY:.spec.priority"
운영 주의사항
| 항목 | 주의사항 | 권장 대응 |
|---|---|---|
| value 간격 | 너무 촘촘하면 나중에 끼워넣기 어려움 | 10만 단위 간격 유지 |
| globalDefault | 클러스터에 1개만 허용, 중복 시 오류 | 반드시 하나만 설정 |
| Preemption 연쇄 | 퇴출된 Pod가 다른 Pod를 퇴출 가능 | 계층 수를 3~5개로 제한 |
| 시스템 값 사용 | 10억 초과 값을 사용자 Pod에 부여 | 사용자 범위(~10억) 준수 |
| Spot/Preemptible 노드 | 클라우드 Spot 노드와 Preemption 혼동 | Spot에는 batch PriorityClass 배치 |
마무리
PriorityClass는 Kubernetes 클러스터의 리소스 배분 정책을 코드로 선언하는 핵심 도구입니다. 핵심 서비스에 높은 우선순위를 부여하고, 배치 작업에 preemptionPolicy: Never를 적용하면 서비스 안정성과 리소스 효율성을 동시에 확보할 수 있습니다. ResourceQuota의 scopeSelector와 조합하면 네임스페이스 단위의 정밀한 리소스 거버넌스까지 구현 가능합니다.