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

问题描述 投票:172回答:15

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

昨天我一直在网上搜索和堆栈溢出,但我真的找不到一个有效的解决方案。 我怎样才能做到这一点?

编辑:

我创建了一个带有工作的docker cron容器的(commented) github repository,它以给定的间隔调用shell脚本。

docker cron containers sh
15个回答
245
投票

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

在他的Run a cron job with Docker中查看来自Julien Boulay的“Ekito/docker-cron”:

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

* * * * * 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描述了构建映像的所有步骤

FROM ubuntu:latest
MAINTAINER [email protected]

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

(参见GaafarcommentHow do I make apt-get install less noisy?apt-get -y install -qq --force-yes cron也可以工作)


或者,确保您的作业本身直接重定向到stdout / stderr而不是日志文件,如hugoShakaanswer中所述:

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

用上面的替换最后一个Dockerfile行

CMD ["cron", "-f"]

另见(关于cron -f,也就是说cron“前景”)“docker ubuntu cron -f is not working


构建并运行它:

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

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

Hello world
Hello world

Eric添加in the comments

请注意,如果在图像构建期间创建了tail,则Output of tail -f at the end of a docker CMD is not showing可能无法显示正确的文件。 如果是这种情况,您需要在容器运行时创建或触摸该文件,以便尾部获取正确的文件。

见“CMD cron && tail -f /var/log/cron.log”。


4
投票

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

这是更高的内聚力,运行脚本可以访问您为服务定义的环境变量。

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

0
投票

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

sudo cron

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


0
投票

当运行一些限制root访问的精简图像时,我不得不将我的用户添加到sudoers并运行为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

docker-compose.yml

也许这有助于某人


0
投票

所以,我的问题是一样的。解决方法是更改​​https://www.vip-consult.solutions/post/better-docker-cron#content中的命令部分。

命令:crontab / etc / crontab && tail -f / etc / crontab

命令:crontab / etc / crontab

命令:tail -f / etc / crontab

问题是命令之间的'&&'。删除后,一切都很好。


-1
投票

到目前为止我发现的最强大的方法是运行一个独立的cron容器 - 安装docker客户端并绑定mounter docker sock,这样你就可以与主机上的docker服务器通信。

然后只需为每个cron作业使用env vars,并使用入口点脚本生成/ etc / crontab

这是我使用这个原理创建的图像,并在过去3 - 4年中在生产中使用它。

http://fuzzyblog.io/blog/rails/2017/05/11/adding-cron-to-a-dockerized-rails-application-using-clockwork.html


-1
投票

尝试使用clockwork gem来安排任务。请按照此链接中提供的步骤操作。

every(1.day, 'Import large data from csv files', :at => '5:00') do |job| `rake 'portal:import_data_from_csv'` end

您可以在lib / clock.rb文件中调用rake任务,如下所示。

command: bundle exec clockwork lib/clock.rb

在docker-compose文件中创建一个单独的容器,并在容器内运行以下命令。

qazxswpoi

92
投票

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

在docker中,每个容器只应执行一个进程,因为如果不这样做,则不会监视分叉并进入后台的进程,并且可能会在您不知情的情况下停止。

当你使用cron cron进程基本上为了在后台执行tailf时,主进程退出并让你在前台执行stdout。后台cron进程可能会停止或失败,您将不会注意到,您的容器仍将以静默方式运行,并且您的业务流程工具将不会重新启动它。

您可以通过将cron的命令输出直接重定向到分别位于stderr/proc/1/fd/1的docker /proc/1/fd/2* * * * * root echo hello > /proc/1/fd/1 2>/proc/1/fd/2 来避免这种情况。

使用基本的shell重定向,您可能希望执行以下操作:

CMD ["cron", "-f"]

你的CMD将是:FROM alpine:3.6 # copy crontabs for root user COPY config/cronjobs /etc/crontabs/root # start crond with log level 8 in foreground, output to stderr CMD ["crond", "-f", "-d", "8"]


37
投票

对于那些想要使用简单轻量图像的人:

* * * * * echo "hello stackoverflow" >> /test_file 2>&1
# remember to end this file with an empty new line

其中cronjobs是包含cronjobs的文件,其形式如下:

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

26
投票

@VonC建议的很好,但我更喜欢在一行中完成所有cron作业配置。这样可以避免像cronjob位置这样的跨平台问题,并且您不需要单独的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"

运行docker容器后,您可以确保cron服务是否正常工作:

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

如果您希望使用ENTRYPOINT而不是CMD,那么您可以用上面的CMD代替

Tasker

13
投票

还有另外一种方法,就是使用docker-compose.yml,一个具有cron(调度程序)支持的任务运行器。

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

这里有一个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")' 文件,它将为您运行一些任务

every: minute

那里有3个任务,所有这些任务都会每分钟运行一次(script),并且每个任务都将在image部分中定义的图像内执行docker-compose up代码。

只需运行http://github.com/opsxcq/tasker,看看它是否有效。这是Tasker repo的完整文档:

VonC's


11
投票

&& tail -f /var/log/cron.log答案非常彻底。另外我想添加一件对我有帮助的东西。如果你只是想在不拖尾文件的情况下运行一个cron作业,那么你很想从cron命令中删除cron -f

但是这会导致Docker容器在运行后立即退出,因为当cron命令完成时,Docker认为最后一个命令已经退出并因此杀死了容器。这可以通过docker run -v "/path/to/cron:/etc/cron.d/crontab" gaafar/cron在前台运行cron来避免。


6
投票

我根据其他答案创建了一个Docker镜像,可以像

/path/to/cron

其中FROM gaafar/cron # COPY crontab file in the cron directory COPY crontab /etc/cron.d/crontab # Add your commands here :crontab文件的绝对路径,或者您可以将它用作Dockerfile中的基础:

is here

供参考,图像为[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


4
投票

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

exec

4
投票

虽然这旨在通过Docker的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 界面在容器中运行进程旁边运行作业,但这可能对您有用。

我编写了一个守护进程,它监视容器并调度在其元数据中定义的作业。例:

docs

'经典',类似cron的配置也是可能的。

这里是image repository,这里是#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"

© www.soinside.com 2019 - 2024. All rights reserved.