평소에 말로만 듣던 가시다님의 쿠버네티스 스터디를 운 좋게 참여하게 되었다.
마침 사내에서 DB를 컨테이너화를 고려하기도 했었고, 평소 오퍼레이터에 관심을 가지어 더욱 더 기대가 되었다.
이번 포스팅에는 1주차 스터디를 진행하면서 평소에 애매하게 알고만 있었던 스테이트풀셋을 정리해본다.
Stateful vs Stateless
위 사진은 Stateful과 Stateless한 파드를 표현한 너무나도 유명한 그림이다.
우리가 애완동물에 기르면서 이름(고유한 식별자)를 붙이고, 가축과 같은 경우에는 굳이 이름을 붙이지 않는다.
즉, State의 유뮤는 사용하는 목적에 맞게 고유한 식별자를 부여하여 상태를 유지하거나, 또는 상태를 저장하지 않는 것이다.
( 일반적으로 웹서버와 같은 경우 stateless, 데이터베이스의 경우 stateful 하다고 말할 수 있다 )
이러한 개념을 도입하여 워크로드로 만든 것이 바로 쿠버네티스의 Statefulset과, Deployment이다.
그렇다면 쿠버네티스 상에서, 평소에 많이 사용하는 Deployment와 차이점이 무엇인지 알아보자.
스테이트풀셋(Statefulset)
스테이트풀셋이 무엇인지 gpt에게 물어보았다.
글 만 보았을 때는 감이 잘 오지 않는다. 일단, 실습을 위해 nginx 이미지의 Statefulset를 배포해보자
# web.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
serviceName: "nginx"
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: registry.k8s.io/nginx-slim:0.8
ports:
- containerPort: 80
name: web
# 스테이트풀셋 배포
kubectl apply -f web.yaml
랜덤 한 UID의 파드 이름이 아닌 고유한 이름의 파드가 생기는 것을 볼 수 있다.
더 자세히 스테이트 풀셋에 대해 알아보자.
스케줄링
스테이트 풀셋은 디플로이먼트와 다르게 파드를 스케일 하거나, 롤링 업데이트 등을 할 때 스케줄링의 순서가 있는 걸로 보인다.
스테이트 풀셋의 레플리카 수 증가 시, 순차적으로 배포가 되는 것을 볼 수 있다.
kubectl scale sts web --replicas=5 && kubectl get pods -w -l app=nginx
statefulset.apps/web scaled
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 3m42s
web-1 1/1 Running 0 3m39s
web-2 0/1 Pending 0 0s
web-2 0/1 ContainerCreating 0 0s
web-2 0/1 ContainerCreating 0 1s
web-2 1/1 Running 0 3s
web-3 0/1 Pending 0 0s
web-3 0/1 Pending 0 0s
web-3 0/1 ContainerCreating 0 0s
web-3 0/1 ContainerCreating 0 1s
web-3 1/1 Running 0 2s
web-4 0/1 Pending 0 0s
web-4 0/1 Pending 0 0s
web-4 0/1 ContainerCreating 0 0s
web-4 0/1 ContainerCreating 0 1s
web-4 1/1 Running 0 3s
다음은 레플리카 수를 감소할 시, 역순으로 감소가 되는 걸 보여준다.
kubectl patch sts web -p '{"spec":{"replicas":2}}' && kubectl get pods -w -l app=nginx
statefulset.apps/web patched
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 4m51s
web-1 1/1 Running 0 4m48s
web-2 1/1 Running 0 69s
web-3 1/1 Running 0 66s
web-4 1/1 Terminating 0 64s
web-4 1/1 Terminating 0 66s
web-4 0/1 Terminating 0 67s
web-4 0/1 Terminating 0 68s
web-4 0/1 Terminating 0 68s
web-3 1/1 Terminating 0 70s
web-3 1/1 Terminating 0 71s
web-3 0/1 Terminating 0 73s
web-3 0/1 Terminating 0 73s
web-3 0/1 Terminating 0 73s
web-2 1/1 Terminating 0 76s
web-2 1/1 Terminating 0 77s
web-2 0/1 Terminating 0 79s
web-2 0/1 Terminating 0 79s
web-2 0/1 Terminating 0 79s
스테이트 풀셋은 아래와 같은 순서를 보여준다.
생성(배포 시) -> 순차
업데이트, 종료 -> 역순
보통 데이터베이스나, 클러스터링 되어있는 미들웨어들은 순서마다 역할이 있는 경우가 많다.(ex: 1번: primary, replicas..)
그런 경우에 순서를 보장해 주는 스테이트 풀셋을 사용하기 적합하다고 생각한다.
추가적으로 특정 순서라던지, 중요한 순서를 보장해야 하는 예외경우가 있다면 OnDelete 배포 전략을 사용해 보자.
스테이트풀셋은 디플로이먼트와 마찬가지로 기본적으로 RollingUpdate 배포 전략을 가지지만 추가적으로 OnDelete 배포전략을 지원한다.
OnDelete 배포전략은 이름에서 오는 의미와 같이 수동으로 파드를 삭제해 주어야 업데이트가 수행된다.
즉, kubectl rollout restart 명령어를 입력하여도 아무런 반응이 없을 것이다. 직접 업데이트할 파드를 수동으로 삭제해주어야 한다.
예시 매니페스트 파일이다.
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: example-statefulset
spec:
serviceName: "example"
replicas: 3
selector:
matchLabels:
app: example
template:
metadata:
labels:
app: example
spec:
containers:
- name: nginx
image: nginx
updateStrategy: # 배포전략
type: OnDelete # OnDelete / RollingUpdate
볼륨(PV, PVC)
다음은 볼륨이다. 먼저 스테이트풀셋에 PVC를 배포해 보자
(※ default 스토리지 클래스가 있기 때문에 위 매니페스트 파일에는 스토리지 클래스가 생략이 되어 있음,)
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
serviceName: "nginx"
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: registry.k8s.io/nginx-slim:0.8
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: www
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 1Gi
스테이트풀셋의 파드 개수만큼 PVC가 생성되었으며 metadata.name + '파드 이름'의 규칙으로 이름이 생성된다.
그럼 디플로이먼트에서도 PVC를 사용할 수 있을까?
정답은 사용할 수 있다. 하지만 여러 가지 제약사항이 있다.
volumeClaimTemplates 필드는 스테이트풀셋에서만 사용할 수 있는 옵션으로 Deployment의 경우에는 미리 PVC를 만들고
아래와 같은 볼륨옵션으로 연결해야 한다.
volumes:
- name: my-pvc
persistentVolumeClaim:
claimName: my-pvc
또한 하나의 PVC를 디플로이먼트의 여러 파드들의 공유해서 사용하기 때문에 PVC의 경우 ReadWriteOnce 정책일 경우 사용이 제약이 생기고, 공유하면서 사용하는 여러 가지 이슈가 많을 것으로 보인다.
( 정신 건강을 위해서 stateful 한 애플리케이션의 경우 스테이트풀셋을 사용하자..)
여담이지만, 예전에 프로젝트를 진행하면서 우리는 디플로이먼트만 사용한다는 레거시한 고객사의 무리한 요구로..
스테이트풀셋의 헬름차트 미들웨어를 디플로이먼트로 올려본 경험이 있었는데... 지옥을 맛봤다.
오토힐링(Autohealing)
스테이트풀셋은 디플로이먼트의 레플리카셋과 달리, 파드가 에러 상태일 경우에, 자동으로 재시작되는 오토힐링 기능이 지원되지 않고, 직접 사용자가 수동으로 파드를 재시작해주어야 한다.
이는 데이터베이스 등과 같이 데이터의 무결성이 중요하거나 중요한 시스템에서 신중한 운영이 필요한 경우 관리자의 개입이 필요하기 때문이다.
따라서, 오토힐링이 필요한 스테이트풀셋의 경우에는 Liveness Probe 정책 등을 설정해주어야 한다
'Kubernetes > Database Operator' 카테고리의 다른 글
Kafka Operator(Strimzi) - DOIK2_5주차 (0) | 2023.11.19 |
---|---|
MongoDB Operator - Percona Operator for MongoDB(PSMDB) - DOIK 4주차 (3) | 2023.11.12 |
PostgreSQL Operator - CloudNative PostgreSQL - DOIK2_3주차 (0) | 2023.11.05 |
쿠버네티스 MySQL InnoDB Cluster - DOIK2_2주차 2 (2) | 2023.10.28 |
쿠버네티스 오퍼레이터란? (Kubernetes Operator) - DOIK_2주차 1 (2) | 2023.10.28 |