1. cronjob이란 무엇인가요?
Kubernetes에는 Linux / Unix Operation System에 존재하는 CronTab을 구현한 CronJob이 존재한다. CronJob은 반복적이고 Scheduling 된 업무를 동작하게 하는 방법 중 하나로 CronTab이 항상 OS Level의 Configuration으로 남아 있는것과 달리 휴발성 있는 컨테이너에서 Job을 실행하고 종료하는 방식으로 보다 안전한 관리 방식을 제공한다.apiVersion: batch/v1beta1
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
위의 예시는 매 1분마다 command 수행을 하게 됩니다. pod를 생성하여 작업하고나서 종료되는 cycle을 갖고 있습니다.
2. cronjob helm chart 구성
보통 spring framework로 구성이 되어있고 1개의 어플리케이션 내에서 여러개의 batch성 작업을 구성하게 됩니다. 그러다보니 고민이 생겼습니다. 초기에 구성을 해뒀던것은 1개의 helm chart에 1개의 cronjob을 수행하게 했었습니다. 왜냐하면 batch app이 늘어날것이라고 예상을 했지만, 1개의 app에서 argument를 달리주어 여러개의 작업을 수행하도록 구성이 되었던 것입니다. 그래서 필자는 하나의 헬름차트 내에서 다수의 cronjob을 생성하도록 구성해야 했습니다.#values file 예시
...
crons:
- name: cronjob
list:
- name: "test1"
command: test1
schedule: "*/5 * * * *"
suspend: false
- name: "test2"
command: test2
schedule: "0 * * * *"
suspend: false
- name: "test3-weekday"
command: test3-weekday
schedule: "0/10 8-20 * * 1-5"
suspend: false
- name: "test3-weekend"
command: test3-weekend
schedule: "0 8-21/2 * * 0,6"
suspend: false
...
values 파일은 위와 같이 crons 하위로 list를 만들어서 여러개의 설정이 한번에 들어가도록 구성을 했습니다.
{{- range $cronjob := .Values.crons }}
{{- range $key, $value := $cronjob.list }}
apiVersion: cronjobber.hidde.co/v1alpha1
kind: TZCronJob
metadata:
name: {{ $.Values.phase }}-{{ $value.name }}
namespace: {{ $.Values.namespace }}
labels:
service.phase: {{ $.Values.phase }}
service.name: {{ $.Values.namespace }}
project.name: {{ $.Values.projectName }}
spec:
schedule: {{ quote $value.schedule }}
timezone: "Asia/Seoul"
successfulJobsHistoryLimit: 5
failedJobsHistoryLimit: 3
suspend: {{ $value.suspend }}
jobTemplate:
spec:
template:
metadata:
labels:
service.phase: {{ $.Values.phase }}
service.name: {{ $.Values.namespace }}
project.name: {{ $.Values.projectName }}
deploy.version: {{ $.Values.deployImgVersion }}
annotations:
sidecar.istio.io/inject: {{ $.Values.istioInject | quote }}
sidecar.istio.io/gracefulshutdown: {{ $.Values.istioGracefulshutdown | quote }}
sidecar.istio.io/rewriteAppHTTPProbers: {{ $.Values.istioRewriteAppHTTPProbers | quote }}
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: networkType
operator: In
values:
- publicip-assignment
containers:
- name: {{ $.Values.phase }}-{{ $value.name }}
image: {{ $.Values.dockerImgName }}:{{ $.Values.deployImgVersion }}
resources:
requests:
memory: {{ $.Values.minMem }}
cpu: {{ $.Values.minCpu }}
limits:
memory: {{ $.Values.maxMem }}
cpu: {{ $.Values.maxCpu }}
env:
{{- range $key, $val := $.Values.extraEnvs }}
- name: {{ $key }}
value: "{{ $val }}"
{{- end }}
- name: JAVA_OPTS
value:
-Xms{{ $.Values.jvmXms }}
-Xmx{{ $.Values.jvmXmx }}
-Dspring.profiles.active={{ $.Values.phase }}
-Dpinpoint.applicationName={{ $.Values.phase }}-dosi-payment-cronjob
- name: BATCH_OPTS
value: {{ $value.command }}
- name: TZ
value: Asia/Seoul
restartPolicy: OnFailure
---
{{- end}}
{{- end}}
실제 cronjob.yaml 파일은 위와 같습니다. 앞서 values 파일에서 설정한 crons 정보를 기반으로 반복적으로 cron형태를 생성하게 됩니다. 그렇게 되면, 1개의 helm chart에서 다수의 cronjob을 생성하는것과 동일하게 구성이 됩니다.
3. cronjob timezone 이슈 해결
cronjob 구성을 마치고 나서, 배포를 수행했고 정상적으로 cron에 맞추어 작업이 되는지를 확인했습니다. - name: "test3-weekday"
command: test3-weekday
schedule: "0/10 8-20 * * 1-5"
suspend: false
- name: "test3-weekend"
command: test3-weekend
schedule: "0 8-21/2 * * 0,6"
suspend: false
특히 위와 같이 주중, 주말에 실행이 되어야 하는 것처럼 주중 8-20시 사이 10분단위로 수행하도록 구성이 되었지만 이상하게도 +9시간씩의 차이가 발생을 했습니다. (UTC+9)인것을 확인하고 cronjob에 TIME ZONE까지 명시적으로 넣었지만 변경되는 것은 없었습니다.
확인을 해보니, 실제 cronjob이 수행이 되기 위해서는 kube-controller의 timzezone에 맞추어 진행이 되는데 이를 변경할수는 없어서 추가적인 cronjob conroller를 설치하기로 했습니다.
cronjobber
#설치
# Install CustomResourceDefinition
$ kubectl apply -f https://raw.githubusercontent.com/hiddeco/cronjobber/master/deploy/crd.yaml
# Setup service account and RBAC
$ kubectl apply -f https://raw.githubusercontent.com/hiddeco/cronjobber/master/deploy/rbac.yaml
# Deploy Cronjobber (using the timezone db from the node)
$ kubectl apply -f https://raw.githubusercontent.com/hiddeco/cronjobber/master/deploy/deploy.yaml
# Deploy Cronjobber (using the updatetz sidecar)
$ kubectl apply -f https://raw.githubusercontent.com/hiddeco/cronjobber/master/deploy/deploy-updatetz.yaml
설치는 굉장히 간다하고, 위의 내용을 설치한뒤, cronjob.yaml의 **timezone: “Asia/Seoul” **옵션을 부여하게 되면 해당 타임존으로 변경이 수행됩니다.
4. Cronjob option 값 조정
필자는 default를 중요시 하기때문에 별다른 설정을 변경하지는 않았고, 개발팀에서 필요로 하는 부분에 대한 설정만을 진행했습니다. schedule: {{ quote $value.schedule }}
timezone: "Asia/Seoul"
successfulJobsHistoryLimit: 5
failedJobsHistoryLimit: 3
...
restartPolicy: OnFailure
- 스케쥴에 대한 설정
- 성공 이력 5건
- 실패 이력 3건
- 재실행 정책 : 실패시
5. 마치며…
이번시간에는 cronjob 구성을 통해서 기존의 jenkins를 통해서 수행하거나 직접 소스상에 스케쥴링을 거는 부분들을 모두 k8s의 장점을 활용할 수 있도록 구성을 했다는 점에서 좋았던 것 같습니다. cronjob의 pod도 모두 메트릭 수집의 대상이기 때문에 성공, 실패 이력에 대해서 대시보드로 표현이 가능하고 alert도 보내줄 수 있게 되었습니다. 나중에는 이러한 부분들까지 모두 구성을 하여 해당 batch에 대해서 notification구성이 될 수 있도록 진행해보겠습니다.참고
https://kubernetes.io/ko/docs/concepts/workloads/controllers/cron-jobs/ https://arisu1000.tistory.com/27837 https://waspro.tistory.com/644함께 보면 좋은 글
- [Kubernetes] Autoscaling 사용하기
- [Kubernetes] Helm Chartmuseum 사용법
- [Kubernetes] K8S Cronjob Monitoring
- [Kubernetes] k8s master 서버 HA 구성하기
새 글이 올라오면 Threads @wonizz.ai 에도 올립니다. 팔로우해 두면 피드에서 바로 볼 수 있습니다.