在docker中运行cron python作业

Chr*_*icz 48 python cron docker

我想在分离模式下在docker容器内运行python cron作业.我的设置如下:

我的python脚本是test.py

  #!/usr/bin/env python
  import datetime
  print "Cron job has run at %s" %datetime.datetime.now()
Run Code Online (Sandbox Code Playgroud)

我的cron文件是my-crontab

* * * * * /test.py > /dev/console
Run Code Online (Sandbox Code Playgroud)

我的Dockerfile是

FROM ubuntu:latest
RUN apt-get update && apt-get install -y software-properties-common python-software-properties && apt-get update

RUN apt-get install -y python cron
ADD my-crontab /
ADD test.py /
RUN chmod a+x test.py

RUN crontab /my-crontab
ENTRYPOINT cron -f
Run Code Online (Sandbox Code Playgroud)

这种方法有哪些潜在的问题?还有其他方法,它们的优点和缺点是什么?

Chr*_*icz 34

尝试在docker容器中运行cron作业时遇到的几个问题是:

  1. docker容器中的时间是UTC而不是本地时间;
  2. docker环境没有传递给cron;
  3. 正如Thomas所说,cron日志记录有很多不足之处,通过docker访问它需要一个基于docker的解决方案.

存在特定于cron的问题,并且列表中存在特定于docker的问题,但无论如何必须解决这些问题以使cron工作.

为此,我目前解决问题的工作方案如下:

创建一个docker卷,cron下运行的所有脚本都将写入:

# Dockerfile for test-logs

# BUILD-USING:        docker build -t test-logs .
# RUN-USING:          docker run  -d -v /t-logs --name t-logs test-logs
# INSPECT-USING:      docker run -t -i  --volumes-from t-logs ubuntu:latest /bin/bash

FROM stackbrew/busybox:latest

# Create logs volume
VOLUME /var/log

CMD  ["true"]
Run Code Online (Sandbox Code Playgroud)

将在cron下运行的脚本是test.py:

#!/usr/bin/env python

# python script which needs an environment variable and runs as a cron job
import datetime
import os

test_environ = os.environ["TEST_ENV"]
print "Cron job has run at %s with environment variable '%s'" %(datetime.datetime.now(), test_environ)
Run Code Online (Sandbox Code Playgroud)

为了通过环境变量,我想在cron下运行,遵循托马斯的建议,并把一个crontab片段为每个脚本(或脚本组)的脚本已经需要一个泊坞窗环境变量的/etc/cron.d一个占位符XXXXXXX,必须被设定.

# placed in /etc/cron.d 
# TEST_ENV is an docker environment variable that the script test.py need

TEST_ENV=XXXXXXX
#
* * * * * root python /test.py >> /var/log/test.log
Run Code Online (Sandbox Code Playgroud)

不是直接调用cron,而是将cron包装在执行以下操作的python脚本中:1.从docker环境变量中读取环境变量,并在crontab片段中设置环境变量.

#!/usr/bin/env python

# run-cron.py
# sets environment variable crontab fragments and runs cron

import os
from subprocess import call
import fileinput

# read docker environment variables and set them in the appropriate crontab fragment
environment_variable = os.environ["TEST_ENV"]

for line in fileinput.input("/etc/cron.d/cron-python",inplace=1):
    print line.replace("XXXXXXX", environment_variable)

args = ["cron","-f", "-L 15"]
call(args)
Run Code Online (Sandbox Code Playgroud)

Dockerfile,对于其中的cron作业运行的是如下的容器:

# BUILD-USING:        docker build -t test-cron .
# RUN-USING docker run --detach=true --volumes-from t-logs --name t-cron test-cron

FROM debian:wheezy
#
# Set correct environment variables.
ENV HOME /root
ENV TEST_ENV test-value

RUN apt-get update && apt-get install -y software-properties-common python-software-properties && apt-get update

# Install Python Setuptools
RUN apt-get install -y python cron

RUN apt-get purge -y python-software-properties software-properties-common && apt-get clean -y && apt-get autoclean -y && apt-get autoremove -y && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

ADD cron-python /etc/cron.d/
ADD test.py /
ADD run-cron.py /

RUN chmod a+x test.py run-cron.py

# Set the time zone to the local time zone
RUN echo "America/New_York" > /etc/timezone && dpkg-reconfigure --frontend noninteractive tzdata

CMD ["/run-cron.py"]
Run Code Online (Sandbox Code Playgroud)

最后,创建容器并运行它们:

  1. 创建日志卷(test-logs)容器: docker build -t test-logs .
  2. 运行日志卷: docker run -d -v /t-logs --name t-logs test-logs
  3. 创建cron容器: docker build -t test-cron .
  4. 运行cron容器: docker run --detach=true --volumes-from t-logs --name t-cron test-cron
  5. 检查在cron下运行的脚本的日志文件:docker run -t -i --volumes-from t-logs ubuntu:latest /bin/bash.日志文件在/var/log.


小智 15

这是对rosksw答案的补充.

无需在crontab文件中进行某些字符串替换,以便将环境变量传递给cron作业.

在运行限制器时将环境变量存储在文件中更简单,然后在每次执行cron时从该文件加载它们.我在这里找到了提示.

在dockerfile中:

CMD mkdir -p /data/log && env > /root/env.txt && crond -n
Run Code Online (Sandbox Code Playgroud)

在crontab文件中:

* * * * * root env - `cat /root/env.txt` my-script.sh
Run Code Online (Sandbox Code Playgroud)


Tho*_*zco 8

添加crontab片段/etc/cron.d/而不是使用root crontab可能更可取.

这个会:

  • 让您通过将其添加到该文件夹​​来添加其他cron作业.
  • 节省几层.
  • 模仿Debian发行版如何为自己的包做.

请注意,这些文件的格式与crontab条目略有不同.这是Debian php包中的一个示例:

# /etc/cron.d/php5: crontab fragment for php5
#  This purges session files older than X, where X is defined in seconds
#  as the largest value of session.gc_maxlifetime from all your php.ini
#  files, or 24 minutes if not defined.  See /usr/lib/php5/maxlifetime

# Look for and purge old sessions every 30 minutes
09,39 *     * * *     root   [ -x /usr/lib/php5/maxlifetime ] && [ -x /usr/lib/php5/sessionclean ] && [ -d /var/lib/php5 ] && /usr/lib/php5/sessionclean /var/lib/php5 $(/usr/lib/php5/maxlifetime)
Run Code Online (Sandbox Code Playgroud)

总的来说,根据经验,在容器中运行cron确实可以很好地工作(除了cron日志记录还有很多不足之处).


小智 6

这是我在 docker 中调试 cron python 脚本的清单:

  1. 确保您cron在某处运行命令。Cron 不会自动启动。RUN您可以使用或从 Dockerfile 运行它CMD,或者将其添加到容器的启动脚本中。如果您使用,CMD您可以考虑使用cron -f标志,该标志将 cron 保持在前台并且不会让容器死亡。但是,我更喜欢tail -f在日志文件上使用。
  2. 将环境变量存储在 /etc/envoronment 中。从 bash startscript 运行此命令printenv > /etc/environment:如果您在 python 脚本中使用环境变量,这是绝对必须的。默认情况下,Cron 对环境变量一无所知。通过它可以读取它们/etc/environment
  3. 使用以下配置测试 Cron:
* * * * * echo "Cron works" >>/home/code/test.log
* * * * * bash -c "/usr/local/bin/python3 /home/code/test.py >>/home/code/test.log 2>/home/code/test.log"
Run Code Online (Sandbox Code Playgroud)

python 测试文件应包含一些print语句或其他显示脚本正在运行的内容。2>/home/code/test.log也会记录错误。否则,您根本不会看到错误并会继续猜测。

完成后,转到容器,使用docker exec -it <container_name> bash并检查:

  1. 该 crontab 配置已使用crontab -l
  2. 使用监控日志tail -f /home/code/test.log

我花了几个小时和几天的时间来解决所有这些问题。我希望这可以帮助某人避免这种情况。


Ant*_*pos 5

另一种可能性是使用Crython。Crython 允许您在单个 python 脚本/进程中定期安排 python 函数。它甚至可以理解 cron 语法:

@crython.job(expr='0 0 0 * * 0 *')
def job():
    print "Hello world"
Run Code Online (Sandbox Code Playgroud)

使用 crython 可以避免在 docker 容器内运行 crond 的各种麻烦 - 您的作业现在是一个在需要时唤醒的单个进程,这更适合 docker 执行模型。但它的缺点是将调度放在程序中,这并不总是可取的。尽管如此,在某些用例中它可能会很方便。

  • 我最终选择了 python `schedule` 包。https://github.com/dbader/schedule (2认同)

evt*_*vdo 5

这是另一种解决方案.

Dockerfile

ADD docker/cron/my-cron /etc/cron.d/my-cron
RUN chmod 0644 /etc/cron.d/my-cron

ADD docker/cron/entrypoint.sh /etc/entrypoint.sh

ENTRYPOINT ["/bin/sh", "/etc/entrypoint.sh"]
Run Code Online (Sandbox Code Playgroud)

entrypoint.sh

 #!/usr/bin/env bash
  printenv | cat - /etc/cron.d/my-cron > ~/my-cron.tmp \
    && mv ~/my-cron.tmp /etc/cron.d/my-cron

cron -f
Run Code Online (Sandbox Code Playgroud)


dog*_*gik 5

我们正在使用以下解决方案。它支持docker logs在 PID 1 上的容器中挂起 cron 进程的功能和能力(如果您使用tail -f上面提供的解决方法 - 如果 cron 崩溃,docker 将不会遵循重启策略):

cron.sh:

#!/usr/bin/env bash

printenv | cat - /etc/cron.d/cron-jobs > ~/crontab.tmp \
    && mv ~/crontab.tmp /etc/cron.d/cron-jobs

chmod 644 /etc/cron.d/cron-jobs

tail -f /var/log/cron.log &

cron -f
Run Code Online (Sandbox Code Playgroud)

Dockerfile:

RUN apt-get install --no-install-recommends -y -q cron 

ADD cron.sh /usr/bin/cron.sh
RUN chmod +x /usr/bin/cron.sh

ADD ./crontab /etc/cron.d/cron-jobs
RUN chmod 0644 /etc/cron.d/cron-jobs

RUN touch /var/log/cron.log

ENTRYPOINT ["/bin/sh", "/usr/bin/cron.sh"]
Run Code Online (Sandbox Code Playgroud)

crontab:

* * * * * root <cmd> >> /var/log/cron.log 2>&1
Run Code Online (Sandbox Code Playgroud)

并且请不要忘记在您的 crontab 中添加令人毛骨悚然的新行


OPS*_*XCQ 5

不要混合使用 crond 和您的基本图像。更喜欢为您的语言使用本机解决方案(安东所说的时间表或 crython),或将其解耦。通过解耦,我的意思是,将事物分开,这样您就不必为了成为 python 和 crond 之间的融合而维护图像。

如果您想让事情解耦,您可以使用Tasker,一个具有 cron(调度程序)支持的任务运行器来解决它。

这是一个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: helloFromPython
                tasks:
                    docker:
                        - name: helloFromPython
                          image: python:3-slim
                          script:
                              - python -c 'print("Hello world from python")'
Run Code Online (Sandbox Code Playgroud)

只需运行docker-compose up,看看它的工作。这是带有完整文档的 Tasker 存储库:

http://github.com/opsxcq/tasker