我试图在调用shell脚本的docker容器内运行cronjob。
昨天我一直在网上搜索,堆栈溢出,但我真的找不到一个有效的解决方案。 我该怎么做呢?
我试图在调用shell脚本的docker容器内运行cronjob。
昨天我一直在网上搜索,堆栈溢出,但我真的找不到一个有效的解决方案。 我该怎么做呢?
当前回答
当在一些限制根访问的经过修剪的映像上运行时,我必须将我的用户添加到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死亡,容器将继续运行。
其他回答
如果映像不包含任何守护进程(因此只有短时间运行的脚本或进程),还可以考虑从外部启动cron,只需用cron信息定义一个LABEL,再加上调度器本身。这样,您的默认容器状态是“exited”。如果您有多个脚本,这可能会比拥有多个并行运行的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=* * * * * "
下面是我的基于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映像中的命令。
此外,任务的输出显然不会出现在docker日志中。
我偶尔尝试寻找一个docker友好的cron实现。最后一次尝试,我找到了一对。
我所说的对docker友好的意思是,“任务的输出可以在docker日志中看到,而不是诉诸于技巧。”
目前我认为最有希望的是超级克隆。它可以提供一个crontab文件,同时对docker友好。利用它:
docker-compose.yml:
services:
supercronic:
build: .
command: supercronic crontab
Dockerfile:
FROM alpine:3.17
RUN set -x \
&& apk add --no-cache supercronic shadow \
&& useradd -m app
USER app
COPY crontab .
定时任务:
* * * * * date
有更多信息的要点。
另一个不错的是yacron,但它使用YAML。
可以使用Ofelia,但它们似乎专注于在单独的容器中运行任务。这可能不是一个缺点,但我不确定为什么我想这么做。
还有一些传统的cron实现:dcron, fcron, cronie。但它们“没有简单的方法来查看任务的输出”。
我根据其他答案创建了一个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
作为参考,图片在这里。
与一次性作业并行设置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映像!