StatefulSet
StatefulSet
StatefulSet은 유상태(stateful) 애플리케이션을 관리하는 데 사용되는 워크로드 API 객체예요.
일련의 파드의 배포와 확장을 관리하고, 이러한 파드의 순서와 고유성에 대한 보장을 제공해요.
Deployment와 마찬가지로 StatefulSet은 동일한 컨테이너 사양을 기반으로 하는 파드를 관리해요. Deployment와 달리 StatefulSet은 각 파드에 대해 고정된(스티키) 신원을 유지해요. 이 파드들은 같은 사양으로 생성되지만 상호 교환할 수 없어요. 각각은 재스케줄링을 거쳐도 유지하는 영속적 식별자를 가져요.
워크로드에 영속성을 제공하기 위해 스토리지 볼륨을 사용하려면 솔루션의 일부로 StatefulSet을 사용할 수 있어요. StatefulSet의 개별 파드는 실패하기 쉽지만, 영속적 파드 식별자는 실패한 파드를 대체하는 새 파드와 기존 볼륨을 일치시키는 것을 더 쉽게 해줘요.
출처: 문서
본문
StatefulSet 사용하기 (Using StatefulSets)
StatefulSet은 다음 중 하나 이상을 요구하는 애플리케이션에 유용해요:
- 안정적이고 고유한 네트워크 식별자.
- 안정적이고 영구적인 스토리지.
- 순서 있는 원활한 배포와 확장.
- 순서 있는 자동 롤링 업데이트.
위에서 안정적(stable)은 파드 (재)스케줄링에 걸친 영속성과 동의어예요. 애플리케이션이 안정적 식별자나 순서 있는 배포, 삭제, 확장을 요구하지 않는다면 상태 없는 복제본 집합을 제공하는 워크로드 객체를 사용해 애플리케이션을 배포해야 해요. Deployment 또는 ReplicaSet이 상태 없는 요구에 더 잘 맞을 수 있어요.
제한 사항 (Limitations)
- 주어진 파드에 대한 스토리지는 요청된 storage class에 기반한 PersistentVolume Provisioner가 프로비저닝하거나 관리자가 사전 프로비저닝해야 해요.
- StatefulSet을 삭제하거나 축소해도 StatefulSet과 연관된 볼륨은 삭제되지 않아요. 이것은 일반적으로 관련 StatefulSet 리소스의 자동 정리보다 더 가치 있는 데이터 안전성을 보장하기 위한 것이에요.
- StatefulSet은 현재 파드의 네트워크 신원을 담당하는 Headless Service를 요구해요. 이 Service를 만드는 것은 사용자의 책임이에요.
- StatefulSet은 삭제될 때 파드 종료에 대한 어떤 보장도 제공하지 않아요. StatefulSet의 파드를 순서 있고 원활하게 종료하려면 삭제 전에 StatefulSet을 0으로 축소하는 것이 가능해요.
- 기본 Pod 관리 정책(
OrderedReady)으로 롤링 업데이트를 사용할 때 수동 개입이 필요한 깨진 상태에 빠질 수 있어요(#forced-rollback).
구성 요소 (Components)
아래 예시는 StatefulSet의 구성 요소를 보여줘요.
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
위 예시에서:
nginx라는 Headless Service가 네트워크 도메인을 제어하는 데 사용됨.web이라는 StatefulSet은 고유한 파드에 nginx 컨테이너 3개의 복제본이 시작될 것임을 나타내는 Spec을 가짐.- volumeClaimTemplates는 PersistentVolume Provisioner가 프로비저닝한 PersistentVolume을 사용해 안정적 스토리지를 제공할 것임.
StatefulSet 객체의 이름은 유효한 DNS 레이블이어야 해요.
파드 셀렉터 (#pod-selector)
StatefulSet의 .spec.selector 필드를 .spec.template.metadata.labels의 레이블과 일치시켜야 해요. 일치하는 파드 셀렉터를 지정하지 않으면 StatefulSet 생성 중에 검증 오류가 발생해요.
볼륨 클레임 템플릿 (#volume-claim-templates)
.spec.volumeClaimTemplates 필드를 설정해 PersistentVolumeClaim을 만들 수 있어요. 이것은 다음 중 하나라도 해당하면 StatefulSet에 안정적 스토리지를 제공해요:
- 볼륨 클레임에 지정된 StorageClass가 동적 프로비저닝을 사용하도록 설정됨.
- 클러스터에 올바른 StorageClass와 충분한 사용 가능한 스토리지 공간을 가진 PersistentVolume이 이미 존재함.
최소 준비 초 (#minimum-ready-seconds)
.spec.minReadySeconds는 새로 생성된 파드가 어떤 컨테이너도 크래시하지 않고 실행되고 준비된 상태로 있어야 하는 최소 초 수를 지정하는 선택적 필드로, 고려 대상으로 간주되기 위한 것이에요. 이것은 롤링 업데이트 전략을 사용할 때 롤아웃의 진행을 확인하는 데 사용돼요. 이 필드는 기본값 0입니다(파드가 준비되자마자 사용 가능한 것으로 간주됨). 파드가 언제 준비된 것으로 간주되는지 더 배우려면 컨테이너 프로브를 참고해요.
파드 신원 (Pod Identity)
StatefulSet 파드는 서수(ordinal), 안정적 네트워크 신원, 안정적 스토리지로 구성된 고유한 신원을 가져요. 신원은 어떤 노드에 (재)스케줄링되든 상관없이 파드에 고정돼요.
서수 인덱스 (#ordinal-index)
N개의 복제본이 있는 StatefulSet의 경우 StatefulSet의 각 파드에 집합에 대해 고유한 정수 서수가 할당돼요. 기본적으로 파드는 0부터 N-1까지의 서수를 할당받아요. StatefulSet 컨트롤러는 이 인덱스를 가진 파드 레이블인 apps.kubernetes.io/pod-index도 추가해요.
시작 서수 (#start-ordinal)
.spec.ordinals는 각 파드에 할당된 정수 서수를 구성할 수 있게 하는 선택적 필드예요. 기본값은 nil이에요. 필드 내에서 다음 옵션을 구성할 수 있어요:
.spec.ordinals.start:.spec.ordinals.start필드가 설정되면 파드는.spec.ordinals.start부터.spec.ordinals.start + .spec.replicas - 1까지의 서수를 할당받아요.
안정적 네트워크 ID (#stable-network-id)
StatefulSet의 각 파드는 StatefulSet의 이름과 파드의 서수에서 호스트네임을 파생해요. 구성된 호스트네임의 패턴은 $(statefulset name)-$(ordinal)이에요. 위 예시는 web-0, web-1, web-2라는 세 파드를 만들 거예요.
StatefulSet은 Headless Service를 사용해 파드의 도메인을 제어할 수 있어요. 이 Service가 관리하는 도메인은 $(service name).$(namespace).svc.cluster.local 형식을 취하며, 여기서 "cluster.local"은 클러스터 도메인이에요.
각 파드가 생성됨에 따라 $(podname).$(governing service domain) 형식의 일치하는 DNS 하위 도메인을 얻으며, 여기서 governing service는 StatefulSet의 serviceName 필드로 정의돼요.
클러스터에서 DNS가 구성된 방식에 따라 새로 실행된 파드의 DNS 이름을 즉시 조회하지 못할 수 있어요. 이 동작은 클러스터의 다른 클라이언트가 파드가 생성되기 전에 그 파드의 호스트네임에 대한 쿼리를 이미 보냈을 때 발생할 수 있어요. 음수 캐싱(DNS에서 일반적)은 이전 실패한 조회의 결과가 파드가 실행된 후에도 최소 몇 초 동안 기억되고 재사용된다는 뜻이에요.
파드가 생성된 후 신속하게 파드를 발견해야 한다면 몇 가지 옵션이 있어요:
- DNS 조회에 의존하지 않고 Kubernetes API를 직접 조회(예: watch 사용).
- Kubernetes DNS 프로바이더에서 캐싱 시간을 줄임(일반적으로 현재 30초 동안 캐싱하는 CoreDNS의 config map을 편집하는 것을 의미).
제한 사항 섹션에서 언급했듯이 파드의 네트워크 신원을 담당하는 Headless Service를 만드는 것은 사용자의 책임이에요.
다음은 Cluster Domain, Service 이름, StatefulSet 이름에 대한 선택과 그것이 StatefulSet의 파드에 대한 DNS 이름에 미치는 영향의 몇 가지 예시예요.
| 클러스터 도메인 | 서비스 (ns/name) | StatefulSet (ns/name) | StatefulSet 도메인 | 파드 DNS | 파드 호스트네임 |
|---|---|---|---|---|---|
| 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} |
DNS 레코드가 생성될 때까지, 그리고 해당 파드가 실행되기 전에 조회가 전송된 경우 음수 캐시 때문에 조회가 즉시 성공하지 않을 수 있다는 점을 유의해요.
안정적 스토리지 (#stable-storage)
StatefulSet에 정의된 각 VolumeClaimTemplate 항목에 대해 각 파드는 하나의 PersistentVolumeClaim을 받아요. 위의 nginx 예시에서 각 파드는 my-storage-class의 StorageClass와 1 GiB의 프로비저닝된 스토리지가 있는 단일 PersistentVolume을 받아요. StorageClass가 지정되지 않으면 기본 StorageClass가 사용돼요. 파드가 노드에 (재)스케줄링될 때 그 volumeMounts는 그 PersistentVolume 클레임과 연관된 PersistentVolume을 마운트해요. 파드나 StatefulSet이 삭제되어도 파드의 PersistentVolume 클레임과 연관된 PersistentVolume은 삭제되지 않는다는 점을 유의해요. 이것은 수동으로 해야 해요.
파드 이름 레이블 (#pod-name-label)
StatefulSet 컨트롤러가 파드를 만들 때 파드의 이름으로 설정된 statefulset.kubernetes.io/pod-name 레이블을 추가해요. 이 레이블은 StatefulSet의 특정 파드에 Service를 연결할 수 있게 해줘요.
파드 인덱스 레이블 (#pod-index-label)
StatefulSet 컨트롤러가 파드를 만들 때 새 파드는 apps.kubernetes.io/pod-index로 레이블이 지정돼요. 이 레이블의 값은 파드의 서수 인덱스예요. 이 레이블은 특정 파드 인덱스로 트래픽을 라우팅하고, 파드 인덱스 레이블로 로그/메트릭을 필터링하는 등에 사용할 수 있어요. 이 기능에 대해 PodIndexLabel 기능 게이트가 기본적으로 활성화되고 잠겨 있다는 점을 유의해요. 그것을 비활성화하려면 사용자가 서버 에뮬레이트 버전 v1.31을 사용해야 해요.
배포 및 확장 보장 (Deployment and Scaling Guarantees)
- N개의 복제본이 있는 StatefulSet의 경우 파드가 배포될 때
{0..N-1}순서대로 순차적으로 생성돼요. - 파드가 삭제될 때는
{N-1..0}의 역순으로 종료돼요. - 파드에 확장 작업이 적용되기 전에 모든 선행(predecessor) 파드가 Running 및 Ready여야 해요.
.spec.minReadySeconds(#minimum-ready-seconds)가 설정되면 선행 파드가 사용 가능해야 해요(minReadySeconds 동안 Ready). - 파드가 종료되기 전에 모든 후속(successor) 파드가 완전히 종료되어야 해요.
StatefulSet은 pod.Spec.TerminationGracePeriodSeconds를 0으로 지정해서는 안 돼요. 이 관행은 안전하지 않으며 강력히 권장되지 않아요. 자세한 설명은 StatefulSet 파드 강제 삭제를 참고해주세요.
위의 nginx 예시가 생성되면 web-0, web-1, web-2 순서로 세 파드가 배포돼요. web-1은 web-0이 Running 및 Ready(/docs/concepts/workloads/pods/pod-lifecycle/)가 될 때까지 배포되지 않고, web-2는 web-1이 Running 및 Ready가 될 때까지 배포되지 않아요. web-0이 web-1이 Running 및 Ready가 된 후, web-2가 시작되기 전에 실패하면 web-2는 web-0이 성공적으로 다시 시작되어 Running 및 Ready가 될 때까지 시작되지 않아요.
사용자가 배포된 예시를 replicas=1로 패치해 확장하면 web-2가 먼저 종료돼요. web-1은 web-2가 완전히 종료되고 삭제될 때까지 종료되지 않아요. web-0이 web-2가 종료되고 완전히 종료된 후, web-1의 종료 전에 실패하면 web-1은 web-0이 Running 및 Ready가 될 때까지 종료되지 않아요.
Pod 관리 정책 (#pod-management-policies)
StatefulSet은 .spec.podManagementPolicy 필드를 통해 순서 보장을 완화하면서도 고유성과 신원 보장을 보존할 수 있게 해줘요.
OrderedReady Pod 관리 (#orderedready-pod-management)
OrderedReady pod 관리는 StatefulSet의 기본값이에요. 배포 및 확장 보장에 설명된 동작을 구현해요.
Parallel Pod 관리 (#parallel-pod-management)
Parallel pod 관리는 StatefulSet 컨트롤러가 모든 파드를 병렬로 시작하거나 종료하게 하고, 다른 파드를 시작하거나 종료하기 전에 파드가 Running 및 Ready가 되거나 완전히 종료될 때까지 기다리지 않게 해요.
확장 작업의 경우 이것은 모든 파드가 동시에 생성되거나 종료된다는 뜻이에요.
.spec.updateStrategy.rollingUpdate.maxUnavailable(#maximum-unavailable-pods)이 1보다 큰 롤링 업데이트의 경우 StatefulSet 컨트롤러는 최대 maxUnavailable개의 파드를 동시에 종료하고 생성해요("버스팅"이라고도 함). 이것은 업데이트를 빠르게 할 수 있지만 파드가 순서 없이 준비될 수 있으며, 이는 엄격한 순서를 요구하는 애플리케이션에는 적합하지 않을 수 있어요.
업데이트 전략 (Update strategies)
StatefulSet의 .spec.updateStrategy 필드는 StatefulSet의 파드에 대한 컨테이너, 레이블, 리소스 요청/한도, 어노테이션의 자동 롤링 업데이트를 구성하고 비활성화할 수 있게 해줘요. 세 가지 가능한 값이 있어요:
- OnDelete: StatefulSet의
.spec.updateStrategy.type이OnDelete로 설정되면 StatefulSet 컨트롤러가 StatefulSet의 파드를 자동으로 업데이트하지 않아요. 사용자가 파드를 수동으로 삭제해야 컨트롤러가 StatefulSet의.spec.template에 대한 수정을 반영하는 새 파드를 만들게 돼요. - RollingUpdate: RollingUpdate 업데이트 전략은 StatefulSet의 파드에 대한 자동 롤링 업데이트를 구현해요. 이것이 기본 업데이트 전략이에요.
- Recreate: 기능 상태: Kubernetes v1.37부터 Alpha; 기본적으로 비활성화됨 이 기능에 대한 더 많은 정보 이 기능을 사용하려면 여러분(또는 클러스터 관리자)이 클러스터의 모든 관련 컴포넌트에 대해 StatefulSetRecreateStrategy(/docs/reference/command-line-tools-reference/feature-gates/#StatefulSetRecreateStrategy) 기능 게이트를 활성화해야 합니다. 더 많은 정보는 기능 게이트 활성화 또는 비활성화(/docs/tasks/administer-cluster/configure-feature-gates/)를 참고해요. Recreate 업데이트 전략은 StatefulSet의 모든 파드를 삭제한 후 StatefulSet의
.spec.template에 대한 수정을 반영하는 새 파드를 만들어요. 이 전략을 사용하려면 StatefulSetRecreateStrategy 기능 게이트(/docs/reference/command-line-tools-reference/feature-gates/#StatefulSetRecreateStrategy)를 활성화해야 해요. 자세한 내용은 Recreate를 참고해요.
롤링 업데이트 (#rolling-updates)
StatefulSet의 .spec.updateStrategy.type이 RollingUpdate로 설정되면 StatefulSet 컨트롤러가 StatefulSet의 각 파드를 삭제하고 다시 만들어요. 파드 종료와 같은 순서(가장 큰 서수에서 가장 작은 서수로)로 진행하며 각 파드를 한 번에 하나씩 업데이트해요.
Kubernetes 컨트롤 플레인은 업데이트된 파드가 Running 및 Ready가 될 때까지 기다렸다가 그 선행 파드를 업데이트해요. .spec.minReadySeconds(최소 준비 초(#minimum-ready-seconds) 참고)를 설정했다면 컨트롤 플레인은 파드가 준비된 후 그 시간만큼 더 기다린 다음 진행해요.
분할 롤링 업데이트 (#partitions)
.spec.updateStrategy.rollingUpdate.partition을 지정해 RollingUpdate 업데이트 전략을 분할할 수 있어요. partition이 지정되면 서수가 partition보다 크거나 같은 모든 파드가 StatefulSet의 .spec.template이 업데이트될 때 업데이트돼요. 서수가 partition보다 작은 모든 파드는 업데이트되지 않고, 삭제되더라도 이전 버전으로 다시 생성돼요. StatefulSet의 .spec.updateStrategy.rollingUpdate.partition이 .spec.replicas보다 크면 .spec.template에 대한 업데이트가 파드에 전파되지 않아요.
대부분의 경우 partition을 사용할 필요가 없지만, 업데이트를 스테이징하거나 카나리를 롤아웃하거나 단계적 롤아웃을 수행하려면 유용해요.
최대 사용 불가 파드 (#maximum-unavailable-pods)
.spec.updateStrategy.rollingUpdate.maxUnavailable 필드를 지정해 업데이트 중 사용 불가할 수 있는 최대 파드 수를 제어할 수 있어요. 값은 절대 숫자(예: 5) 또는 원하는 파드의 백분율(예: 10%)일 수 있어요. 절대 숫자는 백분율 값에서 올림하여 계산돼요. 이 필드는 0일 수 없어요. 기본 설정은 1이에요.
이 필드는 0에서 replicas - 1 범위의 모든 파드에 적용돼요. 0에서 replicas - 1 범위에 사용 불가한 파드가 있으면 maxUnavailable에 계산돼요.
파드가 있는 그대로의 상태에서 사용 불가인지 여부(예: 이미 스케일 다운된 경우)와 관계없이 0에서 replicas - 1 범위의 모든 파드가 이 필드에 의해 고려된다는 점을 유의해요.
강제 롤백 (#forced-rollback)
기본 Pod 관리 정책(OrderedReady)으로 롤링 업데이트를 사용할 때 수동 개입이 필요한 깨진 상태에 빠질 수 있어요.
파드 템플릿을 결코 Running 및 Ready가 되지 않는 구성으로 업데이트하면(예: 잘못된 바이너리나 애플리케이션 수준 구성 오류로 인해) StatefulSet이 롤아웃을 중지하고 기다려요.
이 상태에서는 파드 템플릿을 올바른 구성으로 되돌리는 것만으로는 충분하지 않아요. 알려진 이슈(https://github.com/kubernetes/kubernetes/issues/67250) 때문에 StatefulSet은 작업 구성으로 되돌리려고 시도하기 전에 깨진 파드가 Ready가 될 때까지(결코 일어나지 않음) 계속 기다릴 거예요.
템플릿을 되돌린 후에는 StatefulSet이 이미 잘못된 구성으로 실행하려고 시도한 모든 파드도 삭제해야 해요. 그러면 StatefulSet이 되돌린 템플릿을 사용해 파드를 다시 생성하기 시작할 거예요.
Recreate (#recreate)
StatefulSet의 .spec.updateStrategy.type이 Recreate로 설정되면 StatefulSet 컨트롤러가 StatefulSet의 모든 파드를 한 번에 삭제하고, 업데이트된 .spec.template에서 새 파드를 만들기 전에 완전히 종료될 때까지 기다려요. RollingUpdate와 달리 파드의 이전 버전과 새 버전은 결코 동시에 실행되지 않으므로 이 전략은 업데이트 기간 동안 다운타임을 발생시켜요. 이것은 Deployment의 Recreate 전략을 반영하며, 공유 리소스에 대한 독점 접근을 요구하거나 버전 간 호환되지 않는 디스크 형식을 사용하는 워크로드처럼 두 버전을 동시에 실행할 수 없는 애플리케이션에 유용해요.
삭제는 Pod 관리 정책과 관계없이 항상 모든 파드를 함께 제거해요. 모든 파드가 종료되면 그 정책에 따라 새 파드가 생성돼요: OrderedReady(기본값)에서는 파드가 오름차순 서수 순서로 한 번에 하나씩 다시 생성되며 각 파드가 Running 및 Ready가 될 때까지 기다린 후 다음을 만들어요; Parallel에서는 모든 파드가 한 번에 다시 생성돼요.
이것은 알파 기능이므로 이 전략을 사용하려면 kube-controller-manager와 kube-apiserver에서 StatefulSetRecreateStrategy 기능 게이트(/docs/reference/command-line-tools-reference/feature-gates/#StatefulSetRecreateStrategy)를 활성화해야 해요.
개정 이력 (Revision history)
ControllerRevision은 StatefulSet 컨트롤러 같은 컨트롤러가 역사적 구성 변경을 추적하는 데 사용하는 Kubernetes API 리소스예요.
StatefulSet은 ControllerRevision을 사용해 개정 이력을 유지하며, 롤백과 버전 추적을 가능하게 해요.
StatefulSet이 ControllerRevision으로 변경을 추적하는 방식 (#how-statefulsets-track-changes-using-controllerrevisions)
StatefulSet의 Pod 템플릿(spec.template)을 업데이트하면 StatefulSet 컨트롤러는:
- 새 ControllerRevision 객체를 준비하고,
- Pod 템플릿과 메타데이터의 스냅샷을 저장하고,
- 증분 개정 번호를 할당해요.
핵심 속성 (#key-properties)
핵심 속성과 다른 세부 사항은 ControllerRevision에서 더 배우세요.
개정 이력 관리 (#managing-revision-history)
.spec.revisionHistoryLimit로 보존된 개정을 제어해요:
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: webapp
spec:
revisionHistoryLimit: 5 # Keep last 5 revisions
# ... other spec fields ...
- 기본값: 지정되지 않으면 10개 개정 보존
- 정리 (Cleanup): 한도를 초과하면 가장 오래된 개정이 가비지 컬렉션됨
롤백 수행 (#performing-rollbacks)
다음을 사용해 이전 구성으로 되돌릴 수 있어요:
# View revision history
kubectl rollout history statefulset/webapp
# Rollback to a specific revision
kubectl rollout undo statefulset/webapp --to-revision=3
이것은:
- 개정 3의 Pod 템플릿을 적용하고,
- 업데이트된 개정 번호로 새 ControllerRevision을 만들어요.
ControllerRevision 검사 (#inspecting-controllerrevisions)
관련 ControllerRevision을 보려면:
# List all revisions for the StatefulSet
kubectl get controllerrevisions -l app.kubernetes.io/name=webapp
# View detailed configuration of a specific revision
kubectl get controllerrevision/webapp-3 -o yaml
모범 사례 (#best-practices)
- 대부분의 워크로드에 대해
revisionHistoryLimit을 5–10으로 설정해요. - 깊은 롤백 이력이 필요할 때만 늘려요.
- 정기적으로 개정을 확인해요.
- 개정 수의 급속한 성장에 대해 알림을 설정해요.
- ControllerRevision 객체에 대한 수동 편집.
- 개정을 백업 메커니즘으로 사용(실제 백업 도구 사용).
revisionHistoryLimit: 0설정(롤백 기능 비활성화).
PersistentVolumeClaim 보존 (PersistentVolumeClaim retention)
선택적 .spec.persistentVolumeClaimRetentionPolicy 필드는 StatefulSet의 수명 주기 동안 PVC가 삭제되는지와 방법을 제어해요. 이 필드를 사용하려면 API 서버와 컨트롤러 매니저에서 StatefulSetAutoDeletePVC 기능 게이트(/docs/reference/command-line-tools-reference/feature-gates/)를 활성화해야 해요.
활성화되면 각 StatefulSet에 대해 구성할 수 있는 두 가지 정책이 있어요:
- whenDeleted: StatefulSet이 삭제될 때 적용되는 볼륨 보존 동작을 구성해요.
- whenScaled: StatefulSet의 복제본 수가 줄어들 때, 예를 들어 집합을 축소할 때 적용되는 볼륨 보존 동작을 구성해요.
구성할 수 있는 각 정책에 대해 값을 Delete 또는 Retain으로 설정할 수 있어요.
- Delete: StatefulSet volumeClaimTemplate에서 생성된 PVC가 정책의 영향을 받는 각 파드에 대해 삭제돼요. whenDeleted 정책으로 모든 volumeClaimTemplate의 PVC가 그 파드가 삭제된 후 삭제돼요. whenScaled 정책으로 축소되는 파드 복제본에 해당하는 PVC만 그 파드가 삭제된 후 삭제돼요.
- Retain (기본값): volumeClaimTemplate의 PVC는 그 파드가 삭제될 때 영향을 받지 않아요. 이것은 이 새 기능 이전의 동작이에요.
이러한 정책은 파드가 StatefulSet의 삭제나 축소로 인해 제거될 때만 적용된다는 점을 명심하세요. 예를 들어 StatefulSet과 연관된 파드가 노드 실패로 인해 실패하고 컨트롤 플레인이 대체 파드를 만들면 StatefulSet은 기존 PVC를 유지해요. 기존 볼륨은 영향을 받지 않으며 클러스터는 그것을 새 파드가 시작될 노드에 연결할 거예요.
정책의 기본값은 Retain이며, 이 새 기능 이전의 StatefulSet 동작과 일치해요.
다음은 정책 예시예요:
apiVersion: apps/v1
kind: StatefulSet
...
spec:
persistentVolumeClaimRetentionPolicy:
whenDeleted: Retain
whenScaled: Delete
...
StatefulSet 컨트롤러는 그 PVC에 소유자 참조를 추가하며, 이것은 파드가 종료된 후 가비지 컬렉터가 삭제해요. 이것은 파드가 PVC가 삭제되기 전에(그리고 보존 정책에 따라 백킹 PV와 볼륨이 삭제되기 전에) 모든 볼륨을 깨끗하게 언마운트할 수 있게 해줘요. whenDeleted 정책을 Delete로 설정하면 그 StatefulSet과 연관된 모든 PVC에 StatefulSet 인스턴스에 대한 소유자 참조가 배치돼요.
whenScaled 정책은 파드가 축소될 때만 PVC를 삭제해야 하며, 다른 이유로 파드가 삭제될 때는 안 돼요. 조정(reconciling)할 때 StatefulSet 컨트롤러는 원하는 복제본 수를 클러스터에 실제로 존재하는 파드와 비교해요. id가 복제본 수보다 큰 StatefulSet 파드는 폐기(condemned)되고 삭제 표시되요. whenScaled 정책이 Delete이면 폐기된 파드가 삭제되기 전에 먼저 연관된 StatefulSet 템플릿 PVC의 소유자로 설정돼요. 이것은 폐기된 파드가 종료된 후에만 PVC가 가비지 컬렉션되게 해요.
이것은 컨트롤러가 크래시하고 재시작되면 소유자 참조가 정책에 따라 적절하게 업데이트되기 전에는 어떤 파드도 삭제되지 않는다는 뜻이에요. 폐기된 파드가 컨트롤러가 다운된 동안 강제 삭제되면 소유자 참조는 컨트롤러가 크래시한 시점에 따라 설정되었을 수도 있고 아닐 수도 있어요. 소유자 참조를 업데이트하는 데 여러 조정 루프가 걸릴 수 있으므로 일부 폐기된 파드는 소유자 참조를 설정했고 다른 것은 그렇지 않을 수 있어요. 이런 이유로 컨트롤러가 다시 올라올 때까지 기다리는 것을 권장하며, 그러면 파드를 종료하기 전에 소유자 참조를 검증할 거예요. 그것이 불가능하면 운영자가 PVC의 소유자 참조를 검증해 파드를 강제 삭제할 때 예상 객체가 삭제되도록 해야 해요.
복제본 (#replicas)
.spec.replicas는 원하는 파드 수를 지정하는 선택적 필드예요. 기본값은 1이에요.
kubectl scale statefulset statefulset --replicas=X로 StatefulSet을 수동으로 확장한 다음 매니페스트를 기반으로(예: kubectl apply -f statefulset.yaml 실행으로) StatefulSet을 업데이트하면 그 매니페스트를 적용하는 것이 이전에 한 수동 확장을 덮어써요.
HorizontalPodAutoscaler(또는 수평 확장을 위한 유사한 API)가 StatefulSet의 확장을 관리한다면 .spec.replicas를 설정하지 마세요. 대신 Kubernetes 컨트롤 플레인이 .spec.replicas 필드를 자동으로 관리하게 하세요.
다음 단계 (What's next)
- Pods에 대해 배우기.
- StatefulSet 사용 방법 알아보기: 유상태 애플리케이션 배포 예시를 따라하기. Stateful Set으로 Cassandra 배포 예시를 따라하기. 복제된 유상태 애플리케이션 실행 예시를 따라하기. StatefulSet 확장 배우기. StatefulSet 삭제에 관련된 것 배우기. 파드가 볼륨을 스토리지에 사용하도록 구성 배우기. 파드가 PersistentVolume을 스토리지에 사용하도록 구성 배우기.
- StatefulSet은 Kubernetes REST API의 최상위 리소스예요. 유상태 집합에 대한 API를 이해하려면 StatefulSet 객체 정의를 읽어요.
- PodDisruptionBudget과 그것을 사용해 중단 중 애플리케이션 가용성을 관리하는 방법 읽기.