스테이트풀셋
스테이트풀셋 (StatefulSet)
StatefulSet은 파드 그룹을 실행하면서 각 파드에 **고정된(sticky) 정체성(identity)**을 유지해 주는 워크로드 API 객체예요. 영구 스토리지가 필요하거나 안정적이고 유일한 네트워크 정체성이 필요한 애플리케이션을 관리할 때 유용합니다.
Deployment와 비슷하게 StatefulSet도 동일한 컨테이너 스펙을 기반으로 파드를 관리하지만, Deployment와 달리 각 파드에 고정된 정체성을 부여해요. 같은 스펙으로 만들어진 파드라도 서로 교체할 수 없고, 재스케줄링을 거쳐도 유지되는 고유 식별자를 가집니다.
StatefulSet 활용 (Using StatefulSets)
StatefulSet은 다음 중 하나 이상이 필요한 애플리케이션에 유용해요:
- 안정적이고 유일한 네트워크 식별자
- 안정적인 영구 스토리지
- 순서가 있는, 우아한(graceful) 배포와 스케일링
- 순서가 있는 자동 롤링 업데이트
여기서 "안정적(stable)"이라는 건 파드가 (재)스케줄링되어도 유지된다는 뜻이에요. 안정적인 식별자나 순서 있는 배포·삭제·스케일링이 필요 없는 애플리케이션이라면, 무상태(stateless) 레플리카를 제공하는 Deployment나 ReplicaSet이 더 적합해요.
제약 사항 (Limitations)
- 주어진 파드의 스토리지는 요청된 storage class에 기반한 PersistentVolume Provisioner로 프로비저닝되거나, 관리자가 미리 프로비저닝해야 해요.
- StatefulSet을 삭제하거나 축소해도 StatefulSet과 연결된 볼륨은 삭제되지 않아요. 데이터 안전을 보장하기 위함이에요.
- StatefulSet은 현재 파드의 네트워크 정체성을 담당하는 Headless Service가 필요합니다. 이 Service를 만드는 건 여러분의 책임이에요.
- StatefulSet은 삭제 시 파드 종료에 대한 보장을 제공하지 않습니다. 순서 있는 우아한 종료를 하려면 삭제 전에 replicas를 0으로 스케일 다운하면 돼요.
- 기본 Pod Management Policy(
OrderedReady)로 롤링 업데이트할 때 수동 복구가 필요한 깨진 상태가 될 수도 있어요.
구성 요소 (Components)
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
ports:
- port: 80
name: web
clusterIP: None
selector:
app: nginx
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
selector:
matchLabels:
app: nginx # has to match .spec.template.metadata.labels
serviceName: "nginx"
replicas: 3 # by default is 1
minReadySeconds: 10 # by default is 0
template:
metadata:
labels:
app: nginx # has to match .spec.selector.matchLabels
spec:
terminationGracePeriodSeconds: 10
containers:
- name: nginx
image: registry.k8s.io/nginx-slim:0.24
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: www
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: "my-storage-class"
resources:
requests:
storage: 1Gi
참고: 이 예시는 단순함을 위해
ReadWriteOnce접근 모드를 사용했습니다. 프로덕션에서는ReadWriteOncePod접근 모드를 권장해요.
위 예시에서:
nginx라는 Headless Service가 네트워크 도메인을 제어합니다.web이라는 StatefulSet은 고유한 파드 3개에서 nginx 컨테이너 레플리카를 실행하도록 지정합니다.volumeClaimTemplates는 PersistentVolume Provisioner가 프로비저닝한 PersistentVolumes로 안정적인 스토리지를 제공합니다.
StatefulSet 객체의 이름은 유효한 DNS label이어야 해요.
파드 셀렉터 (Pod Selector)
StatefulSet의 .spec.selector는 .spec.template.metadata.labels와 일치해야 합니다. 일치하지 않으면 생성 시 검증 오류가 발생해요.
볼륨 클레임 템플릿 (Volume Claim Templates)
.spec.volumeClaimTemplates는 PersistentVolumeClaim을 생성해요. 다음 중 하나가 해당하면 StatefulSet에 안정적인 스토리지를 제공합니다:
- 볼륨 클레임에 지정된 StorageClass가 동적 프로비저닝을 사용하도록 설정된 경우
- 클러스터에 올바른 StorageClass와 충분한 저장 공간을 가진 PersistentVolume이 이미 있는 경우
최소 준비 시간 (Minimum ready seconds)
Feature state: Stable since Kubernetes v1.25
.spec.minReadySeconds는 새로 생성된 파드가 컨테이너 충돌 없이 실행·준비되어 있어야 하는 최소 시간(초)을 지정하는 선택 필드예요. 롤링 업데이트 시 롤아웃 진행을 확인하는 데 사용됩니다. 기본값은 0(준비되자마자 사용 가능으로 간주)이에요.
파드 정체성 (Pod Identity)
StatefulSet 파드는 서수(ordinal), 안정적인 네트워크 정체성, 안정적인 스토리지로 구성된 고유한 정체성을 가져요. 파드가 어느 노드에 (재)스케줄링되든 정체성은 유지됩니다.
서수 인덱스 (Ordinal Index)
N개의 레플리카를 가진 StatefulSet에서 각 파드에는 셋 내에서 고유한 정수 서수가 부여돼요. 기본적으로 0부터 N-1까지 부여되며, 컨트롤러는 apps.kubernetes.io/pod-index라는 파드 라벨도 추가합니다.
시작 서수 (Start ordinal)
Feature state: Stable since Kubernetes v1.31; enabled by default
.spec.ordinals.start를 설정하면 파드가 .spec.ordinals.start부터 .spec.ordinals.start + .spec.replicas - 1까지의 서수를 받아요.
안정적인 네트워크 ID (Stable Network ID)
각 파드의 hostname은 $(statefulset name)-$(ordinal) 패턴으로 만들어져요. 위 예시는 web-0, web-1, web-2라는 파드 3개를 만들죠. StatefulSet은 Headless Service를 사용해 파드의 도메인을 제어할 수 있어요. 파드 DNS는 $(podname).$(governing service domain) 형태로 구성됩니다.
| Cluster Domain | Service (ns/name) | StatefulSet (ns/name) | StatefulSet Domain | Pod DNS | Pod Hostname |
|---|---|---|---|---|---|
| cluster.local | default/nginx | default/web | nginx.default.svc.cluster.local | web-{0..N-1}.nginx.default.svc.cluster.local | web-{0..N-1} |
| cluster.local | foo/nginx | foo/web | nginx.foo.svc.cluster.local | web-{0..N-1}.nginx.foo.svc.cluster.local | web-{0..N-1} |
| kube.local | foo/nginx | foo/web | nginx.foo.svc.kube.local | web-{0..N-1}.nginx.foo.svc.kube.local | web-{0..N-1} |
참고: 클러스터 도메인은 별도로 설정하지 않으면
cluster.local이에요.
안정적인 스토리지 (Stable Storage)
정의된 VolumeClaimTemplate 항목마다 각 파드는 PersistentVolumeClaim 하나를 받아요. 파드가 (재)스케줄링되면 volumeMounts가 해당 PersistentVolumeClaim과 연결된 PersistentVolume을 마운트합니다. 파드나 StatefulSet이 삭제되어도 PVC에 연결된 PersistentVolume은 삭제되지 않으며, 수동으로 정리해야 해요.
파드 이름 라벨 (Pod Name Label)
StatefulSet 컨트롤러는 파드를 만들 때 statefulset.kubernetes.io/pod-name 라벨을 추가해요. 이 라벨로 특정 파드에 Service를 연결할 수 있습니다.
파드 인덱스 라벨 (Pod index label)
Feature state: Stable since Kubernetes v1.32; enabled by default
파드 서수 인덱스를 담은 라벨이 추가됩니다.
레플리카 (Replicas)
.spec.replicas는 원하는 파드 수를 지정하는 선택 필드이며 기본값은 1이에요. kubectl scale statefulset <이름> --replicas=3으로 수동 스케일링한 뒤 매니페스트로 kubectl apply하면 매니페스트가 이전 수동 스케일링을 덮어씁니다. HorizontalPodAutoscaler가 스케일링을 관리한다면 .spec.replicas를 직접 설정하지 말고 컨트롤 플레인이 관리하도록 두는 게 좋아요.
다음 단계 (What's next)
- Pods에 대해 배워 보세요.
- StatefulSet을 사용하는 방법을 알아보세요 (상태 유지 애플리케이션 배포, Cassandra 배포, 복제 상태 유지 애플리케이션 실행 등).
StatefulSet은 쿠버네티스 REST API의 최상위 리소스예요. StatefulSet 객체 정의를 읽어보세요.- PodDisruptionBudget에 대해 알아보세요.