Search

Statefulset

공식문서에서는 애플리케이션의 스테이트풀을 관리하는데 사용하는 워크로드 API 오프젝트라고 소개한다.
즉, 상태를 안정적으로 관리할 수 있는 리소스라는 것이다.
스테이트 풀셋은 다음과 같은 요구 사항이 필요한 어플리케이션에 적합하다고 한다.
안정적이고 고유한 네트워크 식별자가 필요한 경우
안정적이고 지속적으로 유지가 필요한 스토리지가 필요한 경우
순차적인, 정상 배포(graceful deployment)와 스케일링이 필요한 경우
순차적인 자동 롤링 업데이트가 필요한 경우
구체적인 사례와 연관지어서 생각을 해보면 스테이트풀셋이 적합한 어플리케이션으로는 데이터베이스가 있다.
데이터 베이스는 영구적으로 데이터의 상태를 저장하는 스토리지 공간이 필요하고 이 공간은 안정적이고 지속적으로 운영이 되어야한다는 특징이 있다. 또한 테이터 베이스를 복제셋이나 클러스터로 운영하기 위해서는 각자를 식별할 수 있어야한다. 스테이트풀셋을 이런 요구사항에 적합한 쿠버네티스의 리소스이다.

StatefulSet과 Deployment의 차이

1. 영구적인 스토리지 사용
우선 스테이트 풀셋은 영구적인 스토리지(pvc)를 각 pod 마다 할당하여 사용해야한다.
이에 반해 디플로이먼트는 영구적인 스토리지를 선택적으로 사용할 수 있고 사용을 하더라도 모든 pod와 공유하는 공유 스토리지로 사용한다.
2. pod를 지속적으로 식별할 수 있는지 여부
스테이트풀셋은 pod를 생성할 때, 그 식별자(name)을 일관성있는 규칙을 가지고 생성한다.
예를 들어서 web이라는 스테이트 풀셋있다면 그 스테이트풀셋의 pod의 식별자(name)은 web-0, web-1, ... , web-n 까지 순차적으로 생성된다. 때문에 지속적으로 각 pod를 식별할 수 있는 예측가능한 식별자를 가질 수 있다. 이에 반해 디플로이먼트는 랜덤한 식별자를 생성한다.
3. 순차적인 삭제 및 갱신
스테이트풀셋을 갱신하거나 삭제할 때, 그 순서가 정해져있다. 이에 반해 디플로이먼트는 삭제 및 갱신 작업을 수행할 때, 설정된 전략에 따라서 무작위의 pod를 대상으로 삭제 및 갱신 작업을 수행하게 된다.
Headless Service
StatefulSet 은 각 Pod의 역할이 다르기 때문에 외부에서 Deployment 처럼 random으로 pod를 선택하는것이 아니라, 특정 Pod와 직접 통신해야 하는 경우가 많다. Pod의 IP는 생성시마다 달라지는데 이를 매번 찾아서 접속할수 없기 때문에, 이럴 경우 Headless Service를 사용한다. Headless Service를 사용하면 Service를 통해 수행되던 로드밸런싱이나 proxy를 하지 않고 Pod마다 고정된 DNS를 생성할 수 있다.
생성 방법은 Service yaml에 spec.clusterIP를 None 으로 정의하면 된다.
Headless Service로 묶인 Pod들은 각각 아래와 같은 고정된 DNS을 가진다.
[pod-name].[svc].[namespace].svc.cluster.local
사실 Headless Service가 없더라도 Pod는 기본적으로 아래와 같은 DNS를 가진다. 다만 DNS에 pod ip주소가 포함되기 때문에 사실상 고정된 DNS가 아니므로 활용이 어렵다. 반면에 Headless Service를 사용하면 pod의 DNS에 ip주소 대신 pod이름을 사용하고, StatefulSet은 고정된 pod 이름을 가지므로 사실상 pod의 DNS는 고정된다고 볼수 있다.
[pod-ip-address].[namespace].pod.cluster.local
apiVersion: v1 kind: Service metadata: name: nginx labels: app: nginx spec: ports: - port: 80 name: web clusterIP: None # Headless 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: nginx:latest # 올바른 아키텍처의 이미지 사용 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
YAML
복사
nginx의 headless-service가 있고 headless-service의 특성상 Pod의 endpoint로 DNS가 생성됨
web의 이름을 가진 3개의 nginx container가 특정 Pod에서 띄워진다는 의미
volumeClaimTemplates를 통해 각 파드에 PVC를 생성하는 템플릿