【问题标题】:Docker cron scheduled job not runningDocker cron计划作业未运行
【发布时间】:2021-08-01 10:40:28
【问题描述】:

我正在尝试使用基于 Alpine 映像的 docker 容器来运行计划的 cron 作业,遵循此 tutorial,但在我的启动脚本中打印了该语句后,容器就退出了,而没有运行我的其他脚本。

我的docker-compose服务配置如下:

  cron:
    image: alpine:3.11
    command: /usr/local/startup.sh && crond -f -l 8
    volumes:
      - ./cron_tasks_folder/1min:/etc/periodic/1min/:ro
      - ./cron_tasks_folder/15min:/etc/periodic/15min/:ro
      - ./cron_tasks_folder/hourly:/etc/periodic/hourly/:ro
      - ./scripts/startup.sh:/usr/local/startup.sh:ro

所以它运行一个名为startup.sh 的初始脚本,然后启动 cron 守护进程。 startup.sh 脚本包含以下内容:

#!/bin/sh

echo "Starting startup.sh.."
echo "*       *       *       *       *       run-parts /etc/periodic/1min" >> /etc/crontabs/root
crontab -l
sleep 300

我在那里放了一个 sleep 命令,这样我就可以在容器上启动一个交互式 shell 并确保它里面的所有东西看起来都很好。该脚本为 1 分钟脚本创建另一个文件夹。我在那里添加了一个测试脚本,我可以验证它在那里:

/etc/periodic/1min # ls -a
.           ..          testScript

脚本是可执行的:

/etc/periodic/1min # ls -l testScript 
-rwxr-xr-x    1 root     root            31 Jul 30 01:51 testScript

而testScript 只是一个回显语句,以确保它首先工作:

echo "The donkey is in charge"

查看 etc/crontabs 中的root 文件,我看到以下内容(我已经多次重新运行容器,每次它都创建一个新的 1min 文件夹,这是不必要的,但我认为不是这里的问题):

# do daily/weekly/monthly maintenance
# min   hour    day     month   weekday command
*/15    *       *       *       *       run-parts /etc/periodic/15min
0       *       *       *       *       run-parts /etc/periodic/hourly
0       2       *       *       *       run-parts /etc/periodic/daily
0       3       *       *       6       run-parts /etc/periodic/weekly
0       5       1       *       *       run-parts /etc/periodic/monthly

*       *       *       *       *       run-parts /etc/periodic/1min
*       *       *       *       *       run-parts /etc/periodic/1min
*       *       *       *       *       run-parts /etc/periodic/1min
*       *       *       *       *       run-parts /etc/periodic/1min
*       *       *       *       *       run-parts /etc/periodic/1min

testScript 中的 echo 语句从未打印到我的终端,并且容器在启动后不久以退出代码 0 退出。我想每分钟打印一次这个声明......我错过了什么?

【问题讨论】:

  • 您认为您在哪里启动 cron 调度程序? crontab -l 列出 cron 作业,但它不会启动调度程序。根据您提供的数据,我会说您实际上并没有启动 cron。
  • @DanielFarrell 我的理解是 docker-compose 的 command 中的 && crond -f -l 8 正在这样做。
  • 好吧,没错,我错过了。但是startup.sh 必须在运行command 的shell 执行crond 之前退出。你在等那5分钟吗?如果我是你,我会用exec crond -f -l 8 代替startup.sh 中的sleep。如果这不起作用,请确保您正在检查 docker 日志。
  • 行得通!我现在收到以下错误,但这是一个不同的问题:run-parts: can't execute '/etc/periodic/1min/testScript': Exec format error。话虽如此,我也可以从我的 docker-compose 命令中删除&& crond -f -l 8。这种配置是可接受的做法吗?如果你想回复这个答案,我会接受。谢谢。
  • 我会提供一个真实的答案。您能否在您的 dockerfile 中提供ENTRYPOINT(如果有)?

标签: linux docker docker-compose cron


【解决方案1】:

在你拥有的 docker compose 文件中

    command: /usr/local/startup.sh && crond -f -l 8

目的是作为 shell 命令运行,但从问题中根本不清楚会发生什么;这取决于您的ENTRYPOINT。由于它是用[] 括号定义的,因此不会提供额外的shell。 command 值将作为参数传递给 ENTRYPOINT。

假设 将 成为一个 shell 命令,shell 中的&& 运行左侧,如果成功,则运行右侧。所以startup.sh 需要在crond 执行之前完成。 startup.sh 以

结尾
sleep 300

crond 仅在 300 秒之后被调用。

在任何一种情况下,crond 要么根本没有被调用,要么 sleep 尚未完成。 cmets 显示发现了一个以crond 开头的错误。

使用诸如此类的入口点是在调用主可执行文件之前配置环境或提供运行时参数的标准做法。要正确执行此操作,您应该确保使用 exec 运行主可执行文件,以便它接收信号,否则这些信号会转到运行入口点脚本的 bash shell。

所以最后startup.sh:

exec crond -f -l 8

将替换运行startup.sh 的shell 为crond,以便crond 接收所有信号(此时shell 已消失)。这很微妙但很重要!

一般来说,应用程序的调用应尽可能简单。例如,您的执行过程在入口点、命令和启动脚本之间进行了拆分,它们之间没有明确的接口。如果您将 crond 直接放入 Dockerfile 并将其保留在那里,您就不会挂断调用。有时必须在运行时提供参数,但环境变量(具有名称,而不仅仅是位置)通常是首选。这使调用简单且调试简单。但是,当这不起作用时,shell 脚本入口点是一个很好的解决方案 - 只需确保 exec 您的最终进程!

【讨论】:

  • 您可以考虑以exec "$@" 结束入口点脚本,然后设置CMD crond -f -l 8。这将具有相同的实际效果,除了您可以 docker run --rm -it your-image sh 运行入口点设置脚本,但以交互式 shell 而不是 cron 守护程序结束,或者在首次设置后启动一些替代命令。
  • 重要的是要注意,我的最终错误已通过在脚本顶部添加 #!/bin/sh shebang 而不仅仅是 echo 语句本身来解决。
猜你喜欢
  • 2010-09-12
  • 1970-01-01
  • 2016-03-06
  • 1970-01-01
  • 2017-11-10
  • 2017-04-17
  • 2016-06-12
  • 1970-01-01
相关资源
最近更新 更多