지원 버전: Kubernetes 1.32 - 1.34
마지막 업데이트: 2026년 2월 22일
Kubernetes에서 스케줄링은 포드를 적절한 노드에 배치하는 과정입니다. 선점은 우선순위가 높은 포드를 위해 우선순위가 낮은 포드를 제거하는 과정이며, 축출은 노드 문제 발생 시 포드를 안전하게 이동시키는 과정입니다. 이 장에서는 Kubernetes의 스케줄링 메커니즘, 노드 선택, 선점, 축출 등의 개념과 Amazon EKS에서의 스케줄링 최적화 방법에 대해 알아보겠습니다.
실습 환경 설정
이 문서의 예제를 따라하기 위해서는 다음과 같은 도구와 환경이 필요합니다:
필수 도구
kubectl v1.34 이상
작동하는 Kubernetes 클러스터 (EKS, minikube, kind 등)
여러 노드가 있는 클러스터 (스케줄링 테스트용)
스케줄링 예제 설정
# 네임스페이스 생성kubectlcreatenamespacescheduling-demo# 노드에 레이블 추가 (여러 노드가 있는 경우)kubectllabelnodes<node-name>disktype=ssdkubectllabelnodes<node-name>gpu=true# 노드 어피니티를 사용하는 파드 생성kubectl-nscheduling-demoapply-f-<<EOFapiVersion: v1kind: Podmetadata: name: nginx-ssdspec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: disktype operator: In values: - ssd containers: - name: nginx image: nginxEOF# 우선순위 클래스 생성kubectlapply-f-<<EOFapiVersion: scheduling.k8s.io/v1kind: PriorityClassmetadata: name: high-priorityvalue: 1000000globalDefault: falsedescription: "This priority class should be used for critical service pods only."EOF# 포드 중단 예산(PDB) 생성kubectl-nscheduling-demoapply-f-<<EOFapiVersion: policy/v1kind: PodDisruptionBudgetmetadata: name: nginx-pdbspec: minAvailable: 1 selector: matchLabels: app: nginxEOF
Kubernetes 스케줄링 아키텍처
스케줄링 개념 비교
개념
목적
사용 사례
Kubernetes 버전
노드 셀렉터
특정 레이블이 있는 노드에 포드 배치
간단한 노드 선택
모든 버전
노드 어피니티
복잡한 노드 선택 규칙 정의
고급 노드 선택
1.6+
포드 어피니티
다른 포드와 가까이 배치
관련 서비스 공동 배치
1.6+
포드 안티-어피니티
다른 포드와 멀리 배치
고가용성 보장
1.6+
테인트와 톨러레이션
특정 포드만 노드에 배치 허용
전용 노드, 노드 격리
1.6+
토폴로지 분배 제약
토폴로지 도메인 간 포드 분산
가용 영역 간 분산
1.16+ (1.19에서 GA)
우선순위 및 선점
중요 워크로드 우선 배치
중요 서비스 보장
1.8+ (1.11에서 GA)
포드 중단 예산
동시에 중단되는 포드 수 제한
고가용성 보장
1.4+ (1.21에서 GA)
스케줄링 기본 개념
핵심 개념: Kubernetes 스케줄러는 포드를 실행할 최적의 노드를 선택하는 컨트롤 플레인 컴포넌트로, 필터링과 스코어링 두 단계로 작동합니다.
Amazon EKS에서는 Kubernetes 스케줄링 기능을 활용하여 워크로드를 최적화할 수 있습니다.
노드 그룹 및 인스턴스 유형
EKS에서는 다양한 노드 그룹과 인스턴스 유형을 활용하여 워크로드에 맞는 리소스를 제공할 수 있습니다:
다양한 인스턴스 유형: 컴퓨팅 최적화, 메모리 최적화, 스토리지 최적화 등
스팟 인스턴스: 비용 효율적인 워크로드를 위한 스팟 인스턴스
GPU 인스턴스: AI/ML 워크로드를 위한 GPU 인스턴스
노드 레이블과 테인트를 사용하여 특정 워크로드를 특정 노드 그룹에 배치할 수 있습니다:
가용 영역 분산
EKS에서는 포드 안티-어피니티와 토폴로지 스프레드 제약 조건을 사용하여 워크로드를 여러 가용 영역에 분산시킬 수 있습니다:
위 예시에서 topologySpreadConstraints는 포드를 여러 가용 영역에 균등하게 분산시킵니다.
Karpenter를 사용한 자동 스케일링
Amazon EKS에서는 Karpenter를 사용하여 워크로드에 맞는 노드를 자동으로 프로비저닝할 수 있습니다:
Karpenter는 포드의 리소스 요구 사항에 맞는 최적의 인스턴스 유형을 선택하여 비용을 최적화합니다.
리소스 요청 및 제한 최적화
EKS에서 워크로드의 리소스 요청과 제한을 최적화하는 것이 중요합니다:
Vertical Pod Autoscaler(VPA): 워크로드의 실제 리소스 사용량을 기반으로 리소스 요청 최적화
Goldilocks: VPA 권장 사항을 시각화하여 리소스 요청 최적화 지원
리소스 쿼터: 네임스페이스별 리소스 사용량 제한
스케줄링 모범 사례
Kubernetes 및 EKS에서 스케줄링을 최적화하기 위한 모범 사례:
적절한 리소스 요청 및 제한 설정:
워크로드의 실제 리소스 사용량을 기반으로 리소스 요청 설정
중요한 워크로드에 적절한 리소스 제한 설정
VPA를 사용하여 리소스 요청 자동 최적화
워크로드 분산:
포드 안티-어피니티를 사용하여 중요한 워크로드를 여러 노드에 분산
토폴로지 스프레드 제약 조건을 사용하여 워크로드를 여러 가용 영역에 분산
노드 어피니티를 사용하여 특정 워크로드를 특정 노드에 배치
노드 리소스 최적화:
다양한 인스턴스 유형을 사용하여 워크로드에 맞는 리소스 제공
스팟 인스턴스를 사용하여 비용 최적화
Karpenter를 사용하여 워크로드에 맞는 노드 자동 프로비저닝
PDB 설정:
중요한 워크로드에 PDB 설정
워크로드 특성에 맞는 minAvailable 또는 maxUnavailable 값 선택
정기적으로 PDB 작동 테스트
우선순위 및 선점 설정:
중요한 워크로드에 높은 우선순위 클래스 설정
시스템 컴포넌트에 system-cluster-critical 또는 system-node-critical 우선순위 클래스 사용
선점 영향 이해 및 테스트
노드 테인트 및 톨러레이션:
특수 워크로드를 위한 전용 노드 설정
유지 관리 중인 노드에 테인트 적용
적절한 톨러레이션 설정
결론
Kubernetes의 스케줄링, 선점 및 축출 메커니즘은 클러스터 리소스를 효율적으로 관리하고 워크로드의 가용성을 유지하는 데 중요한 역할을 합니다. 이러한 기능을 이해하고 활용함으로써 Amazon EKS 클러스터에서 워크로드를 최적화하고 안정적으로 운영할 수 있습니다.
스케줄링 최적화는 지속적인 과정이며, 워크로드 특성과 클러스터 상태에 따라 지속적으로 조정해야 합니다. 모니터링 도구를 활용하여 클러스터 리소스 사용량을 추적하고, 필요에 따라 스케줄링 정책을 조정하는 것이 중요합니다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: cache-service
spec:
replicas: 5
selector:
matchLabels:
app: cache-service
template:
metadata:
labels:
app: cache-service
spec:
containers:
- name: cache
image: redis:7
lifecycle:
postStart:
exec:
command:
- /bin/sh
- -c
- |
# 시작 시 낮은 비용 설정
sleep 10
# 캐시 워밍업 완료 후 사이드카가 비용 증가
- name: cost-updater
image: bitnami/kubectl:latest
command:
- /bin/sh
- -c
- |
# 5분 후 캐시 워밍업 완료로 간주하고 비용 증가
sleep 300
kubectl annotate pod $POD_NAME \
controller.kubernetes.io/pod-deletion-cost=1000 \
--overwrite
# 이후 주기적으로 캐시 히트율에 따라 비용 조정
while true; do
sleep 60
HIT_RATE=$(redis-cli INFO stats | grep keyspace_hits)
# 캐시 히트율에 따라 비용 동적 조정 로직
done
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
apiVersion: batch/v1
kind: Job
metadata:
name: long-running-task
spec:
template:
metadata:
annotations:
# 작업 진행 중인 포드 보호
controller.kubernetes.io/pod-deletion-cost: "10000"
spec:
containers:
- name: worker
image: worker:latest
command: ["./process-large-dataset.sh"]
restartPolicy: Never
# PDB 설정 예시
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: web-pdb
spec:
minAvailable: 2
selector:
matchLabels:
app: web
---
# Descheduler가 이 PDB를 존중하여
# 최소 2개의 web 포드가 항상 유지됨
# 노드 그룹 생성 시 레이블 및 테인트 설정
eksctl create nodegroup \
--cluster my-cluster \
--name gpu-nodes \
--node-labels="workload-type=gpu" \
--node-type=p3.2xlarge \
--taints="gpu=true:NoSchedule"
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-server
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
topologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app: web
containers:
- name: web
image: nginx