我试图在一个调用shell脚本的docker容器中运行一个cronjob。
昨天我一直在网上搜索和堆栈溢出,但我真的找不到一个有效的解决方案。 我怎样才能做到这一点?
编辑:
我创建了一个带有工作的docker cron容器的(commented) github repository,它以给定的间隔调用shell脚本。
您可以将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
(参见Gaafar的comment和How do I make apt-get
install less noisy?:
apt-get -y install -qq --force-yes cron
也可以工作)
或者,确保您的作业本身直接重定向到stdout / stderr而不是日志文件,如hugoShaka的answer中所述:
* * * * * 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
请注意,如果在图像构建期间创建了
tail
,则Output oftail -f
at the end of a dockerCMD
is not showing可能无法显示正确的文件。 如果是这种情况,您需要在容器运行时创建或触摸该文件,以便尾部获取正确的文件。
见“CMD cron && tail -f /var/log/cron.log
”。
在专用容器中定义cronjob,该容器通过docker exec将命令运行到您的服务。
这是更高的内聚力,运行脚本可以访问您为服务定义的环境变量。
crontab -l > cronexample
echo "00 09 * * 1-5 echo hello" >> cronexample
crontab cronexample
rm cronexample
Cron作业存储在/ var / spool / cron / crontabs中(我知道的所有发行版中的常见位置)。顺便说一句,你可以使用类似的东西在bash中创建一个cron选项卡:
sudo cron
这将创建一个带有cron任务的临时文件,然后使用crontab对其进行编程。最后一行删除临时文件。
当运行一些限制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
也许这有助于某人
所以,我的问题是一样的。解决方法是更改https://www.vip-consult.solutions/post/better-docker-cron#content中的命令部分。
从
命令:crontab / etc / crontab && tail -f / etc / crontab
至
命令:crontab / etc / crontab
命令:tail -f / etc / crontab
问题是命令之间的'&&'。删除后,一切都很好。
到目前为止我发现的最强大的方法是运行一个独立的cron容器 - 安装docker客户端并绑定mounter docker sock,这样你就可以与主机上的docker服务器通信。
然后只需为每个cron作业使用env vars,并使用入口点脚本生成/ etc / crontab
这是我使用这个原理创建的图像,并在过去3 - 4年中在生产中使用它。
尝试使用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
采用的解决方案在生产环境中可能是危险的。
在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"]
对于那些想要使用简单轻量图像的人:
* * * * * 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
@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
还有另外一种方法,就是使用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的完整文档:
&& 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来避免。
我根据其他答案创建了一个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
。
在其他主机上部署容器时,请注意它不会自动启动任何进程。您需要确保'cron'服务在容器内运行。在我们的例子中,我使用Supervisord和其他服务来启动cron服务。
exec
虽然这旨在通过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"
。