シェルスクリプトを呼び出すdockerコンテナ内でcronjobを実行しようとしています。
昨日、私はウェブ全体を検索してスタックオーバーフローを起こしましたが、うまくいく解決策を本当に見つけることができませんでした。
これどうやってするの?
編集:
私は (コメント付き)githubリポジトリ を与えられた間隔でシェルスクリプトを呼び出す作業docker cronコンテナで作成しました。
イメージから起動したコンテナーがジョブを実行するために、crontabをイメージにコピーすることができます。
彼の Ekito/docker-cron
の中の Julien Boulay からの " Dockerでクーロンを使う "を見てください:
私たちの仕事を説明するために "
hello-cron
"と呼ばれる新しいファイルを作成しましょう。
* * * * * echo "Hello world" >> /var/log/cron.log 2>&1
# An empty line is required at the end of this file for a valid cron file.
次のDockerfileはあなたのイメージを構築するための全てのステップを記述しています
FROM ubuntu:latest
MAINTAINER [email protected]
RUN apt-get update && apt-get -y install cron
# Copy hello-cron file to the cron.d directory
COPY hello-cron /etc/cron.d/hello-cron
# Give execution rights on the cron job
RUN chmod 0644 /etc/cron.d/hello-cron
# Apply cron job
RUN crontab /etc/cron.d/hello-cron
# Create the log file to be able to run tail
RUN touch /var/log/cron.log
# Run the command on container startup
CMD cron && tail -f /var/log/cron.log
( Gaafar の コメント と apt-get
のインストール時のノイズを少なくするにはどうすればよいですか? :apt-get -y install -qq --force-yes cron
も動作します)
または、 hugoShaka 's answer で説明されているように、ジョブ自体がログファイルではなくstdout/stderrに直接リダイレクトされるようにします。
* * * * * root echo hello > /proc/1/fd/1 2>/proc/1/fd/2
最後のDockerfileの行を
CMD ["cron", "-f"]
(cron -f
について、これはcron "foreground"と言います) " docker ubuntu cron -f
は動作していません "
ビルドして実行します。
Sudo docker build --rm -t ekito/cron-example .
Sudo docker run -t -i ekito/cron-example
辛抱して、2分待ってください。コマンドラインに次のように表示されます。
Hello world
Hello world
tail
は、イメージ構築中に作成された場合、正しいファイルを表示しないかもしれないことに注意してください。
その場合、tailが正しいファイルを取得するためには、コンテナの実行時にファイルを作成またはタッチする必要があります。
" dockerの最後のtail -f
の出力CMD
は表示されていません "を参照してください。
採用したソリューションは、実稼働環境では危険な場合があります。
Dockerでは、コンテナーごとに1つのプロセスのみを実行する必要があります。そうしないと、分岐してバックグラウンドになったプロセスはモニターされず、知らない間に停止する可能性があります。
CMD cron && tail -f /var/log/cron.log
を使用するとき、バックグラウンドでcron
を実行するためにcronプロセスは基本的にforkし、メインプロセスは終了し、tailf
をフォアグラウンドで実行させます。バックグラウンドのcronプロセスは、気付かないうちに停止または失敗する可能性があります。コンテナーはまだサイレントに実行され、オーケストレーションツールは再起動しません。
このようなことを避けるには、cronのコマンド出力をそれぞれ
/proc/1/fd/1
と/proc/1/fd/2
にあるdockerstdout
とstderr
に直接リダイレクトします。
基本的なシェルリダイレクトを使用すると、次のようなことができます。
* * * * * root echo hello > /proc/1/fd/1 2>/proc/1/fd/2
そしてあなたのCMDは次のようになります。CMD ["cron", "-f"]
シンプルで軽量な画像を使いたい人のために:
FROM Alpine:3.6
# copy crontabs for root user
COPY config/cronjobs /etc/crontabs/root
# start crond with log level 8 in foreground, output to stderr
CMD ["crond", "-f", "-d", "8"]
ここで、 cronjobs は、次の形式のcronjobを含むファイルです。
* * * * * echo "hello stackoverflow" >> /test_file 2>&1
# remember to end this file with an empty new line
@VonCが提案したのはいいですが、すべてのcronジョブ設定を1行で行うことを好みます。これはcronjobの場所のようなクロスプラットフォームの問題を避けるでしょうし、あなたは別のcronファイルを必要としません。
FROM ubuntu:latest
# Install cron
RUN apt-get -y install cron
# Create the log file to be able to run tail
RUN touch /var/log/cron.log
# Setup cron job
RUN (crontab -l ; echo "* * * * * echo "Hello world" >> /var/log/cron.log") | crontab
# Run the command on container startup
CMD cron && tail -f /var/log/cron.log
Dockerコンテナを実行した後、cronサービスが機能しているかどうかを確認できます。
# To check if the job is scheduled
docker exec -ti <your-container-id> bash -c "crontab -l"
# To check if the cron service is running
docker exec -ti <your-container-id> bash -c "pgrep cron"
CMDの代わりにENTRYPOINTを使用したい場合は、上記のCMDを代わりに使用できます。
ENTRYPOINT cron start && tail -f /var/log/cron.log
それをする別の方法があります、 Tasker 、cron(スケジューラ)サポートを持っているタスクランナーを使うことです。
どうして ? cronジョブを実行するために、ベースイメージ(python、Java、nodejs、Ruby)とcrondを混在させる必要があります。それは維持するべきもう一つのイメージを意味します。タスカーは、クローンとあなたのコンテナーを切り離すことによってそれを避けます。コマンドを実行したいイメージに集中して、それを使用するようにTaskerを構成することができます。
こちらが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: hello
- every: minute
task: helloFromPython
- every: minute
task: helloFromNode
tasks:
docker:
- name: hello
image: debian:jessie
script:
- echo Hello world from Tasker
- name: helloFromPython
image: python:3-slim
script:
- python -c 'print("Hello world from python")'
- name: helloFromNode
image: node:8
script:
- node -e 'console.log("Hello from node")'
そこには3つのタスクがあり、それらはすべて毎分実行され(every: minute
)、そしてそれぞれがscript
セクションで定義されたイメージの中でimage
コードを実行します。
docker-compose up
を実行するだけで動作します。これが完全なドキュメンテーションを含むTaskerレポジトリです。
VonCの 答えはかなり徹底的です。さらに、私を助けてくれたことを1つ追加したいと思います。ファイルを生成せずにcronジョブを実行したいだけの場合は、cronコマンドから&& tail -f /var/log/cron.log
を削除するだけで済みます。ただし、cronコマンドが完了すると、dockerは最後のコマンドが終了したと判断してコンテナを強制終了するため、dockerコンテナは実行後すぐに終了します。これは、cron -f
を介してcronをフォアグラウンドで実行することで回避できます。
私はこれをコメントとして書きますが、まだ十分なポイントがありません:)
他の答えに基づいてdockerイメージを作成しました。
docker run -v "/path/to/cron:/etc/cron.d/crontab" [gaafar/cron][1]
/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
サービスにdocker execを介してコマンドを実行する専用のコンテナーでcronjobを定義します。
これは結束力が高く、実行中のスクリプトはサービスに定義した環境変数にアクセスできます。
#docker-compose.yml
version: "3.3"
services:
myservice:
environment:
MSG: i'm being cronjobbed, every minute!
image: Alpine
container_name: myservice
command: tail -f /dev/null
cronjobber:
image: docker:Edge
volumes:
- /var/run/docker.sock:/var/run/docker.sock
container_name: cronjobber
command: >
sh -c "
echo '* * * * * docker exec myservice printenv | grep MSG' > /etc/crontabs/root
&& crond -f"
コンテナを別のホストにデプロイするときは、コンテナがプロセスを自動的に起動しないことに注意してください。あなたは 'cron'サービスがあなたのコンテナの中で走っていることを確認する必要があります。私たちの場合、私はcronサービスを開始するために他のサービスと共にSupervisordを使っています。
[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
これはDockerのexec
インターフェースを介してコンテナー内で実行中のプロセスの横にあるジョブを実行することを目的としていますが、これはあなたにとって興味深いかもしれません。
コンテナを監視し、それらのメタデータで定義されたジョブをスケジュールするデーモンをそれらの上に書きました。例:
version: '2'
services:
wordpress:
image: wordpress
mysql:
image: mariadb
volumes:
- ./database_dumps:/dumps
labels:
deck-chores.dump.command: sh -c "mysqldump --all-databases > /dumps/dump-$$(date -Idate)"
deck-chores.dump.interval: daily
'クラシック'、cron風の設定も可能です。
これが docs です、これが imageリポジトリ です。
だから、私の問題は同じでした。修正は、docker-compose.yml
のコマンドセクションを変更することでした。
から
コマンド:crontab/etc/crontab && tail -f/etc/crontab
から
コマンド:crontab/etc/crontab
コマンド:tail -f/etc/crontab
problem はコマンド間の '&&'でした。これを削除した後、それはすべて大丈夫だった。
Cronジョブは/ var/spool/cron/crontabs(私が知っているすべてのディストリビューションで共通の場所)に格納されています。ところで、あなたはそのようなものを使用してbashでクーロンタブを作成することができます:
crontab -l > cronexample
echo "00 09 * * 1-5 echo hello" >> cronexample
crontab cronexample
rm cronexample
これはcronタスクで一時ファイルを作成し、そしてそれをcrontabを使ってプログラムします。最後の行で一時ファイルを削除します。
Rootアクセスを制限するいくつかのトリミングされたイメージを実行するとき、私はユーザーを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
たぶんそれは誰かを助けます