StatefulSet
상태가 있는 애플리케이션을 위한 Kubernetes 리소스
상태가 있는 애플리케이션을 위한 Kubernetes 리소스
StatefulSet은 상태가 있는(Stateful) 애플리케이션을 관리하기 위한 Kubernetes 워크로드 리소스입니다. Deployment와 달리 각 Pod에 고유한 네트워크 ID와 안정적인 영구 스토리지를 제공하며, 순서대로 배포/삭제됩니다.
StatefulSet vs Deployment:
주요 사용 사례:
Pod 관리 정책:
업데이트 전략: RollingUpdate(역순 롤링), OnDelete(수동 삭제 시 업데이트), partition(특정 인덱스 이상만 업데이트) 옵션을 제공합니다.
# postgres-statefulset.yaml
apiVersion: v1
kind: Service
metadata:
name: postgres-headless
labels:
app: postgres
spec:
ports:
- port: 5432
name: postgres
clusterIP: None # Headless Service
selector:
app: postgres
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: postgres
spec:
serviceName: postgres-headless # Headless Service 연결
replicas: 3
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
containers:
- name: postgres
image: postgres:15
ports:
- containerPort: 5432
name: postgres
env:
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: postgres-secret
key: password
- name: PGDATA
value: /var/lib/postgresql/data/pgdata
volumeMounts:
- name: postgres-data
mountPath: /var/lib/postgresql/data
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
readinessProbe:
exec:
command: ["pg_isready", "-U", "postgres"]
initialDelaySeconds: 5
periodSeconds: 10
# PersistentVolumeClaim 템플릿
volumeClaimTemplates:
- metadata:
name: postgres-data
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: standard
resources:
requests:
storage: 10Gi
# 업데이트 전략
updateStrategy:
type: RollingUpdate
rollingUpdate:
partition: 0 # 모든 Pod 업데이트
# Pod 관리 정책
podManagementPolicy: OrderedReady
# StatefulSet Pod DNS 형식
# {pod-name}.{headless-service}.{namespace}.svc.cluster.local
# 예시: postgres StatefulSet (3 replicas)
# postgres-0.postgres-headless.default.svc.cluster.local
# postgres-1.postgres-headless.default.svc.cluster.local
# postgres-2.postgres-headless.default.svc.cluster.local
# 같은 네임스페이스에서 접근
psql -h postgres-0.postgres-headless -U postgres
# 애플리케이션 연결 문자열 (Primary)
postgresql://postgres:password@postgres-0.postgres-headless:5432/mydb
# kubectl로 상태 확인
kubectl get statefulset postgres
# NAME READY AGE
# postgres 3/3 10m
kubectl get pods -l app=postgres
# NAME READY STATUS RESTARTS AGE
# postgres-0 1/1 Running 0 10m
# postgres-1 1/1 Running 0 9m
# postgres-2 1/1 Running 0 8m
# PVC 확인 (Pod별 별도 PVC)
kubectl get pvc
# NAME STATUS VOLUME CAPACITY ACCESS MODES
# postgres-data-postgres-0 Bound pvc-xxx 10Gi RWO
# postgres-data-postgres-1 Bound pvc-yyy 10Gi RWO
# postgres-data-postgres-2 Bound pvc-zzz 10Gi RWO
# partition을 사용한 단계적 롤아웃
# partition=2면 인덱스 2 이상 Pod만 업데이트 (postgres-2만)
# 1. partition 설정으로 일부만 업데이트
kubectl patch statefulset postgres -p \
'{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":2}}}}'
# 2. 이미지 업데이트 (postgres-2만 업데이트됨)
kubectl set image statefulset/postgres postgres=postgres:16
# 3. postgres-2 테스트 후 partition 낮추기
kubectl patch statefulset postgres -p \
'{"spec":{"updateStrategy":{"rollingUpdate":{"partition":1}}}}'
# postgres-1, postgres-2 업데이트됨
# 4. 전체 롤아웃
kubectl patch statefulset postgres -p \
'{"spec":{"updateStrategy":{"rollingUpdate":{"partition":0}}}}'
# postgres-0, postgres-1, postgres-2 모두 업데이트됨
개발자: "DB를 Kubernetes에 올리려는데 Deployment로 하면 될까요?"
시니어: "DB는 StatefulSet을 써야 해. Deployment는 Pod 이름이 랜덤이고, PVC도 Pod 삭제되면 관리가 어려워. StatefulSet은 postgres-0, postgres-1처럼 고정 이름이고, 각 Pod마다 전용 PVC가 유지돼."
개발자: "마스터-슬레이브 구성은요?"
시니어: "postgres-0을 마스터로 고정하고, postgres-1, postgres-2를 슬레이브로 설정해. Headless Service 덕분에 각 Pod에 직접 DNS로 접근할 수 있어서 역할 분리가 쉬워."
면접관: "StatefulSet과 Deployment의 차이점을 설명해주세요."
지원자: "세 가지 주요 차이가 있습니다. 첫째, Pod 이름이 고정됩니다. Deployment는 랜덤 해시가 붙지만 StatefulSet은 0, 1, 2처럼 순차 인덱스입니다. 둘째, Headless Service와 함께 각 Pod에 고유 DNS가 부여됩니다. 셋째, PVC가 Pod와 1:1로 매핑되어 Pod가 재시작되어도 같은 볼륨을 사용합니다."
면접관: "언제 StatefulSet을 사용해야 하나요?"
지원자: "데이터베이스, Kafka, ZooKeeper처럼 각 인스턴스가 고유한 ID를 가지고 영구 저장소가 필요한 경우입니다. 반면 웹 서버처럼 상태가 없는 앱은 Deployment가 적합해요."
운영팀: "StatefulSet 스케일아웃이 안 돼요. Pod가 Pending 상태예요."
개발자: "PVC 프로비저닝 문제일 가능성이 높아요. StorageClass가 제대로 설정되어 있는지, 그리고 스토리지 용량이 충분한지 확인해보세요. kubectl describe pvc로 이벤트 확인하면 원인 나올 거예요."
운영팀: "Pod 삭제했는데 PVC가 남아있어요."
개발자: "StatefulSet은 의도적으로 PVC를 삭제하지 않아요. 데이터 보존을 위해서죠. 정말 삭제하려면 수동으로 kubectl delete pvc 해야 해요."