StatefulSet

앞서 살펴본 Pod의 기본 개념을 바탕으로, 이번에는 Pod가 가지는 주요 특성을 좀 더 깊이 학습해 보겠습니다.
👉 Pod는 언제든지 죽고 새로 생성 (Rolling Update, Auto Scaling 등)
👉 Pod IP는 새로 생성될 때 마다 변경
👉 HPA를 통해 리소스나 트래픽 상황에 따라 Scale Out/In(Auto Scale)이 빈번하게 발생
👉 ReplicaSet을 통해 Pod가 종료되거나 삭제되어도 설정된 상태로 즉시 복구
즉, 쉽게 비유하자면 학창 시절의 자유 좌석제 교실을 떠올릴 수 있습니다.
Deployment로 구동되는 애플리케이션의 Pod는 특정 자리에 이름표가 붙어 있지 않습니다. 학생이 매일 등교할 때마다 반드시 같은 책상에 앉는 것이 아니라, 비어 있는 자리나 상황에 따라 적절한 자리에 앉는 것처럼, Deployment의 Pod 역시 특정 Node나 고정된 위치에 강하게 묶여 있지 않습니다.
Pod가 삭제되거나 장애로 인해 종료되면 Kubernetes는 동일한 역할을 수행하는 새로운 Pod를 다시 생성합니다. 하지만 새로 생성된 Pod는 기존 Pod와 완전히 같은 이름, 같은 IP, 같은 위치를 보장하지 않습니다. 중요한 것은 "그 Pod 자체"가 아니라, 애플리케이션이 원하는 개수만큼 계속 실행되고 있는 상태입니다.
이것이 Deployment 기반 Pod의 핵심 특성입니다. 각각의 Pod는 고유한 정체성을 가진 존재라기보다는, 언제든 새로 생성되고 교체될 수 있는 일회성 실행 단위에 가깝습니다.
그렇다면 이러한 Deploy 구조 위에 Database나 Disk I/O가 지속적으로 발생하는 미들웨어를 배포하면 어떻게 될까요?
앞서 살펴본 것처럼 Deployment로 생성된 Pod는 특정 위치나 고정된 정체성을 보장하지 않습니다. 장애, 재배포, 스케일링 등의 이유로 Pod는 언제든 삭제되고 새로 생성될 수 있으며, 이 과정에서 Pod 이름, IP, 배치되는 Node가 변경될 수 있습니다.
이러한 특성은 Stateless 애플리케이션에는 큰 문제가 되지 않습니다. 하지만 Database처럼 데이터를 지속적으로 저장해야 하거나, Kafka, Redis, Elasticsearch와 같이 Disk I/O와 상태 관리가 중요한 미들웨어라면 이야기가 달라집니다.
Pod가 재생성될 때마다 저장 위치나 네트워크 식별자가 바뀔 수 있다면, 데이터 일관성, 복구, 클러스터 구성, 장애 대응 측면에서 문제가 발생할 수 있습니다. 즉, 단순히 “애플리케이션이 다시 뜨는 것”만으로는 충분하지 않고, 이전 상태를 유지한 채 안정적으로 복구되는 구조가 필요해집니다.
바로 이러한 문제를 해결하기 위해 Kubernetes에서는 StatefulSet 리소스를 제공합니다.

👉 Pod 재시작·스케줄링이 발생해도 고유의 불변 ID(Sticky Identity) 사용
👉 Pod가 랜덤 노드에 스케줄링 되어도 Pod – PVC에 대한 고유 id를 매핑하여 데이터 유지
👉 Headless Service를 통해 각 파드에 고유한 DNS 이름을 부여
예시) StatefulSet 이름: db
Headless Service 이름: my-db
db-0.my-db.svc -> Pod1
db-1.my-db.svc -> Pod2
db-2.my-db.svc -> Pod3
StatefulSet은 상태를 가지는 애플리케이션을 운영하기 위한 Kubernetes Workload 리소스입니다. 각 Pod에 고정된 이름과 순서를 부여하고, Headless Service를 통해 고유한 DNS를 제공하며, Pod별 PVC를 연결해 데이터를 유지할 수 있습니다. 이러한 특성 덕분에 데이터베이스, 메시지 큐, 분산 저장소처럼 Pod의 식별자와 스토리지 유지가 중요한 서비스에 적합합니다.
Deployment로 생성된 Pod가 자유 좌석제 학생이라면, StatefulSet으로 생성된 Pod는 자기 이름표가 붙은 지정 좌석을 가진 학생에 가깝습니다. 학창 시절 교실을 떠올려보면, 어떤 반은 매일 아무 자리에나 앉는 자유 좌석제가 아니라, 학생마다 정해진 자리가 있습니다.
예를 들어 1번 학생은 항상 1번 자리, 2번 학생은 항상 2번 자리, 3번 학생은 항상 3번 자리에 앉습니다.
이때 2번 학생이 잠시 교실을 나갔다가 다시 돌아오더라도, 아무 빈자리에 앉는 것이 아니라 다시 자신의 2번 자리로 돌아옵니다. 책상 위에 놓인 교과서, 필기구, 사물함도 그대로 2번 학생의 것으로 유지됩니다.
StatefulSet도 이와 같은 방식으로 동작합니다. StatefulSet으로 생성된 Pod는 pod-0, pod-1, pod-2처럼 고정된 이름과 순서를 가지며, 각 Pod는 자신에게 연결된 저장소를 유지합니다. Pod가 장애로 인해 삭제되더라도 Kubernetes는 동일한 이름의 Pod를 다시 생성하고, 기존에 사용하던 저장소를 다시 연결합니다.
이 때문에 StatefulSet은 스토리지와 떨어져 생각하기 어렵습니다.
물론 기술적으로 StatefulSet을 생성할 때 반드시 스토리지를 붙여야만 하는 것은 아닙니다. 하지만 StatefulSet을 사용하는 이유가 "상태를 가진 워크로드를 안정적으로 운영하기 위함"이라면, 결국 스토리지와 함께 구성될 수밖에 없습니다.
이러한 특성 덕분에 StatefulSet은 Database, Kafka, Elasticsearch처럼 데이터의 지속성, 생성 순서, 고정된 식별자가 중요한 워크로드에 적합한 리소스로 사용됩니다.
다만, StatefulSet이 상태 저장 워크로드에 적합하다고 해서 모든 Database를 Kubernetes 위에 올리는 것이 항상 바람직한 것은 아닙니다. 특히 RDBMS의 경우 데이터 정합성, 백업 및 복구, 장애 조치, 운영 복잡도 등을 함께 고려해야 하므로, StatefulSet으로 운영하는 것은 여전히 보수적으로 접근할 필요가 있습니다.

StatefulSet의 배포 플로우는 아래과 같습니다.
1. Headless Service 사전 생성
- StatefulSet은 각 Pod에 고정 DNS를 부여하기 위해 Headless Service를 참조합니다.
- Headless Service는 StatefulSet Controller가 자동 생성하지 않으므로, 사용자가 미리 생성해야 합니다.
- 예: pod-0.my-db.default.svc
2. StatefulSet 생성 요청
- 사용자가 kubectl apply -f statefulset.yaml 명령어를 실행합니다.
- 요청은 API Server로 전달됩니다.
- API Server는 요청받은 StatefulSet 오브젝트를 검증합니다.
3. StatefulSet 오브젝트 저장
- 검증이 완료된 StatefulSet 오브젝트는 etcd에 저장됩니다.
- etcd는 Kubernetes 클러스터의 원하는 상태(desired state)를 저장하는 key-value 저장소입니다.
- 이후 컨트롤러들은 API Server를 통해 이 상태 변화를 감지합니다.
4. StatefulSet Controller 감지
- Controller Manager 내부의 StatefulSet Controller가 API Server watch를 통해 StatefulSet 생성을 감지합니다.
- StatefulSet Controller는 선언된 replicas 수와 현재 Pod 상태를 비교합니다.
- 이후 필요한 Pod와 PVC 생성을 순차적으로 진행합니다.
5. PVC 생성
- StatefulSet은 volumeClaimTemplates를 기준으로 각 Pod에 연결될 PVC를 생성합니다.
- 각 Pod는 고유한 PVC를 가지며, Pod가 재생성되어도 동일한 PVC를 다시 사용합니다.
- 예: data-db-0, data-db-1, data-db-2
6. Pod 생성 요청
- StatefulSet Controller는 Pod를 생성하기 위한 요청을 API Server에 기록합니다.
- 이때 Pod는 아직 노드가 정해지지 않은 Pending 상태입니다.
- StatefulSet은 Pod 이름을 pod-0, pod-1, pod-2처럼 순서 있는 이름으로 생성합니다.
7. Pod 순차 생성
- StatefulSet은 Pod를 한 번에 모두 생성하지 않고 순서대로 생성합니다.
- 먼저 pod-0을 생성하고, 해당 Pod가 Running 및 Ready 상태가 된 뒤 pod-1을 생성합니다.
- 이후 pod-1이 Ready가 되면 pod-2를 생성하는 방식으로 순서를 보장합니다.
8. Scheduler가 Pod 배치
- Scheduler는 아직 노드가 지정되지 않은 Pending Pod를 감지합니다.
- 각 노드의 리소스, taint/toleration, affinity, 볼륨 제약 조건 등을 기준으로 적절한 노드를 선택합니다.
- 선택된 노드 정보는 API Server를 통해 Pod의 nodeName에 기록됩니다.
9. kubelet이 할당된 Pod 감지
- 각 노드의 kubelet은 API Server를 watch 하며 자신에게 할당된 Pod를 감지합니다.
- kubelet은 Pod Spec을 확인하고, 해당 Pod를 실행하기 위한 준비를 시작합니다.
- 이 단계부터 실제 워커 노드에서 Pod 실행 작업이 진행됩니다.
10. PVC 마운트
- kubelet은 Pod에 연결된 PVC를 확인하고 스토리지를 마운트합니다.
- 최초 생성 시에는 새로 생성된 PVC를 사용하고, Pod 재생성 시에는 기존 PVC를 다시 사용합니다.
- 이를 통해 Pod가 재시작되거나 다른 노드로 이동하더라도 데이터를 유지할 수 있습니다.
11. 컨테이너 생성 요청
- kubelet은 CRI를 통해 containerd와 같은 Container Runtime에 컨테이너 생성을 요청합니다.
- 이때 Pod Spec에 정의된 이미지, 포트, 환경변수, 볼륨 마운트 정보가 전달됩니다.
- 실제 컨테이너 생성 작업은 Container Runtime이 수행합니다.
12. 이미지 Pull
- Container Runtime은 필요한 컨테이너 이미지를 Registry에서 Pull합니다.
- 이미지가 이미 노드에 존재하고 imagePullPolicy 조건에 맞으면 Pull을 생략할 수도 있습니다.
- 이미지 Pull이 완료되면 컨테이너 실행 준비가 완료됩니다.
13. 컨테이너 실행 및 Ready 확인
- Container Runtime은 컨테이너를 생성하고 실행합니다.
- Pod가 Running 상태가 되고 Readiness Probe를 통과하면 Ready 상태가 됩니다.
- StatefulSet은 이전 Pod가 Ready 상태가 된 것을 확인한 뒤 다음 ordinal Pod 생성을 진행합니다.
14. 상태 업데이트
- kubelet은 Pod와 컨테이너의 상태를 API Server로 지속적으로 업데이트합니다.
- API Server에 기록된 상태를 기반으로 Controller는 원하는 상태와 실제 상태를 비교합니다.
- 문제가 발생하면 StatefulSet Controller와 kubelet이 다시 상태를 맞추는 작업을 수행합니다.
15. 삭제 시 역순 처리
- StatefulSet의 Pod 삭제는 생성 순서와 반대로 진행됩니다.
- 예를 들어 pod-2 → pod-1 → pod-0 순서로 종료됩니다.
- 이 구조를 통해 상태가 있는 애플리케이션의 순서와 안정성을 보장합니다.
'쿠버네티스' 카테고리의 다른 글
| [쿠버네티스] Deployment 쉽게 이해하기: Pod를 안정적으로 배포하는 방법 (0) | 2026.06.25 |
|---|---|
| [쿠버네티스] Static Pod vs Dynamic Pod: 누가 Pod를 관리하는가? (0) | 2026.06.17 |
| [쿠버네티스] Control Plane 상세 분석: API Server, Scheduler, Controller Manager, etcd (0) | 2026.06.12 |
| [쿠버네티스] Kubernetes 아키텍처 입문: 클러스터는 어떻게 구성될까? (0) | 2026.06.10 |
| [쿠버네티스] 왜 컨테이너 대신 파드(Pod)일까? 쿠버네티스의 가장 작은 배포 단위 (0) | 2026.06.10 |