Kubernetes/Kubernetes Advanced

📌 [StatefulSet 심화편 #20] StatefulSet에서 Pod 재배치 및 특정 노드에 고정하는 방법

ygtoken 2025. 3. 14. 10:17
728x90

 

1️⃣ 개요

 

StatefulSet에서 특정 Pod를 특정 노드에 배치하거나, 특정 노드에서 강제로 이동해야 하는 경우가 있습니다.

특히, 노드 장애 발생 시 Pod를 안전하게 재배치하거나, 고성능 스토리지가 있는 노드에 특정 StatefulSet Pod를 배치하는 것이 중요합니다.

 

이번 글에서는 StatefulSet의 Pod를 특정 노드에 배치하거나 이동하는 다양한 방법과 실전 활용법을 정리하겠습니다. 🚀

 


2️⃣ StatefulSet Pod 재배치 및 고정이 필요한 이유

 

📌 StatefulSet Pod 배치를 조정해야 하는 주요 상황

상황 설명
노드 장애 발생 특정 노드 장애 시, 다른 노드로 Pod를 이동해야 함
고성능 스토리지 연결 특정 Pod를 SSD가 있는 노드에서 실행해야 함
지리적 분산 배포 특정 노드 그룹(Region, Zone)에 Pod를 배치해야 함
자원 활용 최적화 CPU, 메모리가 많은 노드에 StatefulSet을 배치

StatefulSet에서는 Pod가 삭제되더라도 같은 이름으로 다시 생성되므로, 특정 노드에 고정하거나 강제 이동하는 방법이 필요합니다.

 


3️⃣ StatefulSet Pod를 특정 노드에 고정하는 방법

 

✅ 1. Node Selector 사용 (특정 노드에 배치 제한)

 

Node Selector를 사용하면 특정 라벨이 있는 노드에서만 Pod가 실행되도록 설정할 수 있습니다.

 

📌 특정 노드에 라벨 추가

kubectl label nodes node-1 disktype=ssd

 

📌 StatefulSet에서 Node Selector 적용 예제

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql
spec:
  serviceName: mysql
  replicas: 3
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      nodeSelector:
        disktype: ssd  # 특정 노드에서만 실행
      containers:
        - name: mysql
          image: mysql:8
          volumeMounts:
            - name: mysql-data
              mountPath: /var/lib/mysql
  volumeClaimTemplates:
    - metadata:
        name: mysql-data
      spec:
        accessModes: ["ReadWriteOnce"]
        resources:
          requests:
            storage: 10Gi

이제 disktype=ssd 라벨이 있는 노드에서만 StatefulSet Pod가 실행됩니다.

 


✅ 2. Node Affinity 사용 (고급 배치 전략 적용)

 

Node Selector보다 더 유연한 조건을 설정할 수 있는 Node Affinity를 활용하면, 복수의 조건을 조합하여 StatefulSet Pod 배치가 가능합니다.

 

📌 Node Affinity 적용 예제 (특정 노드 그룹에서 실행하도록 설정)

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: redis
spec:
  serviceName: redis
  replicas: 3
  selector:
    matchLabels:
      app: redis
  template:
    metadata:
      labels:
        app: redis
    spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
              - matchExpressions:
                  - key: kubernetes.io/hostname
                    operator: In
                    values:
                      - node-1
                      - node-2
      containers:
        - name: redis
          image: redis:latest
          volumeMounts:
            - name: redis-data
              mountPath: /data
  volumeClaimTemplates:
    - metadata:
        name: redis-data
      spec:
        accessModes: ["ReadWriteOnce"]
        resources:
          requests:
            storage: 5Gi

이제 node-1 또는 node-2에서만 StatefulSet이 실행됩니다.

 


✅ 3. Taint & Toleration을 활용한 노드 격리

 

Taint를 설정하면, 특정 Pod만 해당 노드에서 실행되도록 설정할 수 있습니다.

 

📌 특정 노드에 Taint 추가 (다른 Pod는 실행되지 않도록 설정)

kubectl taint nodes node-3 special-node=true:NoSchedule

 

📌 StatefulSet Pod에서 해당 Taint를 허용하는 설정

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: elasticsearch
spec:
  serviceName: elasticsearch
  replicas: 3
  template:
    metadata:
      labels:
        app: elasticsearch
    spec:
      tolerations:
        - key: "special-node"
          operator: "Equal"
          value: "true"
          effect: "NoSchedule"

이제 Elasticsearch StatefulSet은 node-3에서만 실행되며, 다른 Pod는 해당 노드에서 실행되지 않습니다.

 


4️⃣ StatefulSet Pod를 다른 노드로 강제 이동하는 방법

 

✅ 1. 특정 노드에서 StatefulSet Pod를 강제 제거 (cordon & drain)

 

📌 노드를 스케줄링 불가능하도록 설정 (cordon)

kubectl cordon node-1

 

📌 현재 실행 중인 Pod를 다른 노드로 이동 (drain)

kubectl drain node-1 --ignore-daemonsets --delete-emptydir-data

이제 StatefulSet Pod는 다른 노드로 이동됩니다.

 


✅ 2. 특정 StatefulSet Pod를 강제로 삭제하여 다른 노드에서 실행하도록 유도

 

📌 Pod 삭제 후 새로운 노드에서 실행되도록 유도

kubectl delete pod mysql-0

 

📌 새로운 노드에서 실행되는지 확인

kubectl get pods -o wide

StatefulSet 컨트롤러가 자동으로 새로운 노드에서 Pod를 실행합니다.

 


5️⃣ StatefulSet Pod 배치 최적화 전략

 

✅ 1. Pod Anti-Affinity 설정 (StatefulSet Pod 간 노드 분산 배치)

 

StatefulSet의 Pod가 특정 노드에 몰리는 것을 방지하려면 Pod Anti-Affinity를 활용해야 합니다.

 

📌 Pod Anti-Affinity 설정 예제

affinity:
  podAntiAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchLabels:
            app: kafka
        topologyKey: "kubernetes.io/hostname"

이제 동일한 StatefulSet의 Pod가 같은 노드에 배치되지 않습니다.

 


✅ 2. 노드 그룹별 배포 정책 적용 (Region 및 Zone 고려)

 

📌 다른 리전에 분산 배포하도록 설정

affinity:
  nodeAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
      nodeSelectorTerms:
        - matchExpressions:
            - key: topology.kubernetes.io/zone
              operator: In
              values:
                - us-east-1a
                - us-east-1b

클러스터 노드가 여러 지역(Region)에 분산된 경우, 특정 Zone에 StatefulSet Pod를 배포할 수 있습니다.

 


🔥 6️⃣ 결론

 

StatefulSet Pod를 특정 노드에 배치하려면 Node Selector, Node Affinity, Toleration을 활용해야 함

Pod를 특정 노드에서 제거하려면 kubectl drain, kubectl delete pod 명령어를 활용해야 함

Pod Anti-Affinity를 활용하면 StatefulSet Pod가 특정 노드에 몰리는 것을 방지할 수 있음

다중 리전 및 가용 영역(Zone)에 StatefulSet을 배포하려면 Node Affinity 설정을 활용해야 함

728x90