[K8S] StatefulSet

진웅·2026년 1월 15일

K8S Basics

목록 보기
40/40

StatefulSet: 개념, 장점, 그리고 동작 흐름도

  • StatefulSet은 쿠버네티스에서 상태를 가지는 애플리케이션(Stateful Application)을 안정적으로 배포하고 관리하기 위한 핵심 오브젝트다.
  • 일반적인 웹 서버처럼 상태 보관 필요없는(Stateless) 애플리케이션은 Deployment로 관리하는 데 반해, 데이터베이스나 메시지 큐처럼 데이터를 지속적으로 저장하고 고유한 식별자가 필요한 애플리케이션은 StatefulSet을 사용하는 것이 필수적이다.

1. StatefulSet의 개념

StatefulSet은 이름 그대로 '상태'를 유지하는 데 중점을 둔다. Deployment가 Pod을 교체할 때마다 새로운 이름과 IP를 할당받는 일시적인(Ephemeral) 존재로 다룬다면, StatefulSet은 Pod이 재시작되거나 재배포되어도 동일한 '정체성'과 '데이터'를 유지하도록 보장한다.

이를 위해 StatefulSet은 다음과 같은 3가지 핵심적인 보장 사항을 제공한다.

핵심 특징설명예시 (my-app StatefulSet, my-service Headless Service)
안정적인 고유 식별자Pod이 재생성되어도 변하지 않는 고유한 이름을 부여한다my-app-0, my-app-1, my-app-2
안정적인 네트워크Pod의 고유한 이름을 기반으로 DNS 주소를 고정적으로 제공한다my-app-0.my-service, my-app-1.my-service
안정적인 스토리지각 Pod에 영구적인 스토리지(PVC)를 1:1로 연결하고, Pod이 재생성되어도 동일한 스토리지를 다시 연결해 준다my-app-0은 항상 pvc-my-app-0에 연결

왜 필요한가?

  • 데이터베이스 클러스터 (MySQL, PostgreSQL 등): 마스터-슬레이브 구조에서 슬레이브 노드가 마스터 노드의 주소(my-db-0.my-db)를 알아야 한다. 또한, 각 노드는 자신의 데이터를 잃어버리면 안 된다.
  • 분산 메시지 큐 (Kafka, Zookeeper 등): 클러스터 내 각 브로커(노드)는 고유한 ID와 데이터 파티션을 가지며, 다른 브로커와 통신해야 한다.
  • 분산 검색 엔진 (Elasticsearch 등): 샤드(데이터 조각)가 특정 노드에 고정적으로 할당되어 데이터의 일관성을 유지해야 한다.

2. StatefulSet의 장점

StatefulSet을 사용하면 상태를 가진 애플리케이션을 쿠버네티스 환경에서 운영할 때 다음과 같은 명확한 이점을 얻을 수 있다.

2.1 데이터 영속성 보장

가장 큰 장점이다. Pod이 어떤 이유로든(노드 장애, 업데이트 등) 삭제되고 새로 생성되더라도, 기존에 사용하던 PVC(PersistentVolumeClaim)를 그대로 다시 연결한다. 따라서 데이터가 유실되지 않고 안전하게 보존된다.

2.2 예측 가능한 네트워크 통신

<pod-name>.<service-name> 형태의 안정적인 DNS 이름을 제공하기 때문에, 클러스터 내 다른 Pod들이 변경 없는 주소로 상대방을 식별하고 통신할 수 있다. 이는 서비스 디스커버리(Service Discovery) 복잡성을 크게 줄여준다.
-> 왜냐면 pod 가 재기동(reschedule)되어도 pod명이 계속 유지되기 때문에 가능
deployment는 재기동되면 계속 이름이 바뀐다.

2.3 순차적인 운영 관리

StatefulSet은 Pod을 생성, 스케일링, 삭제할 때 정해진 순서(Ordered)를 따른다.

  • 생성/스케일링 아웃: 0번 Pod부터 순서대로 생성된다. (my-app-0 -> my-app-1 -> my-app-2)
  • 삭제/스케일링 인: 가장 높은 번호의 Pod부터 순서대로 삭제된다. (my-app-2 -> my-app-1 -> my-app-0)

이 순서 보장은 데이터베이스 클러스터처럼 마스터 노드가 먼저 준비되어야 슬레이브 노드가 연결될 수 있는 환경에서 매우 중요하다.

2.4 클러스터링 애플리케이션 관리 용이성

위의 장점들이 모두 합쳐져, 복잡한 분산 시스템(클러스터)을 쿠버네티스 위에 구축하는 것이 훨씬 쉬워진다. 개발자가 직접 Pod의 상태를 추적하거나 스토리지를 수동으로 연결할 필요 없이, StatefulSet이라는 선언적(Declarative) YAML 파일만으로 시스템 전체의 안정성을 보장받을 수 있다.


3. StatefulSet 필수 구성 요소

StatefulSet을 사용하려면 반드시 알아야 할 필수 구성 요소들이 있다.

3.1 Headless Service (필수)

StatefulSet(sts)은 반드시 Headless Service와 함께 사용해야 한다.
Headless Service는 clusterIP: None으로 설정된 서비스로, 각 Pod에 개별 DNS 레코드를 생성해준다.
생각해보면, sts장점이 pod 명이유지된다는 것이기 때문에 이를 최대한 활용하기 위한 방법이지 않을까싶다. IP는 POD 재기동시 DEPLOYMENT와 동일하게 변경되기 때문에

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  clusterIP: None  # Headless Service 핵심 설정
  selector:
    app: my-app
  ports:
    - port: 80
      targetPort: 8080

이렇게 설정하면 각 Pod은 다음과 같은 DNS로 접근 가능해진다:

  • my-app-0.my-service.default.svc.cluster.local
  • my-app-1.my-service.default.svc.cluster.local

3.2 volumeClaimTemplates

volumeClaimTemplates는 StatefulSet의 핵심 기능 중 하나이다. 각 Pod마다 독립적인 PVC를 자동으로 생성해준다.

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: my-app
spec:
  serviceName: "my-service"
  replicas: 3
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
        - name: app
          image: nginx
          volumeMounts:
            - name: data
              mountPath: /data
  volumeClaimTemplates:
    - metadata:
        name: data
      spec:
        accessModes: ["ReadWriteOnce"]
        storageClassName: "standard"
        resources:
          requests:
            storage: 10Gi

위 설정으로 생성되는 PVC:

  • data-my-app-0
  • data-my-app-1
  • data-my-app-2

4. Pod Management Policy

StatefulSet은 두 가지 Pod 관리 정책을 제공한다.

4.1 OrderedReady (기본값)

spec:
  podManagementPolicy: OrderedReady
  • Pod을 순차적으로 생성/삭제한다
  • 이전 Pod이 Running & Ready 상태가 되어야 다음 Pod을 생성한다
  • 데이터베이스 클러스터처럼 순서가 중요한 경우에 적합하다

4.2 Parallel

spec:
  podManagementPolicy: Parallel
  • 모든 Pod을 동시에 생성/삭제한다
  • 순서가 중요하지 않고 빠른 스케일링이 필요한 경우에 사용한다
  • 각 Pod이 독립적으로 동작하는 경우에 적합하다

5. Update Strategy

StatefulSet의 업데이트 전략은 두 가지가 있다.

5.1 RollingUpdate (기본값)

spec:
  updateStrategy:
    type: RollingUpdate
    rollingUpdate:
      partition: 0  # 이 번호 이상의 Pod만 업데이트
  • Pod을 역순으로 하나씩 업데이트한다 (N-1 -> N-2 -> ... -> 0)
  • partition 값을 설정하면 카나리 배포가 가능하다
    • 예: partition: 2이면 my-app-2, my-app-3, ... 만 업데이트되고 my-app-0, my-app-1은 그대로 유지된다

5.2 OnDelete

spec:
  updateStrategy:
    type: OnDelete
  • Pod을 수동으로 삭제해야만 새 버전으로 업데이트된다
  • 완전한 수동 제어가 필요한 경우에 사용한다
  • 레거시 애플리케이션 마이그레이션 시 유용하다

6. PVC 삭제 정책

중요한 점: StatefulSet을 삭제하거나 스케일 다운해도 PVC는 자동으로 삭제되지 않는다.

이는 데이터 보호를 위한 의도적인 설계이다. PVC를 삭제하려면 수동으로 삭제해야 한다.

# StatefulSet 삭제 후에도 PVC는 남아있음
kubectl delete statefulset my-app

# PVC 수동 삭제
kubectl delete pvc data-my-app-0 data-my-app-1 data-my-app-2

Kubernetes 1.27+에서는 persistentVolumeClaimRetentionPolicy로 이 동작을 제어할 수 있다:

spec:
  persistentVolumeClaimRetentionPolicy:
    whenDeleted: Delete    # StatefulSet 삭제 시 PVC도 삭제
    whenScaled: Retain     # 스케일 다운 시 PVC 유지

7. StatefulSet 동작 흐름도 (생성 및 스케일링)

아래 흐름도는 replicas: 3으로 설정된 my-app StatefulSet을 생성(kubectl apply)할 때의 동작 과정을 순서대로 나타낸 것이다.

흐름도 설명

  1. 시작: 사용자가 StatefulSet YAML 파일을 적용한다.
  2. 컨트롤러 감지: StatefulSet 컨트롤러가 이 변경 사항을 감지한다.
  3. 순차적 생성 (0 → 1 → 2):
    • 컨트롤러는 0번 Pod부터 생성을 시도한다.
    • 먼저 data-my-app-0 라는 이름의 PVC를 생성하고, 스토리지가 할당될 때까지(Bound 상태) 기다린다.
    • PVC가 준비되면, my-app-0 라는 이름의 Pod를 생성한다. 이 Pod는 방금 생성한 PVC를 자동으로 연결한다.
    • my-app-0 Pod가 완전히 실행 준비(Ready) 상태가 되면, 그다음 1번 Pod를 동일한 과정으로 생성한다.
    • 이 과정을 replicas에 지정된 수(여기서는 3)만큼 반복한다.
  4. 스케일 아웃 (Scale-out): replicas를 3에서 4로 늘리면, 기존에 생성된 Pod(0, 1, 2)는 그대로 두고 3번 Pod부터 동일한 순서에 따라 생성된다.
  5. 스케일 인 (Scale-in): replicas를 3에서 2로 줄이면, 가장 마지막에 생성된 Pod부터 역순으로 삭제된다. 즉, my-app-2 Pod가 삭제되지만 PVC는 유지된다 (기본 동작).

8. StatefulSet vs Deployment 비교

항목StatefulSetDeployment
Pod 이름고정 (my-app-0, my-app-1)랜덤 (my-app-7d8f9-abc12)
네트워크 ID고정 DNS변경될 수 있음
스토리지Pod별 고정 PVC공유 또는 없음
생성 순서순차적 (0→1→2)병렬
삭제 순서역순 (2→1→0)병렬
롤링 업데이트역순임의
사용 사례DB, Kafka, Elasticsearch웹 서버, API 서버

9. 실전 팁

9.1 Pod가 Pending 상태로 멈춰있는 경우

대부분 PVC가 Bound되지 않아서 발생한다. StorageClass가 올바르게 설정되어 있는지, PV가 충분한지 확인해야 한다.

kubectl get pvc
kubectl describe pvc data-my-app-0

9.2 특정 Pod만 재시작하고 싶은 경우

Pod을 삭제하면 StatefulSet 컨트롤러가 동일한 이름, 동일한 PVC로 재생성해준다.

kubectl delete pod my-app-1

9.3 데이터 마이그레이션 시

OnDelete 업데이트 전략을 사용하면 Pod을 하나씩 수동으로 삭제하며 안전하게 마이그레이션할 수 있다.


##주로 deployment와 statefulset 많이 사용하는데,
볼륨 활용관점에서 헷갈려서 비교


개인 서비스를 deployment 가 아닌 statefulset 으로 띄운다면 pod 가 내려가도 ip와 도메인이 안바뀌고 유지되는 건가?


1. 도메인 이름 (DNS): 안정적으로 유지된다

이것이 StatefulSet의 핵심 장점이자 가장 중요한 부분이다.

동작 원리

StatefulSet은 Pod를 생성할 때 my-app-0, my-app-1과 같이 순번(ordinal)이 포함된 고유한 이름을 부여한다.

Headless Service와의 결합

StatefulSet은 일반적으로 clusterIP: None 설정의 Headless Service와 함께 사용된다. 이 서비스는 자체적으로 클러스터 IP를 갖지 않고, 대신 DNS 조회 요청이 오면 연결된 Pod들의 IP 주소 목록을 반환한다.

이 두 가지가 결합되어 my-app-0.my-headless-service와 같은 고정된 DNS 이름이 생성된다.

Pod 재시작 시

만약 my-app-0 Pod가 노드 장애 등으로 삭제되고 새로 생성되더라도, 새로운 Pod의 이름은 여전히 my-app-0이다. 따라서 DNS 이름인 my-app-0.my-headless-service절대 변하지 않는다.

애플리케이션이 다른 Pod를 찾을 때 IP 주소가 아닌 이 고정된 DNS 이름을 사용한다면, Pod가 교체되어도 통신에 문제가 없다.


2. Pod IP 주소: 보장되지 않는다 ❌

동작 원리

쿠버네티스에서 Pod의 IP 주소는 Pod가 스케줄링된 노드(Worker Node)에 의해 동적으로 할당된다.

Pod 재시작 시

만약 my-app-0 Pod가 다른 노드로 재스케줄링되거나, 같은 노드에서 다시 생성되더라도 새로운 IP 주소를 할당받을 가능성이 매우 높다.

StatefulSet의 한계

StatefulSet은 Pod의 이름이 고정되도록 보장할 뿐, Pod가 특정 IP 주소를 가지도록 보장하지는 않는다.

StatefulSet은 my-app-0.my-headless-service라는 이름표(DNS)는 고정시켜주지만, 그 이름표가 붙은 Pod의 실제 주소(IP)는 여전히 바뀔 수 있다.


3. Deployment vs StatefulSet 비교

구분DeploymentStatefulSet
Pod 이름매번 재생성 시 랜덤 해시값 포함 (예: my-app-5f7d8b9c-abcde)순번으로 고정됨 (예: my-app-0)
Pod IP변경됨 (보장 안 됨)변경됨 (보장 안 됨)
도메인 (DNS)변경됨 (Pod 이름이 바뀌므로)고정됨 (Pod 이름이 고정되므로)
스토리지여러 Pod가 하나의 PVC를 공유 가능 (ReadWriteMany)각 Pod이 전용 PVC를 1:1로 연결 (ReadWriteOnce)

4. 언제 무엇을 써야 하는가?

대부분의 경우, 일반적인 서비스는 Deployment를 사용하는 것이 표준이고 올바른 선택이다.

Deployment를 추천하는 경우 (대부분의 웹 서비스)

  • 블로그, 웹사이트, 간단한 API 서버 등 (Stateless 애플리케이션)
  • 여러 Pod가 로드밸런싱되어 하나의 서비스처럼 동작해야 할 때
  • 빠르고 무중단 배포(Rolling Update)가 중요할 때
  • 단순히 데이터를 저장하고 싶다면? → DeploymentPVC(PersistentVolumeClaim)를 하나만 연결해서 사용하면 된다. Pod가 재생성되어도 같은 PVC를 다시 붙이기 때문에 데이터는 유지된다.

StatefulSet을 고려해볼 수 있는 경우

  • 애플리케이션이 고정된 DNS 이름을 필요로 할 때 (예: 앱 내부에 다른 노드의 주소를 하드코딩해야 하는 특수한 경우)
  • 클러스터링을 구성해야 할 때 (예: 3대의 서버가 각자의 역할을 가지고 통신하는 경우)
  • 학습 목적으로 StatefulSet의 동작 방식을 경험해보고 싶을 때

profile
bytebliss

0개의 댓글