Notice
Recent Posts
Recent Comments
Link
«   2025/12   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31
Archives
Today
Total
관리 메뉴

근묵자흑

Kubernetes Pattern: Automated Placement 본문

k8s/kubernetes-pattern

Kubernetes Pattern: Automated Placement

Luuuuu 2025. 8. 30. 20:04

쿠버네티스에서 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 권장