如何让 CronJob 尊重夏令时?
Posted
技术标签:
【中文标题】如何让 CronJob 尊重夏令时?【英文标题】:How to make CronJob respect daylight saving time? 【发布时间】:2019-06-17 14:55:42 【问题描述】:假设我和我正在处理的合作伙伴公司生活在一个雇用Daylight Saving Time 的国家/地区。
我在 Kubernetes 集群中有一个 CronJob,它每天在 4:00、10:00、16:00 和 22:00 将文件上传到合作伙伴公司。例如。 0 4,10,16,22 * * *
.
Kubernetes SIG decided 表明 CronJob 对象将不支持本地时区,并且将始终以默认时区运行,即 UTC。
我可以更改时间表,使其反映上面指定的 UTC 本地时间,并为 CronJob 提供该时间表。但是,每次夏令时开始(一年两次)时,我都需要以某种方式修改所有 CronJobs 以使用新时间,并且我需要修改我的部署管道以创建 CronJobs 的新版本新的时间。
我无法让 CronJob 在夏令时更改后按相同的计划运行,因为该作业将在合作伙伴预期的时间内上传文件。
最简单的管理方法是什么?
选项 1
suggested 可以编写一个新的 kubernetes 控制器,但似乎没有人提出这个挑战并发布了可行的解决方案。
选项 2
我考虑过的另一个选项是更改整个集群的时区。但是如果你google it这似乎不是一个非常流行的解决方案,并且有些人强烈认为kubernetes作为一个云应用程序应该在UTC中运行。
据我了解cron
使用本地时区,在 kubernetes 的情况下将是控制器管理器的时区,这不是它运行的节点的时区。另一方面,更改控制器管理器容器的时区听起来很冒险,因为尚不清楚它将如何与 kubernetes 的其他组件(例如 etcd 和 kubelets)进行交互。
选项 3
每年手动执行两次。由于组织中的人来来去去,因此很难在何时以及如何保留知识。我不希望我们的合作伙伴一年抱怨两次。此外,由于日期每年都在变化,因此为此设置通知可能会很棘手。
选项 4
编写一些自产自销的自动化程序,每年运行两次,并希望到时候能按预期工作。这实际上是触发器,在正确的时间触发并完成它应该做的一切。 (后者更容易测试,但前者更难)。
所有这些选项都让人很不满意。我google了很多,我没有找到很多,我觉得这应该是很常见的问题,但搜索中没有出现。我忽略了什么吗?有没有简单自然的方法来解决?
【问题讨论】:
选项 2,即在处理需要此类时间协调的解决方案时遵循 UTC 设置。在您的情况下,您无需担心时间何时向前/向后移动 @RaunakJhawar 我对它会起作用的信心很低,因为我没有发现任何报告表明它曾在相当长的一段时间内适用于类似生产环境的任何人,而且有很多运动部件。 如果不采用 UTC,则没有自然的方法可以使 cron 选项卡尊重 DST。 有人写了这个:github.com/hiddeco/cronjobber 当涉及到人类并且他们使用本地时间时,仅使用 UTC 的 cmets 是不正确的,例如,在早上 8 点发送电子邮件报告的 cron 作业。我的一种解决方法是我已经修改了我的 cron 作业以每小时触发一个 bash 脚本,如果预期的本地时间是正确的(例如东部标准时间早上 6 点),那么我在那之后触发预期的作业,否则脚本就会退出。 【参考方案1】:我知道这是一个老问题,但 argo 工作流有一个支持时区和夏令时的 Cron Workflows CRD。 https://argoproj.github.io/argo-workflows/cron-workflows/#daylight-saving.
【讨论】:
【参考方案2】:也许我来晚了一点,但我相信最简单的方法是让两个 cronjobs 与 tz-check
结合运行。当时区与预期值匹配时,才运行command
一个很好的检测Daylight Saving Time的帖子,可以找到here。复制其示例,我们可以证明对于时区 TZ=Europe/Stockholm,时区会根据日期更改为夏令时:
$ TZ=Europe/Stockholm date +%Z # CET or CEST depending of when its run
$ TZ=Europe/Stockholm date --date=20170101 +%Z # CET
$ TZ=Europe/Stockholm date --date=20170601 +%Z # CEST
$ TZ=CET date --date=20170101 +%Z # CET
$ TZ=CET date --date=20170601 +%Z # CEST, note that its auto adjusted to CEST
因此,当停留在此示例中并假设 OP 希望根据我们是否在 DST 中在不同时间运行他的 cron 时,我们可以编写以下 crontab:
# Example of job definition:
# .--------------------- minute (0 - 59)
# | .---------------- hour (0 - 23)
# | | .---------- day of month (1 - 31)
# | | | .------- month (1 - 12) OR jan,feb,mar,apr ...
# | | | | .---- day of week (0 - 6) (Sunday=0 or 7)
# | | | | |
# command only runs in Europe/Stockholm Winter time
0 4-23/6 * * * tz-test "Europe/Stockholm" "CET" && command
# command only runs in Europe/Stockholm Summer time
0 3-23/6 * * * tz-test "Europe/Stockholm" "CEST" && command
这里,crontab 定义中的时间以 UTC 给出(因为 cron 在 UTC 中运行),tz-test
命令类似于:
#!/usr/bin/env bash
tz=$(TZ="$1" date "+%Z")
[ "$tz" == "$2" ]
注意:这里你还是要小心。由于时间选择,您的 crontab 可能会在时间更改的当天运行两次甚至更多次。在上面的例子中,情况并非如此。
注意:虽然这个问题是针对 Kubernetes 的,但我确信可以在该框架内实现类似的实现。
【讨论】:
while this question was for Kubernetes, I'm convinced a similar implementation can be achieved within that framework
好像有点没有根据。整个问题在于如何实现 CronJob 控制器,而不是在 pod/OS 级别。他们最近做了一些改变来改善这一点,see my answer【参考方案3】:
时区已添加到 Kubernetes 1.22 中的 CronJob。引用github thread
澄清一下,它在 1.22 中可用。
不过,它以一种非常奇怪的方式实现,并没有在架构中公开。我不知道为什么会这样做,它忽略了 Kubernetes 背后的核心概念。我认为这还需要改进。
可以通过CRON_TZ
变量来完成,如here 所述。
# ┌────────────────── timezone (optional)
# | ┌───────────── minute (0 - 59)
# | │ ┌───────────── hour (0 - 23)
# | │ │ ┌───────────── day of the month (1 - 31)
# | │ │ │ ┌───────────── month (1 - 12)
# | │ │ │ │ ┌───────────── day of the week (0 - 6) (Sunday to Saturday;
# | │ │ │ │ │ 7 is also Sunday on some systems)
# | │ │ │ │ │
# | │ │ │ │ │
# CRON_TZ=UTC * * * * *
更新
此功能将被标记为unsupported
【讨论】:
这定义了控制器工作的时区。这不会解决 DST 问题,除非它接受值例如“欧洲/维也纳”。以上是关于如何让 CronJob 尊重夏令时?的主要内容,如果未能解决你的问题,请参考以下文章