昨天我一直在网上搜索和堆栈溢出,但是我找不到真正可行的解决方案。<
我该怎么做?
编辑:
我已经创建了一个(带注释的)github存储库,其中包含正在工作的docker cron容器,该容器在给定的情况下调用Shell脚本间隔。
#1 楼
您可以将crontab复制到映像中,以使从该映像启动的容器运行该作业。请参见Julien Boulay的
Ekito/docker-cron
中的“使用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 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
(请参阅Gaafar的评论,以及如何使
apt-get
的安装减少噪音?:apt-get -y install -qq --force-yes cron
也可以工作) Nathan Lloyd在评论中指出:
关于陷阱的快速说明:
如果要添加脚本文件并告诉cron要运行它,请记住
RUN 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“ foreground”)“ 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
在映像构建期间创建,则可能无法显示正确的文件。如果是这样,您需要在容器运行时期间创建或触摸文件,以使尾部拾取正确的文件。
请参阅“未显示docker
tail -f
末尾的CMD
输出” 。#2 楼
在生产环境中,采用的解决方案可能很危险。在docker中,每个容器仅应执行一个进程,因为如果不这样做,则不会监视派生到后台的进程。
当您使用
CMD cron && tail -f /var/log/cron.log
时,cron进程基本上是为了在后台执行cron
而派生的,主进程退出并让您在前台执行tailf
。后台cron进程可能会停止或失败,您不会注意到,您的容器仍会静默运行,并且编排工具也不会重新启动它。您可以通过直接重定向来避免此类情况cron的命令输出到分别位于
stdout
和stderr
的docker /proc/1/fd/1
和/proc/1/fd/2
中。使用基本的shell重定向,您可能需要执行以下操作:
* * * * * root echo hello > /proc/1/fd/1 2>/proc/1/fd/2
您的CMD为:
CMD ["cron", "-f"]
评论
不错:cron -f用于“ cron前景”。我已将您的答案包含在我的上面,以提高可见度。 +1
–VonC
17年9月14日在14:49
假设我的程序没有输出任何东西。我是否仍可以使用此方法,并确保我的过程不会在后台停止?
–Arcsector
18年5月18日在19:34
@Arcsector此方法避免将进程放在后台,这就是为什么它不会无提示地失败的原因。在Docker容器中具有后台进程并不简单。如果要有一个正在运行的后台进程,则可能要使用一个初始化进程来监视在容器中运行的多个进程。另一种方法是将过程开始到另一个位于称为“ sidecar”的主要容器旁边的容器中。最好的方法通常是避免容器中的多个进程。
–hugoShaka
18年5月22日在14:14
好干净!爱它 :)
– AmaelH
18/12/8在17:14
这是一个很好的解决方案,除了一个问题之外,对我们来说效果很好。当容器收到SIGTERM信号时,它似乎并不等待调度的进程完成并正常关闭,而是正在杀死可能导致问题的进程。
–詹姆斯·赫尔斯(James Hulse)
1月21日11:03
#3 楼
对于那些想要使用简单轻巧的图像的人: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"]
其中cronjobs是包含您的cronjobs的文件,格式为:
* * * * * echo "hello stackoverflow" >> /test_file 2>&1
# remember to end this file with an empty new line
评论
基于简单,轻便和标准的图像。这应该是公认的答案。还可以使用> / proc / 1 / fd / 1 2> / proc / 1 / fd / 2重定向来直接从docker日志访问cronjobs输出。
– HenriTel
18年4月24日在8:24
对于不使用alpine的用户:支持-d 8参数的crond不是标准的cron,它是busybox中的crond命令。例如,在ubuntu中,您可以将其作为busybox crond -f -d 8运行。对于较旧的版本,必须使用-L / dev / stdout /。
–Trendfischer
18-4-25在13:44
如果可以的话,我会给这个+100。到目前为止,这是在Docker环境中运行cron作业的最佳方法。
–真主
18年5月16日在12:43
如果您不想每次更改cron作业时都生成新映像(或者如果需要多次),则可以运行Alpine并使用卷来设置cron。我使用以下命令对其进行了测试:docker run -v $ {PWD} / cronjobs:/ etc / crontabs / root alpine:3.6 crond -f -d 8. @Groostav您可以在Docker Compose中使用类似的东西。
– duality_
19年7月12日在7:19
CMD [“ crond”或CMD [“ cron”?
– Codesmith
6月17日13:08
#4 楼
@VonC提出的建议很好,但我更喜欢在一行中完成所有cron作业配置。这样可以避免跨平台的问题,例如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"
如果您希望使用ENTRYPOINT而不是CMD,则可以将上面的CMD替换为
ENTRYPOINT cron start && tail -f /var/log/cron.log
评论
运行apt-get update && apt-get -y install cron,否则它将无法找到软件包cron
– alphabetasoup
17年8月29日在23:08
谢谢Youness,您给了我执行以下操作的想法,该方法在我的情况下有效,其中每个cron在不同的文件中指定:RUN cat $ APP_HOME / crons / * | crontab就像一个魅力:)
– marcostvz
17年11月30日15:51
将cron添加到入口点脚本似乎是最好的选择:ENTRYPOINT [“ entrypoint.sh”]
– bozdoz
5月8日0:45
#5 楼
还有另一种方法,可以使用Tasker,它是具有cron(调度程序)支持的任务运行程序。为什么?有时要执行cron作业,您必须将基本图像(python,java,nodejs,ruby)与crond混合。这意味着要维护另一个图像。 Tasker通过分离crond和您的容器来避免这种情况。您可以只关注要执行命令的图像,然后将Tasker配置为使用它。
这是一个
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
代码。只需运行
docker-compose up
,然后查看其工作情况即可。这是Tasker仓库以及完整的文档:http://github.com/opsxcq/tasker
评论
Dockerception(从另一个容器运行docker容器)是一种不好的做法,应仅限于持续集成。一种解决方法是在指定容器上使用docker exec。
– HenriTel
18年4月23日在9:36
Tasker在docker(Dind / Dockerception)中未使用docker,请注意,将docker套接字作为映射传递,所有生成的容器都在Tasker运行的守护程序中生成。而且,如果您不想在docker内部运行tasker,则可以将其部署为其他任何应用程序。
– OPSXCQ
18年4月27日在22:17
我没有使用Tasker的优势。使用java和sh ***只是为了执行一项cron作业,对我来说似乎真的是一种矫kill过正。
–卡尔·阿德勒(Karl Adler)
18-10-30在14:59
混合cron和所需的基本映像(例如python / node)会创建一个需要维护和部署的额外依赖项,在这种情况下,所有作业共享同一容器,这意味着您必须担心在清理完所有内容之后每个工作都在运行。在Tasker上运行的作业是幂等的,因此您无需担心任何事情。
– OPSXCQ
19年1月10日在13:59
#6 楼
尽管这样做的目的是通过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的配置。
这里是文档,这里是图像存储库。 br />
评论
谢谢。这个答案最适合Docker容器环境。 Docker映像中没有任何更改,仅添加了用于执行任务的特殊容器,它按计划像命令docker exec
–PRIHLOP
19-10-6在10:25
这是最干净的“完成工作”的答案。
–易卜拉欣·阿瓦德(Ibrahim Awad)
19年11月28日在9:50
#7 楼
VonC的答案很彻底。另外,我想补充一件事。如果您只想运行cron作业而不拖尾文件,则很想从cron命令中删除&& tail -f /var/log/cron.log
。 但是,这将导致Docker容器在运行后不久退出,因为当cron命令完成时,Docker认为最后一个命令已退出,因此杀死了该容器。可以通过
cron -f
在前台运行cron来避免这种情况。#8 楼
我根据其他答案创建了一个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
作为参考,该图像位于此处。
评论
有趣的形象。 +1
–VonC
16-10-19在15:53
#9 楼
在专用容器中定义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 swarm使它正常工作。获取myservice未知错误。
– Mark Grimes
18年7月18日在17:13
应该警告有关安装Docker套接字具有很高的安全影响:lvh.io/posts/…
–休闲
19-10-22在14:28
#10 楼
如果您将docker用于Windows,请记住,如果要从Windows导入crontab文件到ubuntu容器,则必须将行尾格式从CRLF更改为LF(即从dos更改为unix)。如果没有,您的Cron工作将无法工作。这是一个工作示例:FROM ubuntu:latest
RUN apt-get update && apt-get -y install cron
RUN apt-get update && apt-get install -y dos2unix
# Add crontab file (from your windows host) to the cron directory
ADD cron/hello-cron /etc/cron.d/hello-cron
# Change line ending format to LF
RUN dos2unix /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/hello-cron.log
# Run the command on container startup
CMD cron && tail -f /var/log/hello-cron.log
这实际上花了我几个小时才能弄清楚,因为在Docker容器中调试cron作业是一项繁琐的任务。希望它可以帮助其他无法使他们的代码正常工作的人!
评论
当试图使输出重定向正常工作时,这有助于解决我的问题。像cat / proc / 1 / status> / proc / 1 / fd / 1这样的命令将从crond返回错误,指出crond:USER root pid 6 cmd root cat / proc / 1 / status> / proc / 1 / fd / 1 :不存在的目录/ proc / 1 / fd / 1。将行尾更改为Unix使我能够成功运行命令。谢谢,这花了我几个多小时才弄清楚!
– Daryl Wright
10月28日13:06
#11 楼
在其他主机上部署容器时,只需注意它不会自动启动任何进程。您需要确保容器中正在运行“ 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
评论
我在supervisor.log中收到一个错误,该错误表明cron服务已停止多次并进入了致命状态。但是,cron似乎运行在顶部并正常执行cronjobs。谢谢你!
–lephleg
17年1月14日在23:13
是的,同样的事情也发生在我身上,但它正常工作,因此无需理会。
– Sagar Ghuge
17年2月6日在10:42
#12 楼
在上面的示例中,我创建了这种组合:在Nano中使用Crontab进行高山图像和编辑(我讨厌vi)
FROM alpine
RUN apk update
RUN apk add curl nano
ENV EDITOR=/usr/bin/nano
# start crond with log level 8 in foreground, output to stderr
CMD ["crond", "-f", "-d", "8"]
# Shell Access
# docker exec -it <CONTAINERID> /bin/sh
# Example Cron Entry
# crontab -e
# * * * * * echo hello > /proc/1/fd/1 2>/proc/1/fd/2
# DATE/TIME WILL BE IN UTC
#13 楼
Cron作业存储在/ var / spool / cron / crontabs中(我知道的所有发行版中的公用位置)。顺便说一句,您可以使用以下方法在bash中创建cron选项卡:crontab -l > cronexample
echo "00 09 * * 1-5 echo hello" >> cronexample
crontab cronexample
rm cronexample
这将创建带有cron任务的临时文件,然后使用crontab对其进行编程。最后一行删除临时文件。
评论
cron守护程序通常不在容器中运行。
–马特
16年5月26日在11:28
@BhargavNanekalva,需要在此答案无法解决的容器中进行专门设置。
–马特
17年4月1日在16:33
@Matt,能否请您指出在容器中应如何指定? 。我执行crontab -l并显示命令-kagda.ru/i/6d014816d43_29-06-2017-11:38:59_6d01.png但仍然无法运行
–Tebe
17-6-29在8:38
@Копать_Шо_я_нашел除了必须在容器中运行的服务之外,还必须运行crond,通常使用s6之类的服务管理器。大概问这个问题以获得正确答案
–马特
17-6-29在10:06
#14 楼
在限制根访问权限的某些精简映像上运行时,我不得不将用户添加到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
也许可以帮助某人
评论
我相信节点映像使用节点用户;所以也许您需要为该用户添加权限
– bozdoz
5月8日0:44
#15 楼
与一次性作业并行设置cron使用应该定期运行的作业创建脚本文件(例如run.sh)。
#!/bin/bash
timestamp=`date +%Y/%m/%d-%H:%M:%S`
echo "System path is $PATH at $timestamp"
保存并退出。
使用Entrypoint代替CMD
如果在Docker容器化过程中有多个任务需要执行,请使用Entrypoint文件运行它们全部。
入口点文件是一个脚本文件,在发出docker run命令时生效。因此,我们要运行的所有步骤都可以放在此脚本文件中。例如,我们有2个作业要运行:
运行一次作业:echo“ Docker容器已启动”
运行定期作业:run.sh
创建entrypoint.sh
#!/bin/bash
# Start the run once job.
echo "Docker container has been started"
# Setup a cron schedule
echo "* * * * * /run.sh >> /var/log/cron.log 2>&1
# This extra line makes it a valid cron" > scheduler.txt
crontab scheduler.txt
cron -f
我们来了解一下在文件中设置的crontab
* * * * *
:Cron时间表;该作业必须每分钟运行一次。您可以根据自己的要求更新时间表。/run.sh
:要定期运行的脚本文件的路径/var/log/cron.log
:用于保存脚本输出的文件名计划的cron作业。2>&1
:错误日志(如果有的话)也将重定向到上面使用的相同输出文件。注意:不要忘记添加额外的内容换行,因为它使它成为有效的cron。
Scheduler.txt
:完整的cron设置将重定向到文件。在cron中使用系统/用户特定的环境变量
我实际的cron工作期望将大多数参数作为环境变量传递给docker run命令。但是,使用bash时,我无法使用属于系统或docker容器的任何环境变量。
然后,这是该问题的解决方法:
在入口点中添加以下行。sh
declare -p | grep -Ev 'BASHOPTS|BASH_VERSINFO|EUID|PPID|SHELLOPTS|UID' > /container.env
更新cron设置并指定-
SHELL=/bin/bash
BASH_ENV=/container.env
最后,您的
entrypoint.sh
应该看起来像#!/bin/bash
# Start the run once job.
echo "Docker container has been started"
declare -p | grep -Ev 'BASHOPTS|BASH_VERSINFO|EUID|PPID|SHELLOPTS|UID' > /container.env
# Setup a cron schedule
echo "SHELL=/bin/bash
BASH_ENV=/container.env
* * * * * /run.sh >> /var/log/cron.log 2>&1
# This extra line makes it a valid cron" > scheduler.txt
crontab scheduler.txt
cron -f
最后但并非最不重要的一点:创建一个Dockerfile
FROM ubuntu:16.04
MAINTAINER Himanshu Gupta
# Install cron
RUN apt-get update && apt-get install -y cron
# Add files
ADD run.sh /run.sh
ADD entrypoint.sh /entrypoint.sh
RUN chmod +x /run.sh /entrypoint.sh
ENTRYPOINT /entrypoint.sh
就这样。构建并运行Docker映像!
评论
@himanshuIIITian我尝试过这个问题,问题是“一次性运行”的脚本永远不会返回,而且玉米-f不会返回,所以...这对我不起作用,有什么想法吗?谢谢
–多伦·列维(Doron Levi)
5月19日8:54
@DoronLevi-能否请您分享一些日志以调查问题?或者您可以从这里检查整个代码-github.com/nehabhardwaj01/docker-cron
–himanshuIIITian
5月19日10:28
感谢您的反馈。我很高兴这个答案很有帮助。
–himanshuIIITian
5月21日6:29
#16 楼
这是我基于docker-compose
的解决方案: cron:
image: alpine:3.10
command: crond -f -d 8
depends_on:
- servicename
volumes:
- './conf/cron:/etc/crontabs/root:z'
restart: unless-stopped
cron条目所在的行在
./conf/cron
文件上。注意:这不会运行
alpine
映像上没有的命令。#17 楼
这行是帮助我执行预定任务的行。ADD mycron/root /etc/cron.d/root
RUN chmod 0644 /etc/cron.d/root
RUN crontab /etc/cron.d/root
RUN touch /var/log/cron.log
CMD ( cron -f -l 8 & ) && apache2-foreground # <-- run cron
我的项目在内部运行:FROM php:7.2-apache
#18 楼
所以,我的问题是一样的。解决方法是更改docker-compose.yml
中的命令部分。从
命令:crontab / etc / crontab && tail -f / etc / crontab
执行
命令:crontab / etc / crontab
命令:tail -f / etc / crontab
问题出在'&&'在命令之间。删除后,一切都很好。
#19 楼
我到目前为止发现的最可靠的方法是运行一个独立的cron容器-安装docker客户端并绑定安装docker sock,以便您可以与主机上的docker服务器通信。然后只使用env vars对于每个cron作业和一个生成/ etc / crontab的入口点脚本
这是我使用此原理创建的图像,并在过去3-4年中用于生产。
https://www.vip-consult.solutions/post/better-docker-cron#content
评论
答案应自成体系,不得与外部资源链接
–尼古拉斯·布里亚恩(Nicolas Bouliane)
17年6月24日在13:02
#20 楼
尝试使用发条gem安排任务。请遵循此链接中提供的步骤。http://fuzzyblog.io/blog/rails/2017/05/11/adding-cron-to-a-dockerized-rails-application-using- clockwork.html
您可以按以下方式在lib / clock.rb文件中调用rake任务。
every(1.day, 'Import large data from csv files', :at => '5:00') do |job|
`rake 'portal:import_data_from_csv'`
end
在docker中创建一个单独的容器-compose file并在容器内运行以下命令。
command: bundle exec clockwork lib/clock.rb
评论
使用其他工具进行计划的好主意。但是,这个问题是专门要求cron的,因此,我认为,建议对这个问题进行评论会更好。
–理查德·基弗(Richard Kiefer)
19年9月11日在7:58
评论
我必须首先安装cron,因为它不包括在内。但是通过将其添加到Dockerfile中,它可以工作。谢谢!运行apt-get update && apt-get install cron
–C Heyer
16年5月26日在12:15
您可能应该在安装cron时添加-y以避免docker build退出
–加菲
16-10-16在7:41
此解决方案仍然有效吗?当我遵循给出的准则时,当我以root用户身份登录到容器并键入crontab -l时,我没有为root用户安装crontab,而且,我的屏幕仍然空白。但是,当我检查'/etc/cron.d/'时,我看到crontab文件存在(甚至更令人惊讶),当我检查/var/log/cron.log时,我看到脚本正在运行(文件内容随Hello World一起添加)。我正在Dockerfile中提取此映像:FROM phusion / baseimage:0.10.0。关于行为差异有什么想法吗?
– Ho
18年2月2日在16:30
从2018年开始,这种方法不再有效;有没有人能够使他们的cronjob与Ubuntu作为基本映像一起工作?我对cron开箱即用的Alpine图片不感兴趣
– pelican
18年7月26日在19:57
关于陷阱的快速说明:如果要添加脚本文件并告诉cron运行它,请记住运行chmod 0744 / the_script。如果忘记了,Cron会自动失败。
–内森·劳埃德(Nathan Lloyd)
3月18日,0:42