我试图在调用shell脚本的docker容器内运行cronjob。
昨天我一直在网上搜索,堆栈溢出,但我真的找不到一个有效的解决方案。 我该怎么做呢?
我试图在调用shell脚本的docker容器内运行cronjob。
昨天我一直在网上搜索,堆栈溢出,但我真的找不到一个有效的解决方案。 我该怎么做呢?
当前回答
与一次性作业并行设置cron
创建一个脚本文件,例如run.sh,其中包含应该定期运行的作业。
#!/bin/bash
timestamp=`date +%Y/%m/%d-%H:%M:%S`
echo "System path is $PATH at $timestamp"
保存并退出。
使用入口点而不是CMD
如果在docker容器化过程中有多个作业要启动,使用入口点文件来运行它们。
入口点文件是一个脚本文件,在发出docker run命令时起作用。因此,我们想要运行的所有步骤都可以放在这个脚本文件中。
例如,我们有两个作业要运行:
运行一次job: 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。 txt:完整的cron设置将被重定向到一个文件。
在cron中使用系统/用户特定的环境变量
我实际的cron作业期望将大多数参数作为环境变量传递给docker run命令。但是,使用bash时,我不能使用属于系统或docker容器的任何环境变量。
然后,这个问题就出现了:
在entrypoint.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映像!
其他回答
您可以将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
我想分享一些我发现更灵活的其他建议的典型的修改。我想用一个环境变量来启用更改cron时间,最后添加了一个额外的脚本,在我的entrypoint.sh中运行,但在调用cron -f之前
*updatecron.sh*
#!/bin/sh
#remove old cron files
rm -rf /etc/cron.*/*
#create a new formatted cron definition
echo "$crondef [appname] >/proc/1/fd/1 2>/proc/1/fd/2" >> /etc/cron.d/restart-cron
echo \ >> /etc/cron.d/restart-cron
chmod 0644 /etc/cron.d/restart-cron
crontab /etc/cron.d/restart-cron
这将删除任何现有的cron文件,使用crondef的ENV变量创建一个新的cronfile,然后加载它。
还有另一种方法,就是使用Tasker,它是一种支持cron(调度器)的任务运行器。
为什么?有时为了运行cron作业,你必须将你的基本映像(python, java, nodejs, ruby)与crond混合。这意味着要维持另一个形象。Tasker通过解耦crond和you容器来避免这种情况。您可以只关注想要执行命令的映像,并配置Tasker来使用它。
这里是船坞式作曲。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),并且每个任务都将在image section中定义的图像中执行脚本代码。
只要运行docker-compose up,就能看到它在工作。以下是Tasker回购的完整文档:
http://github.com/opsxcq/tasker
当在一些限制根访问的经过修剪的映像上运行时,我必须将我的用户添加到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死亡,容器将继续运行。
我根据其他答案创建了一个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
作为参考,图片在这里。