본문 바로가기
프로그래밍

[kubernetes] 스테이트풀셋(Statefulset)

by choihyuunmin 2024. 7. 10.

안녕하세요. 이번 포스팅에서는 쿠버네티스의 스테이트풀셋(StatefulSet)에 대해 알아보겠습니다.

 

1) 스테이트풀셋

스테이트풀셋은 쿠버네티스 클러스터의 파드들을 관리하고 생성하는 데 사용하는 워크로드입니다.

여기서 워크로드란, 쿠버네티스 클러스터 상에서 구동되는 어플리케이션을 의미합니다. 앞서 포스팅 했던 쿠버네티스 기본의 디플로이먼트(Deployment)와 비슷한 기능을 하지만, 차이점은 스테이트풀셋은 이름에서 볼 수 있듯이 stateful한 상태를 유지합니다. 즉, 클러스터의 파드들이 독자적으로 생성되어 상태를 유지하게 됩니다. 파드들이 영구적인 식별자를 가지게 되어 동일한 스펙으로 새로운 파드가 생성되어도 기존에 있는 파드를 교체할 수는 없습니다.

그럼에도 스테이트풀셋을 사용하는 이유는 안정적인 서비스 제공, 스토리지 이용의 이점, 원활한 배포와 스케일링 등이 있습니다.

 

스테이트풀셋을 이용하기 위해 헤드리스(headless) 서비스를 먼저 생성해보겠습니다. 헤드리스 서비스는 파드들의 개별 네트워크를 식별하기 위해 사용합니다.

 

헤드리스 서비스를 위한 매니페스트를 작성하겠습니다.

apiVersion: v1
kind: Service
metadata:
  name: statefulset-service
spec:
  selector:
    app.kubernetes.io/name: statefulset-web1
  type: ClusterIP
  clusterIP: None
  ports:
    - protocol: TCP
      port: 80

 

작성할 때 ClusterIP 부분을 None으로 작성해줍니다. 헤드리스 서비스는 Cluster ip가 없는 것이 특징입니다.

메타데이터의 이름을 지정해주고, selector에는 추후에 생성할 스테이트풀셋의 이름을 미리 지정해서 넣어줍니다.

 

> kubectl apply -f service-statefulset.yaml
service/statefulset-service created

 

생성한 파일을 apply 하고 서비스 상태를 확인해보면 아래와 같이 CLUSTER-IP의 상태가 None인 것을 확인할 수 있습니다.

> kubectl get svc
NAME                  TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes            ClusterIP   10.233.0.1   <none>        443/TCP   17d
statefulset-service   ClusterIP   None         <none>        80/TCP    57s

 

다음으로 실제 스테이트풀셋을 생성해보겠습니다.

 

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: statefulset-work1
spec:
  replicas: 3
  selector:
    matchLabels:
      app.kubernetes.io/name: statefulset-web1
  serviceName: statefulset-service
  template:
    metadata:
      labels:
        app.kubernetes.io/name: statefulset-web1
    spec:
      containers:
      - name: nginx
        image: nginx:latest

 

여기서 주의할 점은 matchLabels와 metadata의 labels에 설정한 스테이트풀셋 이름과 위에서 설정한 헤드리스 서비스의 selector 이름이 같아야합니다. 그리고 serviceName에도 마찬가지로 위에서 생성한 헤드리스 서비스의 이름을 넣어줍니다.

 

스테이트풀셋을 실행시키고 상태를 확인해보겠습니다.

> kubectl apply -f statefulset-web.yaml
statefulset.apps/statefulset-work1 created

 

> kubectl get pod -o wide
NAME                  READY   STATUS    RESTARTS   AGE   IP               NODE        NOMINATED NODE   READINESS GATES
statefulset-work1-0   1/1     Running   0          26s   10.233.104.254   ubun20-01   <none>           <none>
statefulset-work1-1   1/1     Running   0          23s   10.233.109.186   ubun20-02   <none>           <none>
statefulset-work1-2   1/1     Running   0          20s   10.233.70.11     ubun20-03   <none>           <none>

 

> kubectl get statefulset -o wide
NAME                READY   AGE    CONTAINERS   IMAGES
statefulset-work1   3/3     115s   nginx        nginx:latest

 

스테이트풀셋에 대한 정보는 kubectl get statefulset 명령어를 통해 볼 수 있습니다.

pod의 상태를 보면 0, 1, 2의 순으로 pod가 생성된 것을 볼 수 있는데, 만약 스테이트풀셋 생성에 사용된 yaml 파일을 수정해서 스테이트풀셋을 수정한다면 가장 나중에 생성된 pod부터 영향을 받습니다. 한번 확인해보겠습니다.

 

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: statefulset-work1
spec:
  replicas: 2
  selector:
    matchLabels:
      app.kubernetes.io/name: statefulset-web1
  serviceName: statefulset-service
  template:
    metadata:
      labels:
        app.kubernetes.io/name: statefulset-web1
    spec:
      containers:
      - name: nginx
        image: nginx:latest

 

위에서 생성했던 매니페스트를 복사해서 statefulset-web2.yaml 파일을 만들었습니다. 이제 이 파일을 apply시켜 새로운 스테이트풀셋을 실행시켜보겠습니다.

 

> kubectl apply -f statefulset-web2.yaml
statefulset.apps/statefulset-work1 configured

 

같은 이름의 스테이트풀셋을 실행시키니 created가 아닌 configured 라는 안내를 반환합니다.

pod를 확인해보겠습니다.

 

> kubectl get pod -o wide
NAME                  READY   STATUS    RESTARTS   AGE    IP               NODE        NOMINATED NODE   READINESS GATES
statefulset-work1-0   1/1     Running   0          9m5s   10.233.104.254   ubun20-01   <none>           <none>
statefulset-work1-1   1/1     Running   0          9m2s   10.233.109.186   ubun20-02   <none>           <none>

 

위에서 가장 나중에 생성됐던 pod 2번이 사라지고 나머지 두개만 남아있는 것을 확인할 수 있습니다. pod의 IP와 AGE를 확인해보면 위에서 생성된 스테이트풀셋의 pod와 동일한 것도 확인할 수 있습니다.