我试图在调用shell脚本的docker容器内运行cronjob。

昨天我一直在网上搜索,堆栈溢出,但我真的找不到一个有效的解决方案。 我该怎么做呢?


当前回答

虽然这旨在通过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一样的配置也是可能的。

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

其他回答

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


重要提示:docker-cron问题3中提到:cron文件使用LF,而不是CRLF。


参见Julien Boulay在他的Ekito/ Docker -cron中的“Run a cron job with Docker”:

让我们创建一个名为“hello-cron”的新文件来描述我们的工作。

# must be ended with a new line "LF" (Unix) and not "CRLF" (Windows)
* * * * * 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.

如果你想知道什么是2>&1,Ayman Hourieh解释道。

下面的Dockerfile描述了构建映像的所有步骤

FROM ubuntu:latest
MAINTAINER docker@ekito.fr

RUN apt-get update && apt-get -y install cron

# Copy hello-cron file to the cron.d directory
COPY hello-cron /etc/cron.d/hello-cron
 
# Give execution rights on the cron job
RUN chmod 0644 /etc/cron.d/hello-cron

# Apply cron job
RUN crontab /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

但是:如果cron死亡,容器将继续运行。

(见Gaafar的评论和我如何使apt-get安装噪音更小?: Apt-get -y install -qq——force-yes cron也可以工作)

正如Nathan Lloyd在评论中所指出的:

关于一个问题的简单说明: 如果您正在添加一个脚本文件并告诉cron运行它,请记住这样做 运行chmod 0744 /the_script 如果你忘记了,Cron会默默地失败。


或者,确保你的作业本身直接重定向到stdout/stderr,而不是一个日志文件,如hugoShaka的回答所述:

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

将最后一行Dockerfile替换为

CMD ["cron", "-f"]

但是:如果你想以非根用户的身份运行任务,它就不起作用了。

参见(关于cron -f,这是说cron“前景”)“docker ubuntu cron -f不能正常工作”


构建并运行它:

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

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

Hello world
Hello world

Eric在评论中补充道:

请注意,如果tail是在映像构建期间创建的,那么它可能不会显示正确的文件。 如果是这种情况,您需要在容器运行时创建或触摸该文件,以便tail获得正确的文件。

参见“docker CMD末尾的tail -f输出不显示”。


更多信息请参见Jason Kulatunga的“在Docker中运行Cron”(2021年4月),他在下面评论道

参见Jason的图片AnalogJ/docker-cron基于:

Dockerfile安装cronie/crond,取决于发行版。 一个入口点初始化/etc/environment,然后调用 Cron -f -l 2

当在一些限制根访问的经过修剪的映像上运行时,我必须将我的用户添加到sudoers并作为sudo cron运行

FROM node:8.6.0
RUN apt-get update && apt-get install -y cron sudo

COPY crontab /etc/cron.d/my-cron
RUN chmod 0644 /etc/cron.d/my-cron
RUN touch /var/log/cron.log

# Allow node user to start cron daemon with sudo
RUN echo 'node ALL=NOPASSWD: /usr/sbin/cron' >>/etc/sudoers

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

也许这对某人有帮助

但是:如果cron死亡,容器将继续运行。

这个问题有很多答案,但有些很复杂,另一些有一些缺点。我试着解释问题并提出解决方案。

cron-entrypoint.sh:

#!/bin/bash

# copy machine environment variables to cron environment
printenv | cat - /etc/crontab > temp && mv temp /etc/crontab

## validate cron file
crontab /etc/crontab

# cron service with SIGTERM support
service cron start
trap "service cron stop; exit" SIGINT SIGTERM

# just dump your logs to std output
tail -f  \
    /app/storage/logs/laravel.log \
    /var/log/cron.log \
    & wait $!

解决问题

环境变量在cron环境中不可用(如env vars或kubernetes secrets) 当crontab文件无效时停止 当机器接收到SIGTERM信号时,优雅地停止cron作业

作为上下文,我在Kubernetes上使用Laravel应用程序使用之前的脚本。

在专用容器中定义cronjob,该容器通过docker exec向服务运行命令。

这是更高的内聚性,运行脚本将能够访问为服务定义的环境变量。

#docker-compose.yml
version: "3.3"
services:
    myservice:
      environment:
        MSG: i'm being cronjobbed, every minute!
      image: alpine
      container_name: myservice
      command: tail -f /dev/null

    cronjobber:
     image: docker:edge
     volumes:
      - /var/run/docker.sock:/var/run/docker.sock
     container_name: cronjobber
     command: >
          sh -c "
          echo '* * * * * docker exec myservice printenv | grep MSG' > /etc/crontabs/root
          && crond -f"

我根据其他答案创建了一个Docker映像,可以像这样使用

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

/path/to/cron: crontab文件的绝对路径,或者你可以在Dockerfile中使用它作为基础文件:

FROM gaafar/cron

# COPY crontab file in the cron directory
COPY crontab /etc/cron.d/crontab

# Add your commands here

作为参考,图片在这里。