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 명령어와 같은 형식
- https://crontab.guru/ 를 활용해서 cron 명령어 작성이 가능
- .spec.jobTemplate : CronJob 에서 어떤 작업을 실행할지 작성
# 생성된 CronJob 정보 확인
$ kubectl get cronjobs
크론잡 설정
- .spec.startingDeadlineSeconds : 지정된 시간에 크론잡이 실행되지 못했을 때 필드값으로 설정한 시간까지 지나면 크론잡이 실행되지 않게 함
- .spec.concurrentcyPolicy : 크론잡이 실행하는 잡의 동시성을 관리
- Allow (기본값) : 크론잡이 여러 개 잡을 동시에 실행할 수 있도록 설정
- Forbid : 크론잡이 잡을 동시에 실행하지 않도록 설정. 새로운 잡을 실행할 시간이고 이전 잡 실행이 아직 완료되지 않은 경우, 크론잡은 새로운 잡 실행을 건너뜀
- Replace : 새로운 잡을 실행할 시간이고 이전 잡 실행이 아직 완료되지 않은 경우, 크론잡은 현재 실행 중인 잡실행을 새로운 잡 실행으로 대체