StatefulSet ?

StatefulSet 개념

  • StatefulSet은 Pod을 scale up&down 하여 새로 배포 할 때 각 Pod의 기존 Spec(hostname,Ip등) 을 유지하여 생성함 (stateful)
  • stateless 한 deployment, replicaset 과는 다른점임
  • Pod 별로 각각의 PVC를 사용하거나 Pod 생성 순서가 중요할 때 (Master / Slave 구성이 필요할떄) statefulset 을 사용하여 Ordering을 보장하고 구분지을 수 있음
  • 위 구성을 replicaSet , delpoyment를 사용했다면 pod-0 , pod-1 이 같은 PVC,PV를 사용하여 Pod 고유의 state가 사라지고 , 재기동 될 때마다 IP,hostname이 달라져 headless Service를 사용할 수 없음

StatefulSet 사용 현황

$ kubectl get statefulset
NAME                         READY   AGE
kimdubi-test-redis-cluster   6/6     2d4h
  • statefulset 하나로 Pod 6대를 관리함, Pod이 down되어도 statefulset에 의해 자동으로 restart 됨
  • Pod,pvc 생성 구문은 statefulset 에서 정의됨

StatefulSet template을 살펴보자

$ kubectl get statefulset kimdubi-test-redis-cluster -o yaml

apiVersion: apps/v1
kind: StatefulSet
metadata:
  annotations:
    meta.helm.sh/release-name: kimdubi-test
    meta.helm.sh/release-namespace: default
  creationTimestamp: "2021-02-21T07:33:55Z"
  generation: 1
  labels:
    app.kubernetes.io/instance: kimdubi-test
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: redis-cluster
    helm.sh/chart: redis-cluster-4.3.0
  name: kimdubi-test-redis-cluster
  namespace: default
  resourceVersion: "358350"
  selfLink: /apis/apps/v1/namespaces/default/statefulsets/kimdubi-test-redis-cluster
  uid: b348894a-e930-4dc2-ba10-c8566eeec0b9
spec:
  podManagementPolicy: Parallel
  replicas: 6
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      app.kubernetes.io/instance: kimdubi-test
      app.kubernetes.io/name: redis-cluster
  serviceName: kimdubi-test-redis-cluster-headless
  template:
    metadata:
      annotations:
        checksum/scripts: 13c84ab100b949b2a69989dbcfa1079e3d930ee56d79744da9abc6d691709923
        checksum/secret: 3fb9c96414bd6f5e1a0841de974fcb260231a9c12bebb2c49af0f02b651e47cf
      creationTimestamp: null
      labels:
        app.kubernetes.io/instance: kimdubi-test
        app.kubernetes.io/managed-by: Helm
        app.kubernetes.io/name: redis-cluster
        helm.sh/chart: redis-cluster-4.3.0
    spec:
      affinity:
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - podAffinityTerm:
              labelSelector:
                matchLabels:
                  app.kubernetes.io/instance: kimdubi-test
                  app.kubernetes.io/name: redis-cluster
              namespaces:
              - default
              topologyKey: kubernetes.io/hostname
            weight: 1
      containers:
      - args:
        - |
          # Backwards compatibility change
          if ! [[ -f /opt/bitnami/redis/etc/redis.conf ]]; then
              echo COPYING FILE
              cp  /opt/bitnami/redis/etc/redis-default.conf /opt/bitnami/redis/etc/redis.conf
          fi
          /opt/bitnami/scripts/redis-cluster/entrypoint.sh /opt/bitnami/scripts/redis-cluster/run.sh
        command:
        - /bin/bash
        - -c
        env:
        - name: REDIS_NODES
          value: 'kimdubi-test-redis-cluster-0.kimdubi-test-redis-cluster-headless
            kimdubi-test-redis-cluster-1.kimdubi-test-redis-cluster-headless kimdubi-test-redis-cluster-2.kimdubi-test-redis-cluster-headless
            kimdubi-test-redis-cluster-3.kimdubi-test-redis-cluster-headless kimdubi-test-redis-cluster-4.kimdubi-test-redis-cluster-headless
            kimdubi-test-redis-cluster-5.kimdubi-test-redis-cluster-headless '
        - name: REDISCLI_AUTH
          valueFrom:
            secretKeyRef:
              key: redis-password
              name: kimdubi-test-redis-cluster
        - name: REDIS_PASSWORD
          valueFrom:
            secretKeyRef:
              key: redis-password
              name: kimdubi-test-redis-cluster
        - name: REDIS_AOF_ENABLED
          value: "yes"
        - name: REDIS_TLS_ENABLED
          value: "no"
        - name: REDIS_PORT
          value: "6379"
        image: docker.io/bitnami/redis-cluster:6.0.10-debian-10-r5
        imagePullPolicy: IfNotPresent
        livenessProbe:
          exec:
            command:
            - sh
            - -c
            - /scripts/ping_liveness_local.sh 5
          failureThreshold: 5
          initialDelaySeconds: 5
          periodSeconds: 5
          successThreshold: 1
          timeoutSeconds: 5
        name: kimdubi-test-redis-cluster
        ports:
        - containerPort: 6379
          name: tcp-redis
          protocol: TCP
        - containerPort: 16379
          name: tcp-redis-bus
          protocol: TCP
        readinessProbe:
          exec:
            command:
            - sh
            - -c
            - /scripts/ping_readiness_local.sh 1
          failureThreshold: 5
          initialDelaySeconds: 5
          periodSeconds: 5
          successThreshold: 1
          timeoutSeconds: 1
        resources:
          limits:
            cpu: 100m
            memory: 100Mi
          requests:
            cpu: 50m
            memory: 50Mi
        securityContext:
          runAsUser: 1001
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
        volumeMounts:
        - mountPath: /scripts
          name: scripts
        - mountPath: /bitnami/redis/data
          name: redis-data
        - mountPath: /opt/bitnami/redis/etc/redis-default.conf
          name: default-config
          subPath: redis-default.conf
        - mountPath: /opt/bitnami/redis/etc/
          name: redis-tmp-conf
      dnsPolicy: ClusterFirst
      enableServiceLinks: false
      restartPolicy: Always
      schedulerName: default-scheduler
      securityContext:
        fsGroup: 1001
      serviceAccount: default
      serviceAccountName: default
      terminationGracePeriodSeconds: 30
      volumes:
      - configMap:
          defaultMode: 493
          name: kimdubi-test-redis-cluster-scripts
        name: scripts
      - configMap:
          defaultMode: 420
          name: kimdubi-test-redis-cluster-default
        name: default-config
      - emptyDir: {}
        name: redis-tmp-conf
  updateStrategy:
    type: RollingUpdate
  volumeClaimTemplates:
  - apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      creationTimestamp: null
      name: redis-data
    spec:
      accessModes:
      - ReadWriteOnce
      resources:
        requests:
          storage: 2Gi
      storageClassName: kimdubi-test
      volumeMode: Filesystem
    status:
      phase: Pending
status:
  collisionCount: 0
  currentReplicas: 6
  currentRevision: kimdubi-test-redis-cluster-86585bd988
  observedGeneration: 1
  readyReplicas: 6
  replicas: 6
  updateRevision: kimdubi-test-redis-cluster-86585bd988
  updatedReplicas: 6

.spec.replicas

  • statefulset 에서 관리할 동일한 스펙의 Pod를 6대만큼 생성하겠다는 설정
  • 생성할 Pod의 상세 설정은 .spec.template.spec에 정의 되어있음

.spec.selector.matchLabels

  • statefulset 에서 관리할 Pod를 구분짓는 조건
  • Pod의 label과 .spec.selector.matchLabels가 동일한지 체크를 통해 관리할 Pod를 구분함

.spec.serviceName

  • statefulset 으로 생성된 Pod 들이 사용할 Service
  • statefulset 에선 Pod에 직접 access할 수 있는 DNS를 할당하기 위해 headless service를 사용함
  • 관련 내용은 service편에서..

.spec.template.metadata.labels

  • 생성할 Pod의 label 을 설정하는 부분, .spec.selector.matchLabels의 label과 일치해야함

.spec.updateStrategy.type

  • statefulset 을 통해 배포할 때 Pod이 배포되는 방식을 설정
  • RollingUpdate : Ordering 된 Pod 들을 마지막 Pod부터 순서대로 재생성하여 배포함
  • onDelete : Pod을 수동으로 삭제 했을 때 새로운 설정이 반영된 Pod가 생성됨

.spec.volumeClaimTemplates

  • statefulset 에 의해 생성되고 관리되는 Pod에 하나씩 binding 해줄 PVC 정의 부분
  • 정의한 PVC를 .spec.template.spec.containers.volumeMounts 를 통해 container의 /bitnami/redis/data 디렉토리에 binding하고 있음