Infra/Kubernetes

[Kubernetes 입문] 6-2. 컨트롤러 (DemonSet, StatefulSet, Job, CronJob)

에드박 2023. 1. 19. 20:23

데몬셋 (DemonSet) - 공식문서

  • 클러스터 전체 노드에 특정 파드를 실행할 때 사용
    • 노드가 클러스터에 추가되면, 파드도 추가됨
    • 노드가 클러스터에서 제거되면, 데몬셋이 실행한 파드가 가비지(garbage)로 수집됨
  • 데몬셋의 대표적인 용도
    • 모든 노드에서 클러스터 스토리지 데몬 실행
    • 모든 노드에서 로그 수집 데몬 실행
    • 모든 노드에서 노드 모니터링 데몬 실행
# daemonset-example.yaml (데몬셋 예시)

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: fluentd-elasticsearch
  namespace: kube-system
  labels:
    k8s-app: fluentd-logging
spec:
  selector:
    matchLabels:
      name: fluentd-elasticsearch
  updateStrategy:
    type: RollingUpdate
  template:
    metadata:
      labels:
        name: fluentd-elasticsearch
    spec:
      containers:
      - name: fluentd-elasticsearch
        image: fluent/fluentd-kubernetes-daemonset:elasticsearch
        env:
        - name: testenv
          value: value
        resources:
          limits:
            memory: 200Mi
          requests:
            cpu: 100m
            memory: 200Mi
  • .spec.updateStrategy : 데몬셋의 파드를 업데이트 하는 전략 (자세한 내용은 공식 문서 참고) 
    • 2가지 타입이 존재 ( OnDelete, RollingUpdate ) 
    • OnDelete : 데몬셋 템플릿 업데이트 후, 데몬셋 파드를 수동으로 삭제할 때만, 새로운 데몬셋 파드가 생성됨 (쿠버네티스 1.5 버전 이하에서는 기본 값)
    • RollingUpdate : 데몬셋 템플릿 업데이트 후, 오래된 데몬셋 파드가 종료되고 새로운 데몬셋 파드가 자동으로 생성됨 (1.5 이상 버전에서 기본 값)
      • .spec.updateStrategy.rollingUpdate.maxUnavailable: 업데이트 도중 사용할 수 없는 최대 DaemonSet 파드 수 (기본값 1)
      • .spec.updateStrategy.rollingUpdate.maxSurge: DaemonSet 파드가 업데이트 중에 기존의 사용 가능한 DaemonSet 파드가 존재할 수 있는 최대 수 (기본 값 0)
      • .spec.minReadySeconds: 새로 생성된 DaemonSet 파드가 사용 가능한 것으로 간주되기 위해 컨테이너 충돌 없이 준비돼야 하는 최소 시간 (기본값 0)
# DaemonSet 적용
$ kubectl apply -f {데몬셋 템플릿 이름}

# Example
$ kubectl apply -f daemonset-example.yaml

# DaemonSet 확인해보기
$ kubectl get darmonset -n {네임스페이스}


스테이트풀셋 (StatefuleSet)

  • 상태가 있는 파드들을 관리하기 위한 컨트롤러
  • 여러 파드 사이에 순서를 지정해서 실행하는 것이 가능
  • Deployment와 동일하게 컨테이너 스펙을 기반으로 둔 파드들을 관리한다. 각 파드의 독자성을 유지한다는 것이(상태가 있다는 것) 차이점
  • 스토리지 볼륨을 사용할 때, 재시작 시 데이터 유지가 필요할 때 사용 가능
  • 다음의 항목이 필요한 애플리케이션에 유용함
    • 안정된, 고유한 네트워크 식별자
    • 안정된, 지속성을 갖는 스토리지
    • 순차적인, 정상 배포(graceful deployment)와 스케일링
    • 순차적인, 자동 롤링 업데이트
  • StatefulSet을 삭제 또는 스케일 다운해도 StatefulSet과 관련된 볼륨은 삭제되지 않음
    • StatefulSet과 연관된 모든 리소스를 자동으로 제거하는 것보다 더 중요한 데이터의 안전을 보장하기 위함
# StatefulSet 예시 (statefulset-example.yaml)

apiVersion: v1
kind: Service
metadata:
  name: nginx-statefulset-service
  labels:
    app: nginx-statefulset-service
spec:
  ports:
  - port: 80
    name: web
  clusterIP: None
  selector:
    app: nginx-statefulset-service
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
spec:
  selector:
    matchLabels:
      app: nginx-statefulset # .spec.template.metadata.labels 와 일치해야한다.
  serviceName: "nginx-statefulset-service"
  replicas: 3
  template:
    metadata:
      labels:
        app: nginx-statefulset
    spec:
      terminationGracePeriodSeconds: 10
      containers:
      - name: nginx-statefulset  # .spec.selector.matchLabels 와 일치해야한다.
        image: nginx
        ports:
        - containerPort: 80
          name: web
  • 위의 Service 는 StatefulSet 에서 serviceName 에서 사용하기 위해 정의되는 것
    • 서비스 이름과 스테이트풀셋에서 만들어진 파드 이름을 조합하면 쿠버네티스 클러스터 안에서 사용하는 도메인을 만들 수 있음
    • 파드이름.서비스이름 형식 (nginx-statefuleset.nginx-statefuleset-service)
  • (StatefulSet을 정의한 부분에서) .metadata.name 필드 값으로 StatefulSet 의 이름을 지정
  • .spec.template.spec.terminationGracePeriodSeconds 필드는 graceful의 대기 시간을 설정
  • .spec.selector 필드는 .spec.template.metadata.labels 레이블과 일치하도록 설정해야함. 해당하는 파드 셀렉터를 찾지못하면 StatefulSet 생성 과정에서 검증 오류가 발생
# StatefulSet 적용
$ kubectl apply -f {StatefulSet 템플릿 명}

# 조회
$ kubectl get svc,statefulset,pods

  • Pod 명을 보면 Deployment 에서 봤을 때와 다르게, StatefulSet 에서는 스테이트풀셋이름.번호순 으로 생성된것을 볼 수 있다.
    • pod/web-0 , pod/web-1 , pod/web-2
    • 이것은 실행된 순서대로 번호가 붙은 것
  • Pod가 삭제 될때는 생성된 것의 역순으로 제거됨 ( 2 -> 1 -> 0 )
    • Pod 개수를 줄일 때도 역순으로 제거.
    • 지금 상황에서 2개로 줄인다면, pod/web-2 가 우선적으로 제거됨

 

StatefulSet 에서 Pod 를 순서 없이 실행하거나 종료하기

  • StatefulSet 의 기본 동작은 Pod 를 순서대로 관리하는 것
  • .spec.podManagementPolicy 필드를 이용해 순서를 없앨 수도 있음
    • 기본값이 OrderedReady 로 파드를 순서대로 관리한다는 뜻
    • Parallel로 변경하면 파드들이 순서 없이 병렬로 실행
# Pod 생성 병렬 실행 예시

# Service 부분은 생략
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web-parallel # 확인을 편하게 하기위해 이름 변경
spec:
  podManagementPolicy: Parallel # 병렬 생성 정책으로 변경
  selector:
    matchLabels:
      app: nginx-statefulset
  serviceName: "nginx-statefulset-service"
  replicas: 3
  template:
    metadata:
      labels:
        app: nginx-statefulset
    spec:
      terminationGracePeriodSeconds: 10
      containers:
      - name: nginx-statefulset
        image: nginx
        ports:
        - containerPort: 80
          name: web

StatefulSet 로 파드 업데이트

  • .spec.updateStrategy.type 필드에 설정 RollingUpdate 와 OnDelete가 존재 (DaemonSet 에서 설명한 것과 같은 옵션)
  • 기본 값은 RollingUpdate (자동으로 예전 Pod를 삭제하고 새로운 Pod를 실행)
  • .spec.updateStrategy.rollingUpdate.partition 필드 값을 지정하면, StatefulSet 에 변경사항이 있을 때 지정된 값보다 큰 번호를 가진 Pod들을 업데이트 함

아래는 .spec.updateStrategy.rollingUpdate.partition을 1로 설정하고 StatefulSet 설정에 env 값을 추가한 뒤 Pod 의 상태

  • web-1, web-2 만 새로 생성된 것을 확인할 수 있다. (AGE 값 확인)
  • env 값을 조회했을 때, web-1, web-2 만 env가 업데이트 됨

  • .spec.updateStrategy.type을 OnDelete 로 설정하면 StatefulSet 의 템플릿을 수정해도 바로 반영되지 않음
  • StatefulSet 에 속한 Pod를 수동으로 삭제했을 때만, 수정된 설정이 반영된 Pod 가 생성됨

Job - 공식문서

  • 하나 이상의 Pod 를 생성하고 지정된 수의 Pod 가 성공적으로 종료될 때까지 계속해서 파드의 실행을 재시도함
  • 실행된 후 종료해야 하는 성격의 작업을 실행시킬 때 사용할 수 있음
# Job 예시 (job-example.yaml)

apiVersion: batch/v1
kind: Job
metadata:
  name: pi
spec:
  template:
    spec:
      containers:
      - name: pi
        image: perl:5.34.0
        command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
      restartPolicy: Never
  backoffLimit: 4
  • .spec.template.spec.containers[].command : 실행할 명령어 지정
    • 위 예시는 파이(π)의 2000자리까지 계산해서 출력
  • .spec.template.spec.restartPolicy : 파드 실행 실패 시 재시작 정책을 지정
    • Always (기본 값) : 정상적으로 종료(0 exit code)된 상태라도 재시작
    • OnFailure : 비정상적으로 종료된 경우에만 재시작
    • Never : Container의 exit code 와 관계없이 재시작하지 않는 정책
  • .spec.backoffLimit : 잡 실행이 실패했을 때 자동으로 재시도할 횟수를 설정 (기본값은 6)
    • 실패했을 때, 지수적으로 증가하는 백-오프 지연을 적용(10초, 20초, 40초 ... ). 실패 시 재시작 대기 시간을 늘려감 
    • 재시도 횟수는 다음 두 방법으로 계산
      • .status.phase = "Failed" 인 파드의 수
      • restartPolicy = "OnFailure" 를 사용하는 경우, .status.phase 가 Pending 이거나 Running 인 파드들이 가지고 있는 모든 컨테이너의 수
# Job 생성
$ kubectl apply -f {Job 템플릿 명}

# Job 조회
$ kubectl describe job {Job 이름}

kubectl get pods 를 사용해서 Job 이 생성한 파드의 상태를 볼 수도 있다.

출력된 로그를 확인하려면 $ kubectl logs {Pod 이름} 을 입력

Job 의 종류

  • 비 병렬 잡(단일 잡)
    • 파드가 실패하지 않은 한, 하나의 파드만 시작
    • 파드가 성공적으로 종료하자마자 즉시 잡이 완료
    • .spec.comletions 과 .spec.parallelism 값을 설정하지 않음 (둘 다 기본값인 1을 유지)
  • 고정적인 완료 횟수를 가진 병렬 잡
    • .spec.comletions 에 0이 아닌 양수 값을 지정
    • .spec.parallelism 을 설정하지 않음
  • 작업 큐(queue) 가 있는 병렬 잡
    • .spec.completions 를 설정하지 않고, .spec.parallelism 을 0이 아닌 양수로 설정
    • Pod는 각자 또는 외부 서비스 간에 조정을 통해 각각의 작업을 결정해야 함
    • 파드 각각은 정상적으로 실행 종료됐는지를 독립적으로 판단이 가능
    • 파드 하나라도 정상적으로 실행 종료되면 새로운 파드가 실행되지 않음
    • 최소한 파드 1개가 정상적으로 종료된 후 모든 파드가 실행 종료되면, 잡이 정상적으로 종료됨
    • 성공적으로 종료된 파드가 하나라도 생긴 경우, 다른 파드들은 작업을 지속하지 않아야하고 어떠한 출력도 내지 않음. 이 때 파드들은 모두 종료되는 과정을 실행

잡 종료와 정리

  • 잡이 완료되면 파드가 더 이상 생성되지도 않지만, 일반적으로는 삭제되지도 않는다.
  • 잡 오브젝트는 완료된 후에도 상태를 볼 수 있도록 남아 있는것
  • 잡 삭제는 사용자가 직접 해야함
    • kubectl delete job {Job 이름}
  • 잡을 종료하는 방법에는
    • .spec.backoffLimit 을 설정해 일정 횟수 이상 재시도 후 모든 파드가 종료되도록 제어
    • 유효 데드라인 설정 : .spec.activeDeadlineSeconds 필드를 초 단위로 설정하면 됨
    • .spec.activeDeadlineSeconds > .spec.backoffLimit  와 같이 activeDeadlineSeconds 설정이 우선순위가 더 높다

크론잡 (CronJob) - 공식문서

  • Job을 시간 기준으로 관리하도록 생성
  • 지정한 시간에 한번만 잡을 실행하거나 지정한 시간동안 주기적으로 잡을 반복 실행 (1일 / 1주 / 1달 마다 1회)
  • CronJob 이 실행된 후에는 위의 Job과 마찬가지로 동작함
# CronJob 예시 (cronjob-example.yaml)

apiVersion: batch/v1
kind: CronJob
metadata:
  name: hello
spec:
  schedule: "*/1 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: hello
            image: busybox
            args:
            - /bin/sh
            - -c
            - date; echo Hello from the Kubernetes cluster
          restartPolicy: OnFailure
  • .spec.schedule : 스케줄을 지정. 리눅스 cron 명령어와 같은 형식
  • .spec.jobTemplate : CronJob 에서 어떤 작업을 실행할지 작성
# 생성된 CronJob 정보 확인
$ kubectl get cronjobs

크론잡 설정

  • .spec.startingDeadlineSeconds : 지정된 시간에 크론잡이 실행되지 못했을 때 필드값으로 설정한 시간까지 지나면 크론잡이 실행되지 않게 함
  • .spec.concurrentcyPolicy : 크론잡이 실행하는 잡의 동시성을 관리
    • Allow (기본값) : 크론잡이 여러 개 잡을 동시에 실행할 수 있도록 설정
    • Forbid : 크론잡이 잡을 동시에 실행하지 않도록 설정. 새로운 잡을 실행할 시간이고 이전 잡 실행이 아직 완료되지 않은 경우, 크론잡은 새로운 잡 실행을 건너뜀
    • Replace : 새로운 잡을 실행할 시간이고 이전 잡 실행이 아직 완료되지 않은 경우, 크론잡은 현재 실행 중인 잡실행을 새로운 잡 실행으로 대체