如何在Docker容器中运行cron作业?

我正在尝试在调用shell脚本的docker容器中运行cronjob。

昨天我一直在searchnetworking和堆栈溢出,但我真的找不到解决scheme。
我怎样才能做到这一点?

编辑:

我已经创build了一个(注释的)github仓库,它有一个工作的docker cron容器,它在给定的时间间隔调用一个shell脚本。

您可以将您的crontab复制到映像中,以便从映像启动的容器运行作业。

请参阅Julien Boulay在他的Ekito/docker-cron 使用Docker运行cron作业 :

我们创build一个名为“ crontab ”的新文件来描述我们的工作。

 * * * * * root echo "Hello world" >> /var/log/cron.log 2>&1 # An empty line is required at the end of this file for a valid cron file. 

以下DockerFile描述了构build图像的所有步骤

 FROM ubuntu:latest MAINTAINER docker@ekito.fr RUN apt-get update && apt-get -y install cron # Add crontab file in the cron directory ADD crontab /etc/cron.d/hello-cron # Give execution rights on the cron job RUN chmod 0644 /etc/cron.d/hello-cron # Create the log file to be able to run tail RUN touch /var/log/cron.log # Run the command on container startup CMD cron && tail -f /var/log/cron.log 

(请参阅Gaafar的评论,以及如何使apt-get安装更less噪声?
apt-get -y install -qq --force-yes cron也可以工作)


或者,确保你的工作本身直接redirect到stdout / stderr而不是日志文件,如hugoShaka的回答所述 :

  * * * * * root echo hello > /proc/1/fd/1 2>/proc/1/fd/2 

用最后的Dockerfile行replace

 CMD ["cron", "-f"] 

另见(关于cron -f ,也就是说cron“foreground”)“ docker ubuntu cron -f不工作 ”


build立并运行它:

 sudo docker build --rm -t ekito/cron-example . sudo docker run -t -i ekito/cron-example 

耐心等待2分钟,你的命令行应该显示:

 Hello world Hello world 

采用的解决scheme在生产环境中可能是危险的。

在Docker中,每个容器只应该执行一个进程,因为如果你不这样做的话,分叉和去后台的进程不会被docker监视,并且可能在你不知道的情况下停止。

当你使用CMD cron && tail -f /var/log/cron.log ,cron进程基本上是为了在后台执行cron而fork的,主进程退出并让你在前台执行tailf 。 cron进程可能停止或失败,您将不会注意到,您的容器仍将静默运行,并且您的编排工具将不会重新启动它。

您可以通过将cron的命令输出直接redirect到分别位于/proc/1/fd/1/proc/1/fd/2 docker stdoutstderr来避免这种情况。

使用基本的bash命令,你可能想要做这样的事情:

* * * * * root echo hello > /proc/1/fd/1 2>/proc/1/fd/2

而你的CMD将是: CMD ["cron", "-f"]

@VonC的build议是好的,但我更喜欢在一行中完成所有的cron作业configuration。 这将避免像cronjob位置的跨平台问题,你不需要一个单独的cron文件。

 FROM ubuntu:latest # Install cron RUN apt-get -y install cron # Create the log file to be able to run tail RUN touch /var/log/cron.log # Setup cron job RUN (crontab -l ; echo "* * * * * echo "Hello world" >> /var/log/cron.log") | crontab # Run the command on container startup CMD cron && tail -f /var/log/cron.log 

运行Docker容器后,可以确定cron服务是否正在工作:

 # To check if the job is scheduled docker exec -ti <your-container-id> bash -c "crontab -l" # To check if the cron service is running docker exec -ti <your-container-id> bash -c "pgrep cron" 

如果你更喜欢进入点而不是CMD,那么你可以用上面的CMD来代替CMD

 ENTRYPOINT cron start && tail -f /var/log/cron.log 

尽pipe这样做的目的是通过Docker的exec接口在容器的正在运行的进程旁边运行作业,但这可能会对您有所帮助。

我已经编写了一个守护进程,用于观察容器,并在它们的元数据中定义作业(在其元数据中定义)。 例:

 version: '2' services: wordpress: image: wordpress mysql: image: mariadb volumes: - ./database_dumps:/dumps labels: deck-chores.dump.command: sh -c "mysqldump --all-databases > /dumps/dump-$$(date -Idate)" deck-chores.dump.interval: daily 

“经典”,类似cron的configuration也是可能的。

这里是文档 ,这里是图像存储库 。

我创build了一个基于其他答案的docker镜像,可以像这样使用

docker run -v "/path/to/cron:/etc/cron.d/crontab" [gaafar/cron][1]

其中/path/to/cron :crontab文件的绝对path

或在Dockerfile中用作基础

 FROM gaafar/cron # COPY crontab file in the cron directory COPY crontab /etc/cron.d/crontab # Add your commands here 

VonC的答案相当彻底。 另外,我想添加一件帮助我的东西。如果你只想运行一个cron作业而不拖拽一个文件,那么你会试图从&& tail -f /var/log/cron.log中删除cron命令。 然而,这将导致docker容器在运行后立即退出,因为当cron命令完成时,docker认为最后一个命令已经退出,因此会终止容器。 这可以通过cron -f在前台运行cron来避免

我会写这个评论,但我没有足够的积分:)

还有另一种方式来做,就是使用Tasker ,一个拥有cron(调度程序)支持的任务运行者。

为什么? 有时候要运行一个cron作业,你必须把你的基本镜像(python,java,nodejs,ruby)和crond混合在一起。 这意味着要维护的另一个形象。 Tasker通过解耦crond和你的容器来避免这种情况。 您可以只关注要执行命令的映像,并将Taskerconfiguration为使用它。

这里是一个docker-compose.yml文件,它会为你运行一些任务

 version: "2" services: tasker: image: strm/tasker volumes: - "/var/run/docker.sock:/var/run/docker.sock" environment: configuration: | logging: level: ROOT: WARN org.springframework.web: WARN sh.strm: DEBUG schedule: - every: minute task: hello - every: minute task: helloFromPython - every: minute task: helloFromNode tasks: docker: - name: hello image: debian:jessie script: - echo Hello world from Tasker - name: helloFromPython image: python:3-slim script: - python -c 'print("Hello world from python")' - name: helloFromNode image: node:8 script: - node -e 'console.log("Hello from node")' 

这里有3个任务,他们都会每分钟执行一次( every: minute ),每个任务都将执行script代码,在image部分定义的image

只要运行docker-compose up ,并看到它的工作。 这是塔斯克回购与全面的文件:

http://github.com/opsxcq/tasker

在其他主机上部署容器时,请注意,它不会自动启动任何进程。 您需要确保“cron”服务在您的容器中运行。 在我们的情况下,我正在使用Supervisord和其他服务来启动cron服务。

 [program:misc] command=/etc/init.d/cron restart user=root autostart=true autorestart=true stderr_logfile=/var/log/misc-cron.err.log stdout_logfile=/var/log/misc-cron.out.log priority=998 

Cron作业存储在/ var / spool / cron / crontabs(我知道的所有发行版中都是常见的地方)。 顺便说一句,你可以使用类似的东西在bash中创build一个cron选项卡:

 crontab -l > cronexample echo "00 09 * * 1-5 echo hello" >> cronexample crontab cronexample rm cronexample 

这将使用cron任务创build一个临时文件,然后使用crontab对其进行编程。 最后一行删除临时文件。

目前我发现的最稳健的方法是运行独立的cron容器 – 安装docker客户端并绑定docker sock,以便与主机上的docker服务器通信。

然后,对每个cron作业和入口点脚本使用env vars来生成/ etc / crontab

这是我用这个原理创造的一个图像,在过去的3 – 4年里用于生产。

https://www.vip-consult.solutions/post/better-docker-cron#content