我试图在调用shell脚本的docker容器内运行cronjob。
昨天我一直在网上搜索,堆栈溢出,但我真的找不到一个有效的解决方案。 我该怎么做呢?
我试图在调用shell脚本的docker容器内运行cronjob。
昨天我一直在网上搜索,堆栈溢出,但我真的找不到一个有效的解决方案。 我该怎么做呢?
当前回答
下面是我的基于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日志中。
其他回答
与一次性作业并行设置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映像!
如果映像不包含任何守护进程(因此只有短时间运行的脚本或进程),还可以考虑从外部启动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=* * * * * "
这个问题有很多答案,但有些很复杂,另一些有一些缺点。我试着解释问题并提出解决方案。
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 $!
解决问题
环境变量在cron环境中不可用(如env vars或kubernetes secrets) 当crontab文件无效时停止 当机器接收到SIGTERM信号时,优雅地停止cron作业
作为上下文,我在Kubernetes上使用Laravel应用程序使用之前的脚本。
当您将容器部署到另一个主机上时,请注意它不会自动启动任何进程。你需要确保'cron'服务在你的容器中运行。 在我们的例子中,我使用了监工和其他服务来启动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
当在一些限制根访问的经过修剪的映像上运行时,我必须将我的用户添加到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死亡,容器将继续运行。