개발강의정리/DevOps

[데브옵스를 위한 쿠버네티스 마스터] 쿠버네티스 핵심개념-Statefulset

nineDeveloper 2021. 1. 3.
728x90

Statefulset

https://blog.naver.com/isc0304/221885403537

스테이트풀셋(Statefulset)이란?

애플리케이션의 상태를 저장하고 관리하는 데 사용되는 쿠버네티스 객체다
기존의 포드를 삭제하고 생성할 때 상태가 유지되지 않는 한계가 있다
때문에 포드를 삭제하고 생성하면 완전히 새로운 가상환경이 시작된다

하지만 필요에 따라 이러한 포드의 상태를 유지하고 싶을 수 있다
응용프로그램의 로그나 기타 다른 정보들을 함께 저장하고자 하는 경우 단순히 PV를 하나 마운트해 이를 유지하기는 어렵다
스테이트풀셋으로 생성되는 포드는 영구 식별자를 가지고 상태를 유지시킬 수 있다

스테이트풀셋를 사용하고 자하는 케이스 다음과 같다

  • 안정적이고 고유한 네트워크 식별자가 필요한 경우
  • 안정적이고 지속적인 스토리지를 사용해야 하는 경우
  • 질서 정연한 포드의 배치와 확장을 원하는 경우
  • 포드의 자동 롤링업데이트를 사용하기 원하는 경우

스테이트풀셋은 각 포드의 상태를 유지할 수 있는 장점과 함께 몇가지 문제를 해결해야 한다

  • 스테이트풀셋과 관련된 볼륨이 삭제되지 않음 (관리 필요)
  • 포드의 스토리지는 PV나 스토리지클래스로 프로비저닝 수행해야 함
  • 롤링업데이트를 수행하는 경우 수동으로 복구해야 할 수 있음 (롤링업데이트 수행 시 기존의 스토리지와 충돌로 인해 애플리케이션이 오류가 발생할 수 있다는 의미다)
  • 포드 네트워크 ID를 유지하기 위해 헤드레스(headless) 서비스 필요

상태를 유지할 수 있다는 장점도 있지만 이로 인해 포드를 각각 따로 관리해줘야 하는 문제도 함께 동반한다
따라서 스테이트풀셋을 사용할 건지 디플로이먼트를 사용할 것인지는 프로젝트의 상황에 따라 달라질 수 있다

스테이트풀 생성 및 관찰

nginx-statefulset.yaml 파일 작성

# nginx-statefulset.yaml
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
  serviceName: "nginx" # 헤드레스 서비스를 지정한다.
  replicas: 3 # by default is 1
  template:
    metadata:
      labels:
        app: nginx
    spec:
      terminationGracePeriodSeconds: 10 # 강제 종료까지 대기하는 시간
      containers:
      - name: nginx
        image: k8s.gcr.io/nginx-slim:0.8
        ports:
        - containerPort: 80
          name: web
        volumeMounts:
        - name: www
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates: # PVC 설정을 저장하는 부분
  - metadata:
      name: www
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: "standard"
      resources:
        requests:
          storage: 1Gi

kubectl 로 생성 및 확인

statefulset 한번에 하나씩 만들어짐

$ kubectl create -f nginx-statefulset.yaml
service/nginx created
statefulset.apps/web created

$ kubectl get svc
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.36.0.1    <none>        443/TCP   18m
nginx        ClusterIP   None         <none>        80/TCP    40s

$ kubectl get all
NAME        READY   STATUS    RESTARTS   AGE
pod/web-0   1/1     Running   0          69s
pod/web-1   1/1     Running   0          39s
pod/web-2   1/1     Running   0          23s

NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
service/kubernetes   ClusterIP   10.36.0.1    <none>        443/TCP   18m
service/nginx        ClusterIP   None         <none>        80/TCP    70s

NAME                   READY   AGE
statefulset.apps/web   3/3     70s

$ kubectl get pvc
NAME        STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
www-web-0   Bound    pvc-dd97b926-278d-48f0-ade2-e458949c227b   1Gi        RWO            standard       2m5s
www-web-1   Bound    pvc-96da613a-1ff6-4afd-8bad-94cb17306db4   1Gi        RWO            standard       94s
www-web-2   Bound    pvc-cc84c78a-318a-4d38-b514-f5ed80a237e8   1Gi        RWO            standard       78s

도메인 네임과 서비스 동작 확인

$ kubectl run -i --tty --image busybox:1.28 dns-test --restart=Never --rm /bin/sh
If you don't see a command prompt, try pressing enter.

# nslookup web-0.nginx.default.svc
Server:    10.36.0.10
Address 1: 10.36.0.10 kube-dns.kube-system.svc.cluster.local

Name:      web-0.nginx.default.svc
Address 1: 10.32.2.12 web-0.nginx.default.svc.cluster.local

# nslookup web-1.nginx.default.svc
Server:    10.36.0.10
Address 1: 10.36.0.10 kube-dns.kube-system.svc.cluster.local

Name:      web-1.nginx.default.svc
Address 1: 10.32.2.13 web-1.nginx.default.svc.cluster.local

# nslookup web-2.nginx.default.svc
Server:    10.36.0.10
Address 1: 10.36.0.10 kube-dns.kube-system.svc.cluster.local

Name:      web-2.nginx.default.svc
Address 1: 10.32.1.4 web-2.nginx.default.svc.cluster.local

각각의 포드에 도메인 네임 서비스를 통해 접근할 수 있는 것을 확인할 수 있음

$ kubectl get pod -o wide
NAME       READY   STATUS    RESTARTS   AGE     IP           NODE                                       NOMINATED NODE   READINESS GATES
web-0      1/1     Running   0          32m     10.32.2.12   gke-cluster-1-default-pool-f6cef6fa-hbbq   <none>           <none>
web-1      1/1     Running   0          31m     10.32.2.13   gke-cluster-1-default-pool-f6cef6fa-hbbq   <none>           <none>
web-2      1/1     Running   0          31m     10.32.1.4    gke-cluster-1-default-pool-f6cef6fa-hmlx   <none>           <none>

스케일 업, 스케일 다운

변경감지 대기

$ kubectl get pod -w
NAME       READY   STATUS    RESTARTS   AGE
dns-test   1/1     Running   0          5m14s
web-0      1/1     Running   0          34m
web-1      1/1     Running   0          34m
web-2      1/1     Running   0          33m

새로운 탭을 열어 스케일 확장을 진행

$ kubectl scale statefulset web --replicas 5
statefulset.apps/web scaled

하나씩 변경 되는 것을 확인

NAME       READY   STATUS    RESTARTS   AGE
dns-test   1/1     Running   0          5m14s
web-0      1/1     Running   0          34m
web-1      1/1     Running   0          34m
web-2      1/1     Running   0          33m
dns-test   0/1     Error     0          7m5s
dns-test   0/1     Terminating   0          7m6s
dns-test   0/1     Terminating   0          7m6s
web-3      0/1     Pending       0          0s
web-3      0/1     Pending       0          0s
web-3      0/1     Pending       0          6s
web-3      0/1     ContainerCreating   0          6s
web-3      1/1     Running             0          16s
web-4      0/1     Pending             0          0s
web-4      0/1     Pending             0          0s
web-4      0/1     Pending             0          6s
web-4      0/1     ContainerCreating   0          6s
web-4      1/1     Running             0          30s

다시 스케일을 축소

$ kubectl scale statefulset web --replicas 1
statefulset.apps/web scaled

스케일 축소에 따라 삭제되는 것을 확인

NAME       READY   STATUS    RESTARTS   AGE
web-4      1/1     Terminating         0          6m19s
web-4      0/1     Terminating         0          6m20s
web-4      0/1     Terminating         0          6m21s
web-4      0/1     Terminating         0          6m21s
web-3      1/1     Terminating         0          6m37s
web-3      0/1     Terminating         0          6m38s
web-3      0/1     Terminating         0          6m43s
web-3      0/1     Terminating         0          6m43s
web-2      1/1     Terminating         0          42m
web-2      0/1     Terminating         0          42m
web-2      0/1     Terminating         0          42m
web-2      0/1     Terminating         0          42m
web-1      1/1     Terminating         0          42m
web-1      0/1     Terminating         0          42m
web-1      0/1     Terminating         0          43m
web-1      0/1     Terminating         0          43m

스토리지 지속성 확인

포드가 삭제되도 pvc와 pv 스토리지가 여전히 남아있는 것을 확인

$ kubectl get pvc
NAME        STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
www-web-0   Bound    pvc-dd97b926-278d-48f0-ade2-e458949c227b   1Gi        RWO            standard       45m
www-web-1   Bound    pvc-96da613a-1ff6-4afd-8bad-94cb17306db4   1Gi        RWO            standard       45m
www-web-2   Bound    pvc-cc84c78a-318a-4d38-b514-f5ed80a237e8   1Gi        RWO            standard       44m
www-web-3   Bound    pvc-c5e6a7c5-ab35-4ac6-af58-d07f3d8f5230   1Gi        RWO            standard       9m10s
www-web-4   Bound    pvc-d74a2339-583a-499e-9f19-66129969785a   1Gi        RWO            standard       8m54s

$ kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM               STORAGECLASS   REASON   AGE
pvc-96da613a-1ff6-4afd-8bad-94cb17306db4   1Gi        RWO            Delete           Bound    default/www-web-1   standard                45m
pvc-c5e6a7c5-ab35-4ac6-af58-d07f3d8f5230   1Gi        RWO            Delete           Bound    default/www-web-3   standard                9m10s
pvc-cc84c78a-318a-4d38-b514-f5ed80a237e8   1Gi        RWO            Delete           Bound    default/www-web-2   standard                44m
pvc-d74a2339-583a-499e-9f19-66129969785a   1Gi        RWO            Delete           Bound    default/www-web-4   standard                8m53s
pvc-dd97b926-278d-48f0-ade2-e458949c227b   1Gi        RWO            Delete           Bound    default/www-web-0   standard                45m

스테이트 풀셋 삭제 후 에도 여전히 남아있음을 확인

$ kubectl delete statefulsets web
statefulset.apps "web" deleted

$ kubectl get pvc
NAME        STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
www-web-0   Bound    pvc-dd97b926-278d-48f0-ade2-e458949c227b   1Gi        RWO            standard       45m
www-web-1   Bound    pvc-96da613a-1ff6-4afd-8bad-94cb17306db4   1Gi        RWO            standard       45m
www-web-2   Bound    pvc-cc84c78a-318a-4d38-b514-f5ed80a237e8   1Gi        RWO            standard       44m
www-web-3   Bound    pvc-c5e6a7c5-ab35-4ac6-af58-d07f3d8f5230   1Gi        RWO            standard       9m10s
www-web-4   Bound    pvc-d74a2339-583a-499e-9f19-66129969785a   1Gi        RWO            standard       8m54s

$ kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM               STORAGECLASS   REASON   AGE
pvc-96da613a-1ff6-4afd-8bad-94cb17306db4   1Gi        RWO            Delete           Bound    default/www-web-1   standard                45m
pvc-c5e6a7c5-ab35-4ac6-af58-d07f3d8f5230   1Gi        RWO            Delete           Bound    default/www-web-3   standard                9m10s
pvc-cc84c78a-318a-4d38-b514-f5ed80a237e8   1Gi        RWO            Delete           Bound    default/www-web-2   standard                44m
pvc-d74a2339-583a-499e-9f19-66129969785a   1Gi        RWO            Delete           Bound    default/www-web-4   standard                8m53s
pvc-dd97b926-278d-48f0-ade2-e458949c227b   1Gi        RWO            Delete           Bound    default/www-web-0   standard                45m

다시 생성시 기존에 스테이트풀셋이 유지하고 있던 것이 있기 때문에 스케일을 다시 하게 되면 기존에 있던 것에 그대로 붙게됨

kubectl create -f nginx-statefulset.yaml
statefulset.apps/web created
Error from server (AlreadyExists): error when creating "nginx-statefulset.yaml": services "nginx" already exists

생성된 pod에 클레임이 잘 연결돼 있는지 확인한다
이름이 모두 기존의 pvc와 동일하게 잘 연결된 모습을 확인할 수 있다

$ kubectl get pod -o yaml | grep claim
        claimName: www-web-0
        claimName: www-web-1
        claimName: www-web-2

롤링 업데이트

업데이트 시에도 동일하게 동작하는지 확인

edit 명령으로 업데이트

$ kubectl edit statefulsets.apps web

image 를 k8s.gcr.io/nginx-slim:0.9 로 수정

...
spec:
  ...
  template:
    ...
    spec:
      ...
      containers:
      - image: k8s.gcr.io/nginx-slim:0.9
...

역순으로 업데이트가 잘 되는 것을 확인할 수 있음

NAME       READY   STATUS    RESTARTS   AGE
web-2      0/1     Pending             0          0s
web-2      0/1     Pending             0          0s
web-2      0/1     ContainerCreating   0          0s
web-2      1/1     Running             0          10s
web-2      1/1     Terminating         0          9m48s
web-2      0/1     Terminating         0          9m48s
web-2      0/1     Terminating         0          9m49s
web-2      0/1     Terminating         0          9m50s
web-2      0/1     Pending             0          0s
web-2      0/1     Pending             0          0s
web-2      0/1     ContainerCreating   0          0s
web-2      1/1     Running             0          24s
web-1      1/1     Terminating         0          10m
web-1      0/1     Terminating         0          10m
web-1      0/1     Terminating         0          10m
web-1      0/1     Terminating         0          10m
web-1      0/1     Pending             0          0s
web-1      0/1     Pending             0          0s
web-1      0/1     ContainerCreating   0          0s
web-1      1/1     Running             0          23s
web-0      1/1     Terminating         0          11m
web-0      0/1     Terminating         0          11m
web-0      0/1     Terminating         0          11m
web-0      0/1     Terminating         0          11m
web-0      0/1     Pending             0          0s
web-0      0/1     Pending             0          0s
web-0      0/1     ContainerCreating   0          0s
web-0      1/1     Running             0          7s
728x90

댓글

💲 추천 글