web-dev-qa-db-ja.com

cronの実行python docker内のジョブ

私はpython cronジョブを切り離しモードでdockerコンテナー内で実行したいと思います。私のセットアップは以下のとおりです。

My pythonスクリプトはtest.py

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

私のcronファイルはmy-crontabです

* * * * * /test.py > /dev/console

私の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

このアプローチの潜在的な問題は何ですか?他のアプローチがあり、それらの長所と短所は何ですか?

47

Dockerコンテナでcronジョブを実行しようとしたときに直面したいくつかの問題は次のとおりです。

  1. dockerコンテナの時刻は現地時間ではなくUTCです。
  2. docker環境はcronに渡されません。
  3. トーマスが指摘したように、cronロギングには多くの要望が残されており、Dockerからアクセスするには、Dockerベースのソリューションが必要です。

リストにはcron固有の問題があり、リストにはDocker固有の問題がありますが、いずれにしてもcronを機能させるために対処する必要があります。

そのために、質問で提起された問題に対する私の現在の作業ソリューションは次のとおりです。

Cronの下で実行されるすべてのスクリプトが書き込むdockerボリュームを作成します。

# 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"]

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)

Cronで実行するスクリプトに環境変数を渡すには、Thomasの提案に従い、/etc/cron.dにdocker環境変数が必要な各スクリプト(またはスクリプトのグループ)にcrontabフラグメントを配置しますプレースホルダー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

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)

Cronジョブが実行されるコンテナのDockerfileは次のとおりです。

# 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"]

最後に、コンテナを作成して実行します。

  1. ログボリューム(テストログ)コンテナーを作成します: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にあります。
33

Roskswの回答を補足します。

環境変数をcronジョブに渡すために、crontabファイルで文字列を置換する必要はありません。

違反者を実行するときに環境変数をファイルに保存し、cronを実行するたびにこのファイルから環境変数をロードする方が簡単です。ヒントを見つけました こちら

Dockerfileで:

CMD mkdir -p /data/log && env > /root/env.txt && crond -n

Crontabファイルで:

* * * * * root env - `cat /root/env.txt` my-script.sh
15
Alban Mouton

ルートのcrontabを使用する代わりに/etc/cron.d/に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)

全体として、経験から、コンテナーでcronを実行することは非常にうまく機能します(cronのログ記録に加えて、多くのことが望まれています)。

8
Thomas Orozco

これが代替ソリューションです。

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"]

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
5
evtuhovdo

以下のソリューションを使用しています。 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

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"]

crontab:

* * * * * root <cmd> >> /var/log/cron.log 2>&1

そして、あなたのcrontabに不気味な新しい行を追加することを忘れないでください

3
dogik

Crondとベースイメージを混在させないでください。ご使用の言語のネイティブソリューション(アントンが言ったスケジュールまたはクリトン)を使用するか、分離することをお勧めします。つまり、デカップリングすることで、物事を分離しておくことができます。したがって、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")'

ただ走れ docker-compose up、そしてそれが動作するのを見る。完全なドキュメントを含むTaskerリポジトリは次のとおりです。

http://github.com/opsxcq/tasker

2
OPSXCQ

シングルコンテナ方式

phusion/baseimage のように、PID 0を適切に処理するベースイメージを使用して、 密接に関連すること である同じコンテナ内でcrondを実行できます。

専用コンテナ法

よりクリーンなのは、crondを実行するだけの別のコンテナをリンクすることです。例えば:

Dockerfile

 FROM busybox
 ADD crontab /var/spool/cron/crontabs/www-data
 CMD crond -f

crontab

 * * * * * echo $USER

次に実行します:

 $ docker build -t cron .
 $ docker run --rm --link something cron

注:この場合、ジョブはwww-dataとして実行されます。 crontabへの書き込みアクセスのみを持つrootが所有する必要があるため、rootファイルをボリュームとしてマウントすることはできません。そうしないと、crondは何も実行しません。また、crondrootとして実行する必要があります。

2
Wernight

別の可能性は、 Crython を使用することです。 Crythonでは、単一のpythonスクリプト/プロセス内からpython関数を定期的にスケジュールできます。cron構文も理解できます。

@crython.job(expr='0 0 0 * * 0 *')
def job():
    print "Hello world"

Crythonを使用すると、Dockerコンテナー内でcrondを実行することによるさまざまな頭痛の種を回避できます。ジョブは必要に応じて起動する単一のプロセスになり、Docker実行モデルにより適しています。ただし、プログラム内にスケジューリングを配置するという欠点があります。これは必ずしも望ましいことではありません。それでも、いくつかのユースケースでは便利かもしれません。

1
Anton I. Sipos