私は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
このアプローチの潜在的な問題は何ですか?他のアプローチがあり、それらの長所と短所は何ですか?
Dockerコンテナでcronジョブを実行しようとしたときに直面したいくつかの問題は次のとおりです。
リストには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"]
最後に、コンテナを作成して実行します。
docker build -t test-logs .
docker run -d -v /t-logs --name t-logs test-logs
docker build -t test-cron .
docker run --detach=true --volumes-from t-logs --name t-cron test-cron
docker run -t -i --volumes-from t-logs ubuntu:latest /bin/bash
。ログファイルは/var/log
にあります。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
ルートのcrontab
を使用する代わりに/etc/cron.d/
にcrontabフラグメントを追加することをお勧めします。
これは:
これらのファイルの形式が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のログ記録に加えて、多くのことが望まれています)。
これが代替ソリューションです。
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
以下のソリューションを使用しています。 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に不気味な新しい行を追加することを忘れないでください
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リポジトリは次のとおりです。
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
は何も実行しません。また、crond
をroot
として実行する必要があります。
別の可能性は、 Crython を使用することです。 Crythonでは、単一のpythonスクリプト/プロセス内からpython関数を定期的にスケジュールできます。cron構文も理解できます。
@crython.job(expr='0 0 0 * * 0 *')
def job():
print "Hello world"
Crythonを使用すると、Dockerコンテナー内でcrondを実行することによるさまざまな頭痛の種を回避できます。ジョブは必要に応じて起動する単一のプロセスになり、Docker実行モデルにより適しています。ただし、プログラム内にスケジューリングを配置するという欠点があります。これは必ずしも望ましいことではありません。それでも、いくつかのユースケースでは便利かもしれません。