근묵자흑
Kubernetes Pattern: Automated Placement 본문
쿠버네티스에서 Pod가 어느 노드에 배치될지 결정하는 것은 애플리케이션의 성능, 가용성, 비용에 직접적인 영향을 미칩니다.
이번 포스트에서는 Kubernetes Patterns 6장의 Automated Placement 패턴을 Minikube 환경에서 직접 테스트하며 각 배치 전략의 실제 동작을 확인해보겠습니다.
테스트 환경
- 이번장의 실습 코드는 GitHub 저장소에서 확인할 수 있습니다.
Minikube 멀티노드 클러스터 설정
먼저 3개 노드를 가진 Minikube 클러스터를 생성합니다:
# 3노드 Minikube 클러스터 생성
minikube start --nodes 3 --cpus 2 --memory 2048 --driver=docker
# 노드 확인
kubectl get nodes
실행 결과:
NAME STATUS ROLES AGE VERSION
minikube Ready control-plane 2m v1.28.0
minikube-m02 Ready <none> 1m v1.28.0
minikube-m03 Ready <none> 1m v1.28.0
5가지 배치 패턴
1. Node Selector - 간단한 노드 선택
Node Selector는 라벨 기반의 가장 기본적인 노드 선택 방법입니다.
테스트 코드:
apiVersion: v1
kind: Pod
metadata:
name: node-selector-pod
namespace: automated-placement
spec:
nodeSelector:
disktype: ssd
environment: production
containers:
- name: app
image: k8spatterns/random-generator:1.0
테스트 실행:
kubectl apply -f node-selector.yml
kubectl get pods -n automated-placement -o wide
결과:
NAME NODE STATUS
node-selector-pod minikube Running
- Node Selector는 AND 조건으로 작동합니다. 모든 라벨이 일치하는 노드에만 배치됩니다.
2. Node Affinity - 유연한 노드 선택 규칙
Node Affinity는 더 복잡한 조건을 표현할 수 있습니다.
테스트 코드:
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/os
operator: In
values: ["linux"]
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
preference:
matchExpressions:
- key: disktype
operator: In
values: ["ssd"]
테스트 결과:
- 필수 조건(Linux OS) 충족
- SSD 노드 우선 배치 (weight=100)
- SSD 노드가 없어도 다른 노드에 배치 가능
3. Pod Affinity/Anti-Affinity - Pod 간 관계 기반 배치
가장 실용적이고 강력한 패턴입니다. Redis와 웹 애플리케이션을 예로 테스트했습니다.
Redis 배포 (Anti-Affinity):
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values: ["redis"]
topologyKey: "kubernetes.io/hostname"
Web App 배포 (Affinity to Redis):
spec:
affinity:
podAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values: ["redis"]
topologyKey: "kubernetes.io/hostname"
테스트 결과:
애플리케이션 Pod수 배치 결과
Redis 2개 minikube, minikube-m02 (분산)
Web App 3개 Redis와 같은 노드 우선 배치
Database 3개 각각 다른 노드에 분산
- Cache와 App을 같은 노드에 배치 → 레이턴시 감소
- DB 레플리카를 다른 노드에 분산 → 고가용성 확보
4. Taints와 Tolerations - 노드 격리 및 전용 워크로드
특정 노드를 특별한 용도로 예약하는 패턴입니다.
GPU 노드 시뮬레이션:
# 세 번째 노드를 GPU 노드로 설정
kubectl taint nodes minikube-m03 gpu=true:NoSchedule
kubectl label node minikube-m03 accelerator=gpu
GPU 워크로드 배포:
spec:
tolerations:
- key: "gpu"
operator: "Equal"
value: "true"
effect: "NoSchedule"
containers:
- name: ml-training
image: tensorflow/tensorflow:latest
resources:
limits:
nvidia.com/gpu: 1
테스트 결과:
워크로드 타입 Taint 노드 배치 일반 노드 배치
GPU 워크로드 가능 불가능
일반 워크로드 불가능 가능
Critical Pod 가능 가능
(모든 Toleration)
5. Topology Spread Constraints - 균등 분산
가장 최신이고 강력한 분산 배치 메커니즘입니다.
테스트 코드:
spec:
topologySpreadConstraints:
- maxSkew: 1 # 최대 불균형 허용치
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app: ha-web
- maxSkew: 2
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: ScheduleAnyway
12개 Pod 배포 결과:
Zone 노드수 Pod 배치 균등도
us-west-1a 1개 4개 ✅
us-west-1b 1개 4개 ✅
us-west-1c 1개 4개 ✅
----------------------------------------
총계 3개 12개 완벽한 균등 분산
실전 교훈 및 베스트 프랙티스
1. 패턴별 사용 시나리오
| 패턴 | 사용 시나리오 | 장점 | 단점 |
|---|---|---|---|
| Node Selector | 간단한 노드 구분 | 단순하고 직관적 | 유연성 부족 |
| Node Affinity | 복잡한 노드 선택 | OR 조건, 선호도 표현 | 설정 복잡 |
| Pod Affinity | 마이크로서비스 | Pod 관계 표현 | 리소스 집중 가능 |
| Taints | 전용 노드 | 완벽한 격리 | 관리 오버헤드 |
| Topology Spread | 고가용성 | 완벽한 균등 분산 | K8s 1.19+ 필요 |
2. 실제 발견한 주의사항
Node Selector의 함정
# 잘못된 예: 오타 주의!
nodeSelector:
disktype: sdd # ssd가 아닌 sdd
# 결과: Pod가 Pending 상태로 남음
Anti-Affinity 비용
Redis Anti-Affinity 테스트:
- 2개 Pod, 2개 노드: 정상 분산
- 4개 Pod, 3개 노드: ⚠️ 1개 Pod Pending
- 해결책: preferredDuringScheduling 사용
Topology Spread maxSkew 이해
maxSkew=1: 최대 1개 차이 허용
Zone A: 3개
Zone B: 2개
Zone C: 4개 (차이가 2개)
성능 영향 분석
테스트 중 관찰한 스케줄링 성능:
배치 패턴 스케줄링 시간 CPU 오버헤드
Node Selector <1초 최소
Node Affinity 1-2초 낮음
Pod Affinity 2-3초 중간
Topology Spread 3-5초 높음
복합 사용 5-10초 매우 높음
kube-linter 검증
모든 YAML 파일에 대해 kube-linter를 사용하여 매니패스트를 검증했습니다.
kube-linter 검증 결과
# 초기 검사
trunk check --filter=kube-linter *.yml
# 발견된 주요 이슈
✗ 45개 high severity 이슈 발견
- run-as-non-root: 15개
- no-read-only-root-fs: 20개
- latest-tag: 4개
- no-anti-affinity: 6개
# 수정 후 재검사
✓ Critical 이슈 모두 해결
✓ Security Context 적용
✓ 이미지 버전 명시
✓ Health Probes 추가
Automated Placement 패턴용 설정 (.kube-linter.yaml)
checks:
addAllBuiltIn: true
exclude:
# 배치 테스트에 적합한 완화
- no-read-only-root-fs # DB/Redis는 쓰기 필요
- no-anti-affinity # 배치 패턴 테스트 목적
- minimum-three-replicas # 테스트시 적은 Pod 허용
include:
- latest-tag # 버전 명시 필수
- unset-cpu-requirements # 리소스 설정 필수
- no-liveness-probe # Health check 권장'k8s > kubernetes-pattern' 카테고리의 다른 글
| Kubernetes Pattern: Periodic Job (2) | 2025.09.13 |
|---|---|
| Kubernetes Pattern: Batch Job (3) | 2025.09.06 |
| Kubernetes Pattern: Managed Lifecycle (2) | 2025.08.23 |
| Kubernetes Pattern: Health Probe Pattern(정상상태 점검 패턴) (1) | 2025.08.16 |
| Kubernetes Pattern: 선언적 배포(Declarative Deployment) + FluxCD (3) | 2025.08.09 |