简体   繁体   English

Docker cron 计划作业未运行

[英]Docker cron scheduled job not running

I am trying to use a docker container based on an Alpine image to run a scheduled cron job, following this tutorial , but after printing the statement in my startup script, the container just exits, without running my other script.我正在尝试使用基于 Alpine 映像的 docker 容器来运行计划的 cron 作业,遵循本教程,但是在我的启动脚本中打印语句后,容器只是退出,而没有运行我的其他脚本。

My docker-compose service is configured as follows:我的 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

So it runs an initial script called startup.sh and then starts the cron daemon.所以它运行一个名为startup.sh的初始脚本,然后启动 cron 守护进程。 The startup.sh script contains the following: startup.sh脚本包含以下内容:

#!/bin/sh

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

I dropped a sleep command in there just so I could launch an interactive shell on the container and make sure everything inside it looks good.我在里面放了一个 sleep 命令,这样我就可以在容器上启动一个交互式 shell 并确保里面的所有东西看起来都很好。 The script creates another folder for 1min scripts.该脚本为 1 分钟脚本创建了另一个文件夹。 I have added a test script in there, and I can verify it's there:我在那里添加了一个测试脚本,我可以验证它在那里:

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

The script is executable:该脚本是可执行的:

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

And testScript is just an echo statement to make sure it's working first:testScript只是一个 echo 语句,以确保它首先工作:

echo "The donkey is in charge"

And looking at the root file in etc/crontabs, I see the following (I've re-run the container several times, and each time it's creating a new 1min folder, which is unnecessary, but I think not the problem here):查看 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

The echo statement in testScript is never printed to my terminal, and the container exits with exit code 0 shortly after starting. testScript的 echo 语句永远不会打印到我的终端,并且容器在启动后不久以退出代码 0 退出。 I want to print this statement every minute... what am I missing?我想每分钟打印一次这个声明......我错过了什么?

In the docker compose file you have在 docker compose 文件中,你有

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

The intention is to run as a shell command, but it's not at all clear from the question that's what's going to happen;目的是作为一个 shell 命令运行,但从问题中完全不清楚会发生什么; that depends on your ENTRYPOINT .这取决于您的ENTRYPOINT Since it's defined with [] brackets, not additional shell will be provided.因为它是用[]括号定义的,所以不会提供额外的 shell。 The command value will be passed as arguments to the ENTRYPOINT . command值将作为参数传递给ENTRYPOINT

Assuming that will become a shell command, && in the shell runs the left hand side, and if that succeeds, then runs the right hand side.假设这成为一个 shell 命令,shell 中的&&运行左侧,如果成功,则运行右侧。 So startup.sh needs to complete before crond is executed.所以startup.sh需要crond执行之前完成。 startup.sh ends with startup.sh

sleep 300

crond is invoked only after that 300 seconds. crond300 秒调用。

In either case, crond is either not invoked at all, or sleep has not been completing.在任何一种情况下, crond要么根本没有被调用,要么sleep没有完成。 The comments show that an error starting crond was discovered.评论显示发现了启动crond的错误。

Using an entrypoint such as this is standard practice to configure the environment before, or provide runtime parameters when, invoking the main executable.使用这样的入口点是在调用主可执行文件之前配置环境或提供运行时参数的标准做法。 To do it right, you should make sure to use exec to run the main executable so that it receives the signals that would otherwise go to the bash shell running the entrypoint script.要做到这一点,您应该确保使用exec来运行主可执行文件,以便它接收信号,否则这些信号将进入运行入口点脚本的 bash shell。

So at the end of startup.sh :所以在startup.sh的末尾:

exec crond -f -l 8

Will replace the shell running startup.sh with crond , so that crond receives all signals (at this point the shell is gone).将使用crond替换运行startup.sh的外壳,以便crond接收所有信号(此时外壳消失了)。 It's subtle but important!这很微妙但很重要!

In general, keep the invocation of the application as simple as possible.通常,使应用程序的调用尽可能简单。 Case in point, your execution process was split between entrypoint, command, and startup script, with no clear interface between them.举个例子,你的执行过程被分割成入口点、命令和启动脚本,它们之间没有明确的接口。 You wouldn't have gotten hung up on the invocation if you had put crond directly into the Dockerfile and left it at that.如果您将crond直接放入 Dockerfile 并将其留在那里,您就不会挂断调用。 Sometimes arguments must be provided at runtime, but environment variables - which have names , not just positions - are often preferred.有时必须在运行时提供参数,但环境变量 - 具有名称,而不仅仅是位置 - 通常是首选。 This keeps invocations simple and debugging straightforward.这使调用保持简单且调试简单。 But, when that doesn't work, a shell script entrypoint is a great solution - just make sure to exec your final process!但是,当这不起作用时,shell 脚本入口点是一个很好的解决方案 - 只需确保exec您的最终进程即可!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM