[英]How to run a cron job inside a docker container?
我正在尝试在调用 shell 脚本的 docker 容器中运行一个 cronjob。
昨天我一直在网上搜索和堆栈溢出,但我找不到真正有效的解决方案。
我怎样才能做到这一点?
您可以将 crontab 复制到映像中,以便从所述映像启动的容器运行作业。
请参阅Julien Boulay在他的Ekito/docker-cron
中的“使用 Docker 运行 cron 作业”:
让我们创建一个名为“
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
(请参阅Gaafar的评论和如何使apt-get
install 减少噪音? :
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 “前景”)“ 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
,它可能不会显示正确的文件。
如果是这种情况,您需要在容器运行时创建或触摸文件,以便 tail 获取正确的文件。
请参阅“未显示 docker CMD
末尾的tail -f
输出”。
在Jason Kulatunga的“在 Docker 中运行 Cron ”(2021 年 4 月)中查看更多信息,他在下面评论
请参阅 Jason 的图像AnalogJ/docker-cron
基于:
安装cronie
/ crond
的 Dockerfile,具体取决于发行版。
初始化/etc/environment
然后调用的入口点
cron -f -l 2
接受的答案在生产环境中可能是危险的。
在 docker 中,每个容器应该只执行一个进程,因为如果不这样做,分叉并进入后台的进程不会受到监控,并且可能会在您不知情的情况下停止。
当您使用CMD cron && tail -f /var/log/cron.log
时,cron 进程基本上 fork 以便在后台执行cron
,主进程退出并让您在前台执行tailf
。 后台 cron 进程可能会停止或失败,您不会注意到,您的容器仍将静默运行,并且您的编排工具不会重新启动它。
您可以通过将 cron 的命令输出直接重定向到分别位于
/proc/1/fd/1
和/proc/1/fd/2
的 dockerstdout
和stderr
来避免这种情况。
使用基本的 shell 重定向,您可能想要执行以下操作:
* * * * * root echo hello > /proc/1/fd/1 2>/proc/1/fd/2
你的 CMD 将是: CMD ["cron", "-f"]
对于那些想要使用简单轻量级图像的人:
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
@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
还有另一种方法是使用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
),并且每个任务都将在image
部分定义的图像内执行script
代码。
只需运行docker-compose up
,看看它是否正常工作。 这是包含完整文档的 Tasker 存储库:
尽管这旨在通过 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 的配置也是可能的。
VonC的回答非常彻底。 此外,我想补充一件对我有帮助的事情。 如果您只想运行 cron 作业而不拖尾文件,则很想从 cron 命令中删除&& tail -f /var/log/cron.log
。
然而,这将导致 Docker 容器在运行后不久退出,因为当 cron 命令完成时,Docker 认为最后一个命令已经退出并因此终止容器。 这可以通过cron -f
在前台运行 cron 来避免。
如果您使用 docker for windows,请记住,如果您打算将 crontab 文件从 windows 导入到 ubuntu 容器,则必须将行尾格式从 CRLF 更改为 LF(即从 dos 到 unix)。 如果没有,您的 cron-job 将无法工作。 这是一个工作示例:
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 作业是一项乏味的任务。 希望它可以帮助其他无法让他们的代码工作的人!
我根据其他答案创建了一个 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
作为参考,图片在这里。
不幸的是,上述答案都没有对我有用,尽管所有答案都会导致解决方案并最终导致我的解决方案,如果它对某人有帮助,这里是片段。 谢谢
这可以通过 bash 文件解决,由于 Docker 的分层架构,cron 服务不会通过 RUN/CMD/ENTRYPOINT 命令启动。
只需添加一个 bash 文件,该文件将启动 cron 和其他服务(如果需要)
DockerFile
FROM gradle:6.5.1-jdk11 AS build
# apt
RUN apt-get update
RUN apt-get -y install cron
# Setup cron to run every minute to print (you can add/update your cron here)
RUN touch /var/log/cron-1.log
RUN (crontab -l ; echo "* * * * * echo testing cron.... >> /var/log/cron-1.log 2>&1") | crontab
# entrypoint.sh
RUN chmod +x entrypoint.sh
CMD ["bash","entrypoint.sh"]
入口点.sh
#!/bin/sh
service cron start & tail -f /var/log/cron-2.log
如果还需要任何其他服务与 cron 一起运行,则在同一命令中使用&
添加该服务,例如: /opt/wildfly/bin/standalone.sh & service cron start & tail -f /var/log/cron-2.log
进入 docker 容器后,您可以看到testing cron....
将在文件中每分钟打印一次: /var/log/cron-1.log
在专用容器中定义 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"
我决定使用busybox,因为它是最小的图像之一。
crond 在前台执行(-f),日志发送到 stderr(-d),我没有选择更改日志级别。 crontab 文件被复制到默认路径:/var/spool/cron/crontabs
FROM busybox:1.33.1
# Usage: crond [-fbS] [-l N] [-d N] [-L LOGFILE] [-c DIR]
#
# -f Foreground
# -b Background (default)
# -S Log to syslog (default)
# -l N Set log level. Most verbose 0, default 8
# -d N Set log level, log to stderr
# -L FILE Log to FILE
# -c DIR Cron dir. Default:/var/spool/cron/crontabs
COPY crontab /var/spool/cron/crontabs/root
CMD [ "crond", "-f", "-d" ]
当您在另一台主机上部署容器时,请注意它不会自动启动任何进程。 您需要确保“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
创建一个脚本文件,比如 run.sh,其中包含应该定期运行的作业。
#!/bin/bash
timestamp=`date +%Y/%m/%d-%H:%M:%S`
echo "System path is $PATH at $timestamp"
保存并退出。
如果您在 docker 容器化期间有多个工作要启动,请使用入口点文件来运行它们。
入口点文件是一个脚本文件,它在发出 docker run 命令时生效。 所以,我们想要运行的所有步骤都可以放在这个脚本文件中。
例如,我们有 2 个作业要运行:
运行一次作业:回显“Docker 容器已启动”
运行定期作业:run.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 工作期望将大多数参数作为传递给 docker run 命令的环境变量。 但是,使用 bash,我无法使用属于系统或 docker 容器的任何环境变量。
然后,这是解决此问题的方法:
declare -p | grep -Ev 'BASHOPTS|BASH_VERSINFO|EUID|PPID|SHELLOPTS|UID' > /container.env
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
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 镜像!
您可以采用的另一条路线是Ofelia ,这是一个高度可配置的任务运行器映像,允许 4 种执行模式。
job-exec: this job is executed inside of a running container.
job-run: runs a command inside of a new container, using a specific image.
job-local: runs the command inside of the host running ofelia.
job-service-run: runs the command inside a new "run-once" service, for running inside a swarm
这里的优势是其他人已经为你完成了所有繁重的工作。 超级方便和容易。
它还有一个漂亮的官方吉祥物。
从上面的例子中,我创建了这个组合:
在 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
这是我基于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
映像上的命令。这个问题有很多答案,但有些很复杂,有些有一些缺点。 我尝试解释问题并尝试提供解决方案。
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 $!
解决的问题
对于上下文,我在 Kubernetes 上使用以前的脚本和 Laravel 应用程序。
在一些限制 root 访问的精简图像上运行时,我必须将我的用户添加到 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
也许这可以帮助某人
这条线是帮助我运行我预先安排的任务的那条线。
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
Cron 作业存储在 /var/spool/cron/crontabs (我知道的所有发行版中的常见位置)。 顺便说一句,您可以使用类似的东西在 bash 中创建一个 cron 选项卡:
crontab -l > cronexample
echo "00 09 * * 1-5 echo hello" >> cronexample
crontab cronexample
rm cronexample
这将使用 cron 任务创建一个临时文件,然后使用 crontab 对其进行编程。 最后一行删除临时文件。
所以,我的问题是一样的。 修复方法是更改docker-compose.yml
中的命令部分。
从
命令:crontab /etc/crontab && tail -f /etc/crontab
至
命令:crontab /etc/crontab
命令:tail -f /etc/crontab
问题是命令之间的“&&”。 删除后,一切都很好。
如果您想运行 crontab 以外的其他服务,除了您的入口点之外,您可能还想调用此脚本来激活您的脚本:
addCronTabEntry.sh
(crontab -l 2>/dev/null; echo "*/1 * * * * <yourscript>") | crontab -
service cron start
专注于在接收SIGTERM
或SIGQUIT
信号时优雅地停止 cronjobs(例如,在运行docker stop
时)。
这不太容易。 默认情况下,cron 进程只是被杀死而没有注意运行 cronjobs。 我正在详细说明巴布罗斯克的回答:
Dockerfile
:
FROM ubuntu:latest
RUN apt-get update \
&& apt-get -y install cron procps \
&& rm -rf /var/lib/apt/lists/*
# Copy cronjobs file to the cron.d directory
COPY cronjobs /etc/cron.d/cronjobs
# Give execution rights on the cron job
RUN chmod 0644 /etc/cron.d/cronjobs
# similarly prepare the default cronjob scripts
COPY run_cronjob.sh /root/run_cronjob.sh
RUN chmod +x /root/run_cronjob.sh
COPY run_cronjob_without_log.sh /root/run_cronjob_without_log.sh
RUN chmod +x /root/run_cronjob_without_log.sh
# Apply cron job
RUN crontab /etc/cron.d/cronjobs
# to gain access to environment variables, we need this additional entrypoint script
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
# optionally, change received signal from SIGTERM TO SIGQUIT
#STOPSIGNAL SIGQUIT
# Run the command on container startup
ENTRYPOINT ["/entrypoint.sh"]
entrypoint.sh
:
#!/bin/bash
# make global environment variables available within crond, too
printenv | grep -v "no_proxy" >> /etc/environment
# SIGQUIT/SIGTERM-handler
term_handler() {
echo 'stopping cron'
service cron stop
echo 'stopped'
echo 'waiting'
x=$(($(ps u -C run_cronjob.sh | wc -l)-1))
xold=0
while [ "$x" -gt 0 ]
do
if [ "$x" != "$xold" ]; then
echo "Waiting for $x running cronjob(s):"
ps u -C run_cronjob.sh
xold=$x
sleep 1
fi
x=$(($(ps u -C run_cronjob.sh | wc -l)-1))
done
echo 'done waiting'
exit 143; # 128 + 15 -- SIGTERM
}
# cron service with SIGTERM and SIGQUIT support
service cron start
trap "term_handler" QUIT TERM
# endless loop
while true
do
tail -f /dev/null & wait ${!}
done
cronjobs
* * * * * ./run_cronjob.sh cron1
*/2 * * * * ./run_cronjob.sh cron2
*/3 * * * * ./run_cronjob.sh cron3
假设您将所有 cronjobs 包装在run_cronjob.sh
脚本中。 这样,您可以执行关闭将正常等待的任意代码。
run_cronjobs.sh
(保持 cronjob 定义干净的可选帮助脚本)
#!/bin/bash
DIR_INCL="${BASH_SOURCE%/*}"
if [[ ! -d "$DIR_INCL" ]]; then DIR_INCL="$PWD"; fi
cd "$DIR_INCL"
# redirect all cronjob output to docker
./run_cronjob_without_log.sh "$@" > /proc/1/fd/1 2>/proc/1/fd/2
run_cronjob_without_log.sh
your_actual_cronjob_src()
顺便说一句,当收到SIGKILL
时,容器仍然会立即关闭。 这样,您可以使用 docker docker-compose stop -t 60 cron-container
类的命令等待 60 秒以使 cronjobs 正常完成,但在超时后仍然可以确定终止它们。
只需添加到您也可以使用此图像的答案列表: https://hub.docker.com/repository/docker/cronit/simple-cron
并使用它作为启动 cron 作业的基础,像这样使用它:
FROM cronit/simple-cron # Inherit from the base image
#Set up all your dependencies
COPY jobs.cron ./ # Copy your local config
显然,可以将cron作为容器内的进程(在 root 用户下)与其他进程一起运行,使用ENTRYPOINT
中的 ENTRYPOINT 语句和start.sh
脚本,其中包括行process cron start
。 更多信息在这里
#!/bin/bash
# copy environment variables for local use
env >> etc/environment
# start cron service
service cron start
# start other service
service other start
#...
如果您的映像不包含任何守护程序(因此它只是短期运行的脚本或进程),您也可以考虑从外部启动您的 cron,只需使用 cron 信息定义一个 LABEL 以及调度程序本身。 这样,您的默认容器 state 将“退出”。 如果您有多个脚本,与拥有多个并行运行的 cron 实例相比,这可能会导致您的系统占用更少的空间。
见: https://github.com/JaciBrunning/docker-cron-label
示例 docker-compose.yaml:
version: '3.8'
# Example application of the cron image
services:
cron:
image: jaci/cron-label:latest
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
- "/etc/localtime:/etc/localtime:ro"
hello:
image: hello-world
restart: "no"
labels:
- "cron.schedule=* * * * * "
我想分享对我发现更灵活的其他一些建议的典型修改。 我想使用环境变量启用更改 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,然后加载它。
我们的是一个作为 cron 作业运行的 nodejs 应用程序,它也依赖于环境变量。
以下解决方案对我们有用。
码头文件:
# syntax=docker/dockerfile:1
FROM node:12.18.1
ENV NODE_ENV=production
COPY ["startup.sh", "./"]
# Removed steps to build the node js application
#--------------- Setup cron ------------------
# Install Cron
RUN apt-get update
RUN apt-get -y install cron
# Run every day at 1AM
#/proc/1/fd/1 2>/proc/1/fd/2 is used to redirect cron logs to standard output and standard error
RUN (crontab -l ; echo "0 1 * * * /usr/local/bin/node /app/dist/index.js > /proc/1/fd/1 2>/proc/1/fd/2") | crontab
#--------------- Start Cron ------------------
# Grant execution rights
RUN chmod 755 startup.sh
CMD ["./startup.sh"]
启动.sh:
!/bin/bash
echo "Copying env variables to /etc/environment so that it is available for cron jobs"
printenv >> /etc/environment
echo "Starting cron"
cron -f
对于多个作业和各种依赖项,如zsh
和curl
,这是一个很好的方法,同时还结合了其他答案的最佳实践。 奖励:这不需要您在myScript.sh
上设置+x
执行权限,这在新环境中很容易错过。
cron.dockerfile
FROM ubuntu:latest
# Install dependencies
RUN apt-get update && apt-get -y install \
cron \
zsh \
curl;
# Setup multiple jobs with zsh and redirect outputs to docker logs
RUN (echo "\
* * * * * zsh -c 'echo "Hello World"' 1> /proc/1/fd/1 2>/proc/1/fd/2 \n\
* * * * * zsh /myScript.sh 1> /proc/1/fd/1 2>/proc/1/fd/2 \n\
") | crontab
# Run cron in forground, so docker knows the task is running
CMD ["cron", "-f"]
像这样将其与 docker compose 集成:
docker-compose.yml
services:
cron:
build:
context: .
dockerfile: ./cron.dockerfile
volumes:
- ./myScript.sh:/myScript.sh
请记住,当您更改 cron.dockerfile 的内容时,您需要cron.dockerfile
docker compose build cron
,但是对myScript.sh
的更改将立即反映出来,因为它已安装在 compose 中。
所有答案都需要在容器内进行根访问,因为“cron”本身请求 UID 0。请求根访问(例如通过 sudo)是违反 docker 最佳实践的。 我使用https://github.com/gjcarneiro/yacron来管理计划任务。
到目前为止,我找到的最可靠的方法是运行一个独立的cron容器-安装docker客户端并绑定安装docker sock,以便您可以与主机上的docker服务器通信。
然后只需对每个cron作业使用env vars和一个入口点脚本来生成/ etc / crontab
这是我使用此原理创建的图像,并在过去3-4年中用于生产。
https://www.vip-consult.solutions/post/better-docker-cron#content
尝试使用clockwork gem 来安排任务。 按照此链接中提供的步骤操作。
您可以在 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 文件中创建一个单独的容器并在容器内运行以下命令。
command: bundle exec clockwork lib/clock.rb
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.