StatefulSet란?
스테이트풀셋은 애플리케이션의 스테이트풀을 관리하는데 사용하는 워크로드 API 오브젝트이다. 파드 집합의 디플로이먼트와 스케일링을 관리하며, 파드들의 순서 및 고유성을 보장한다 .
deployment와 비슷한 기능을 하고 있다. 그래서 deployment와 항상 비교된다.
deployment와 차이점
StatefuleSet의 내부 pod들은 각자 역할이 다르고, 그 pod들을 따로 관리한다. 이를 통해서 어플리케션 자체의 State를 보장하면서 앱의 생성, 배포, 스케일링기능을 지원한다. Deployment는 앱이 Stateless하다는 전제 아래에서 앱을 관리(생성, 배포, 스케일링)하기 때문에, PV 연결 되었어도 앱을 생성하거나 스케일링하는 과정에서 오류가 발생할 수 있다.
그래서 pv와 pvc생성하여 관리하고자 하면 statefulset을 쓰는 것을 더 권유한다.
StatefulSet의 특징
- 내부 pod 마다 각각 pvc, pv를 생성하여 관리
- 내부 pod 마다 고유한 pvc를 갖도록 설정이 가능하며, 스케일 확장에 용이하다.
- Deployment + pvc + pv 로 앱을 배포할 때는 확장이 어렵다. 이미 정해진 pod에 볼륨이 묶여있는 상태에서 pod의 수를 증가시키면, 이미 해당 볼륨이 사용되고 있다는 에러가 발생한다. (https://akomljen.com/kubernetes-persistent-volumes-with-deployment-and-statefulset/)
- 예를 들어 mynginx란 이름의 pod를 정의하면 생성 시 mynginx-0, mynginx-1, mynginx-2...식으로 이름이 부여된다.
- 내부 pod 마다 개별적으로 네트워크 식별 및 접근
- StatefulSet의 내부 pod은 구분된다. headless service를 통해서 원하는 pod만 식별하여 접근하는 기능을 제공한다.
- 내부 pod들의 배치 순서 존재
-
- pod들간의 의존관계가 존재하는 경우, 주어진 순서로 pod들을 실행할 수 있다.
- pod들간의 의존관계가 존재하는 경우, 주어진 순서로 pod들을 실행할 수 있다.
- pod들간의 의존관계가 존재하는 경우, 주어진 순서로 pod들을 실행할 수 있다.
-
Headless
statefulSet을 구성하기 위해서는 Headless 서비스를 필수적으로 사용해야 한다. 왜냐하면 기존의 rs나 ds같은 경우 Pod가 삭제되면, 셋팅된 이미지를 받아서 Pod하나 만들어 준다.
그러나 Statefulset은 Database같은 mutable 어플리케이션이기에 아무 Pod만 만들어서는 안된다. 또한, 정확히 기존에 사용하던 그 Pod가 다시 만들어져야 한다. 그렇게 하기 위해서 Headless가 부여하는 Pod의 고유성을 이용하게 된다.
실습하기
1) Headless service 만들기
// **mysql-headless-service.yaml**
apiVersion: v1
kind: Service
metadata:
name: mysql
spec:
clusterIP: None
selector:
app: mysql
ports:
- port: 3306
name: mysql
StatefulSet에서 Pod의 네트워크 ID를 관리하려면 헤드리스 서비스가 필요하다. 그러므로 mysql-headless-service.yaml을 만든다.
kubectl apply -f mysql-headless-service.yaml
2) ConfigMap 생성하기
특정 구성 요구 사항이 있는 경우 ConfigMap을 생성한다. 이 단계는 선택 사항이다. 나의 경우에는 mysql을 가지고 statefulset을 만듦으로, mysql에 필요한 환경을 여기에 셋팅해준다. configmap이 필요없다면 생성하지 않아도 된다.
apiVersion: v1
kind: ConfigMap
metadata:
name: mysql
data:
mysql_database.txt: "test"
kubectl apply -f mysql-configmap.yaml
3) sercet 만들기
3-1) yaml 파일로 생성한 경우
apiVersion: v1
kind: Secret
metadata:
name: mysql-secret
type: Opaque
data:
# The value should be base64 encoded
MYSQL_ROOT_PASSWORD: bXktc2VjcmV0LXB3 # "my-secret-pw" base64 encoded
이건 configmap과 같이 생성안해도 상관없는 파일이다. mysql에 대한 password를 해당 파일에 넣어 statefulset을 생성했을 때 연결할 수 있다.
kubectl apply -f mysql-secret.yaml
3-2) command로 생성한 경우
kubectl create secret generic mysql-secret \\
--from-literal=MYSQL_ROOT_PASSWORD=your_root_password \\
--from-literal=MYSQL_USER=your_user \\
--from-literal=MYSQL_PASSWORD=your_mysql_password
위와 같이 mysql 셋팅에 필요한 값들을 위에서 configmap에서 같이 생성해주고, root_password나 user값들을 숨겨야 함으로 이를 secret에 작성하여 생성해준다.
kubectl get secret your-secret-name -o yaml
위와 같은 command로 생성했을 경우 따로 yaml파일이 존재하지않는다. 그러므로 yaml파일을 보고 싶다면 위와 같은 command로 작성하면 확인이 가능하다. 아래가 그 예시이다.
apiVersion: v1
data:
MYSQL_PASSWORD: dWhlZWtpbmcxMg==
MYSQL_ROOT_PASSWORD: bXlyb290
MYSQL_USER: dWhlZWtpbmc=
kind: Secret
metadata:
creationTimestamp: "2024-05-22T00:33:07Z"
name: mysql-secret
namespace: default
resourceVersion: "57322"
uid: 0854bfeb-ad61-4c6c-a38a-25eb10486177
type: Opaque
위와 같이 yaml파일이 확인했을 때 암호화된 data를 확인할 수 있다. 내가 작성한 것이 맞게 생성되었는지 확인할려면 아래와 같이 작성할 수 있다.
echo 'bXlyb290' | base64 --decode # should output your root password
echo 'dWhlZWtpbmc=' | base64 --decode # should output your user
echo 'dWhlZWtpbmcxMg==' | base64 --decode # should output your user password
4) StatefulSet 만들기
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql
spec:
serviceName: "mysql"
replicas: 3
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:5.7
ports:
- containerPort: 3306
name: mysql
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: MYSQL_ROOT_PASSWORD
volumeMounts:
- name: mysql-persistent-storage
mountPath: /var/lib/mysql
volumes:
- name: mysql-config-volume
configMap:
name: mysql-config
items:
- key: my.cnf
path: my.cnf
volumeClaimTemplates:
- metadata:
name: mysql-persistent-storage
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 2Gi
mysql-statefulset.yaml를 위의 내용으로 만든다.
kubectl apply -f statefulset.yaml
그러면 replica를 세 개로 지정해서 2G인 mysql 파드가 세개 생긴 것을 확인할 수 있다.
👇🏻 참고 사이트
https://velog.io/@curiosity806/kubernetes-Persistent-Volumes-Deployment와-StatefulSet의-차이점
https://kubernetes.io/ko/docs/concepts/workloads/controllers/statefulset/
https://velog.io/@repush/Statefulset
https://www.anyflow.net/sw-engineer/kubernetes-statefulset-volume-pv-pvc-storageclass