How to make cronjob to support timezone
Problem
CronJob
이 지정된 시간에 잘 동작했는 지 확인해 본 결과 이상한 점을 발견했다.
오후 2시 32분에 CronJob
의 동작을 확인했는데 이전에 실행된 시간이 4시간 32분 전이라고, 즉 새벽 1시가 아니라 오전 10시에 실행이 되었다는 나오는 것이다.
$ date
Sat Oct 10 14:32:36 KST 2020
$ kubectl get cronjob
NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE
pocket-stat 0 1 * * * False 0 4h32m 14h
혹시 10시를 1시로 잘못 설정했나 하고 kubectl describe cronjob
명령으로 확인해 봤지만 schedule
정보는 정상적으로 설정되어 있었다는.
Schedule: 0 1 * * *
하지만 kubectl describe cronjob
명령으로 확인한 실제 실행된 시간은 역시 오전 10시
Last Schedule Time: Sat, 10 Oct 2020 10:00:00 +0900
아래는 kubectl describe cronjob
명령의 전체 결과.
$ kubectl describe cronjob pocket-stat
Name: pocket-stat
Namespace: default
Labels: app.kubernetes.io/managed-by=Helm
Annotations: meta.helm.sh/release-name: pocket-stat
meta.helm.sh/release-namespace: default
Schedule: 0 1 * * *
Concurrency Policy: Allow
Suspend: False
Successful Job History Limit: 3
Failed Job History Limit: 1
Starting Deadline Seconds: <unset>
Selector: <unset>
Parallelism: <unset>
Completions: <unset>
Pod Template:
Labels: app.kubernetes.io/instance=pocket-stat
app.kubernetes.io/name=pocket-stat
Service Account: pocket-stat
Containers:
pocket-stat:
Image: ghcr.io/cychong47/pocket-stat:0.1
Port: 32769/TCP
Host Port: 0/TCP
Environment:
INFLUXDB_HOST: influxdb.default
INFLUXDB_PORT: 8086
POCKET_CONSUMER_KEY: <set to the key 'pocket_consumer_key' in secret 'my-tokens'> Optional: false
POCKET_ACCESS_TOKEN: <set to the key 'pocket_access_token' in secret 'my-tokens'> Optional: false
TZ: Asia/Seoul
Mounts: <none>
Volumes: <none>
Last Schedule Time: Sat, 10 Oct 2020 10:00:00 +0900
Active Jobs: <none>
Events: <none>
이상하다, 이게 무슨 조화일까?
시간을 내서 원인을 확인해 봐야겠다 싶었는데 다른 일을 하다 9시간 차이
라는 게 뇌리에 남았다. 9 이라는 숫자가 왠지 낯익은데.
개발한 SW를 국내에서만 사용하면 문제가 없지만, 해외에 판매해서 우리와 다른 Timezone에서 실행하면 한번 쯤은 겪어 봤을 수 있는 UTC+9
.
그래서 검색을 해 보니 아니나 다를 까 CronJob
이 Timezone을 지원하지 않는다고.구글링 결과에서 한글로 된 자료가 별로 없었는데 아마도 다른 Timezone
, kubernetes
그리고 CronJob
이라는 조합이 그리 흔한 경우가 아니라서 그런 듯 하다.
CronJob
을 설명하는 공식 문서에는 이에 대해 다음과 같이 명시하고 있다.
From CronJob | Kubernetes
Caution:
All CronJob schedule: times are based on the timezone of the kube-controller-managerIf your control plane runs the kube-controller-manager in Pods or bare containers, the timezone set for the kube-controller-manager container determines the timezone that the cron job controller uses.
Timezone 는 우리나라에서만 사용하는 것도 아니고, 미국 같은 경우에는 특히나 동부, 서부도 다른 Timezone을 사용하고 있으니 관련 이슈가 이미 제기되었을 것 같고. 유럽만 해도 서로 다른 Timezone에 위치한 나라가 모여있는 곳이라 같은 문제가 있을 텐데. 확인해 보니 Kubernetes 커뮤너티에서도 이미 이슈화가 되어 검토를 했지만, 지원하지 않는 걸로 정리를 했다고 한다. Daylight Saving Time(DST)이라고 하는 Summer Time 도 고려해야 하고 kubernetes 내 다른 component들과의 시간 동기화도 고려해야 하는 등 고려해야 할 게 너무 많다고. 그래서 그냥 UTC로 고수하겠다고.
Resolutions
Python의 경우도 그렇지만 환경변수 TZ
을 설정하는 방법이 많이 시도된 듯 한데
Kube-controller-manager
의 경우에는 해당 container의 TZ
를 변경하는 건 소용이 없다고.
대신 /etc/localtime
을 설정하면 된다고 한다.(참고로, 해당 파일이 없는 경우 기본 설정이 UTC
)
After testing today, the solution based on TZ environment variable in the kube-controller-manager pod doesn’t work.
To make timezone work we have to mount a volume inside the pod at /etc/localtime as is described here kubernetes/kubernetes#80577 (comment)
변경해야 할 파일은 /etc/kubernetes/manifests/kube-controller-manager.yaml
인데, 설정 변경 후에는 자동적으로 kube-controller-manager-(hostname)
pod를 다시 배포 하므로 파일만 수정하고 저장하면 된다.(restart count가 0인 걸 봐서는 단순히 restart가 아니라 기존 deployment를 제거하고 새로 deploy하는 듯 하다)
추가 해야 할 내용은 다음과 같이 host OS의 /etc/localtime
파일을 container에 마운트하는 것이다.
- mountPath: /etc/localtime
name: localtime
readOnly: true
- hostPath:
path: /etc/localtime
type: FileOrCreate
name: localtime
다시 배포된 kube-controller-manager
에 제대로 mount되었는 지 확인해 본다.
$ kubectl describe pod kube-controller-manager-mini1 -n kube-system
...
Mounts:
...
/etc/localtime from localtime (ro)
...
...
이제 kube-controller-manager
pod와 host OS의 시간을 확인해 보면 다음과 같이 같은 시간 대 임을 알 수 있다.
$ kubectl exec kube-controller-manager-mini1 -n kube-system -- /bin/date
Tue Oct 13 22:54:26 KST 2020
$ date
Tue Oct 13 22:54:27 KST 2020
이제 시간이 지나서 CronJob
이 실행된 시간을 다시 확인해 보면 이제는 설정한 대로 01:00 AM
임을 확인할 수 있다.
$ kubectl describe cronjob pocket-stat
...
Last Schedule Time: Wed, 14 Oct 2020 01:00:00 +0900
...
Alternatives
Kubernetes 커뮤니티에서 주로 추천하는 방법은 CronJob
의 schedule
을 그냥 UTC
기준으로 설정하라고.
이 경우 01:00은 전날 16:00과 같다고 하니 이렇게 설정하라는 (http://timeanddate.com/worldclock/converter.html)
Reference
- IBM Knowledge Center kube-controller-manager가 CronJob을 실행시키는 주체인데, kube-controller-manager container가 UTC 시간 기준으로 동작해서 Timezone을 고려하지 않으므로, 해당 container에 master node의 timezone 정보를 추가하면 될 거라고
- Cron Jobs migration to Kubernetes tips |It’s my SRE life
- GitHub - hiddeco/cronjobber: Cronjobber is a cronjob controller for Kubernetes with support for time zones CronJob 대신 Timezone을 지원하는 resource 를 정의