シェルスクリプトを呼び出すDockerコンテナー内でcronjobを実行しようとしています。
昨日、私はWeb全体とスタックオーバーフローを検索してきましたが、実際に機能する解決策を見つけることができませんでした。
これどうやってするの?
編集:
私は、(コメントされた)githubリポジトリーを作成しました。これは、所定の間隔でシェル・スクリプトを呼び出す、動作するdocker cronコンテナーを使用しています。
シェルスクリプトを呼び出すDockerコンテナー内でcronjobを実行しようとしています。
昨日、私はWeb全体とスタックオーバーフローを検索してきましたが、実際に機能する解決策を見つけることができませんでした。
これどうやってするの?
編集:
私は、(コメントされた)githubリポジトリーを作成しました。これは、所定の間隔でシェル・スクリプトを呼び出す、動作するdocker cronコンテナーを使用しています。
回答:
crontabをイメージにコピーして、そのイメージから起動されたコンテナーでジョブを実行することができます。
「を参照してください。ドッカーとcronジョブを実行してから、」ジュリアンBOULAY彼の中にEkito/docker-cron
:
「
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 docker@ekito.fr
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
ことができますか?:うまくいく場合もあります)
落とし穴に関する簡単なメモ:
スクリプトファイルを追加して、それを実行するようにcronに指示している場合、忘れた場合、Cronは警告なしで失敗することに注意してください。
RUN chmod 0744 /the_script
または、hugoShakaの回答に記載されているように、ジョブ自体がログファイルではなくstdout / stderrに直接リダイレクトされることを確認します。
* * * * * root echo hello > /proc/1/fd/1 2>/proc/1/fd/2
最後のDockerfile行を
CMD ["cron", "-f"]
参照(about cron -f
、つまりcronの「フォアグラウンド」)「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
イメージのビルド中に作成された場合、正しいファイルが表示されない場合があることに注意してください。
その場合は、テールが正しいファイルを取得できるように、コンテナーの実行時にファイルを作成または操作する必要があります。
「Dockerの最後の出力が表示さtail -f
れCMD
ない」を参照してください。
-y
crontab -l
、rootにcrontabがインストールされていません。また、画面に何も表示されません。しかし、「/ etc / cron.d /」を確認すると、crontab /var/log/cron.log
ファイルが存在することがわかります(さらに驚くべきことにHello World
)。このイメージをDockerfileにプルしています:FROM phusion/baseimage:0.10.0
。行動の不一致に関するアイデアはありますか?
採用されたソリューションは、運用環境では危険な場合があります。
dockerでは、コンテナーごとに1つのプロセスのみを実行する必要があります。そうしないと、分岐してバックグラウンドになったプロセスは監視されず、知らないうちに停止する可能性があります。
あなたが使用する場合はCMD cron && tail -f /var/log/cron.log
cronプロセスを基本的に実行するためにforkしcron
、バックグラウンドでメインプロセスが終了し、あなたが実行してみましょうtailf
フォアグラウンドで。バックグラウンドのcronプロセスが停止したり、失敗したりすることに気付かない場合があります。コンテナは引き続きサイレントで実行され、オーケストレーションツールは再起動しません。
あなたのドッキングウィンドウに直接のcronのコマンドの出力をリダイレクトすることによって、そのようなことを避けることができます
stdout
し、stderr
中にそれぞれ配置されるの/proc/1/fd/1
と/proc/1/fd/2
。
基本的なシェルリダイレクトを使用すると、次のようなことができます。
* * * * * root echo hello > /proc/1/fd/1 2>/proc/1/fd/2
そしてあなたのCMDは次のようになります: CMD ["cron", "-f"]
cron -f
「cronフォアグラウンド」用です。わかりやすくするために、あなたの回答を上記に含めました。+1
シンプルで軽量なイメージを使用したい場合:
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"]
どこcronジョブは、このフォームでは、あなたのcronジョブを含むファイルです。
* * * * * echo "hello stackoverflow" >> /test_file 2>&1
# remember to end this file with an empty new line
> /proc/1/fd/1 2> /proc/1/fd/2
リダイレクトを使用して、Dockerログから直接cronjobs出力にアクセスします。
-d 8
パラメータをサポートするcrond は標準のcronではなく、busyboxからのcrondコマンドです。たとえば、ubuntuから、これをとして実行できますbusybox crond -f -d 8
。古いバージョンでは、を使用する必要があります-L /dev/stdout/
。
docker run -v ${PWD}/cronjobs:/etc/crontabs/root alpine:3.6 crond -f -d 8
。@Groostav Docker Composeでも同様のことができます。
CMD ["crond"
またはCMD ["cron"
?
@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
RUN apt-get update && apt-get -y install cron
それ以外の場合は、パッケージを見つけることができませんcron
RUN cat $APP_HOME/crons/* | crontab
cron
エントリポイントスクリプトへの追加は、最良のオプションのようです。ENTRYPOINT["entrypoint.sh"]
これを行う別の方法は、cron(スケジューラー)をサポートするタスクランナーであるTaskerを使用することです。
どうして ?cronジョブを実行するために、ベースイメージ(python、java、nodejs、ruby)をcrondと混合する必要がある場合があります。それは維持する別のイメージを意味します。Taskerは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リポジトリは次のとおりです。
docker exec
、指定されたコンテナで使用することです。
これは、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のような構成も可能です。
ここにドキュメントがあります。ここに画像リポジトリがあります。
docker exec <container_name> <some_command>
、スケジュールによるコマンドのように機能します。
他の回答に基づいてDockerイメージを作成しました。これは次のように使用できます
docker run -v "/path/to/cron:/etc/cron.d/crontab" gaafar/cron
ここで/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
参考までに、画像はこちらです。
コンテナを別のホストにデプロイするときは、プロセスが自動的に開始されないことに注意してください。コンテナ内で「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を介してコマンドを実行する専用コンテナーで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"
myservice unknown
エラーを。
WindowsでDockerを使用している場合、WindowsからUbuntuコンテナーにcrontabファイルをインポートする場合は、行末の形式をCRLFからLFに(つまり、DOSからUNIXに)変更する必要があることに注意してください。そうでない場合、cronジョブは機能しません。これが実際の例です:
FROM ubuntu:latest
RUN apt-get update && apt-get -y install cron
RUN apt-get update && apt-get install -y dos2unix
# Add crontab file (from your windows host) to the cron directory
ADD cron/hello-cron /etc/cron.d/hello-cron
# Change line ending format to LF
RUN dos2unix /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/hello-cron.log
# Run the command on container startup
CMD cron && tail -f /var/log/hello-cron.log
Dockerコンテナでcronジョブをデバッグするのは面倒な作業なので、実際に理解するには数時間かかりました。それが彼らのコードを機能させることができない他の誰かを助けることを願っています!
上記の例から、私はこの組み合わせを作成しました:
NanoでCrontabを使用した高山画像と編集(viが嫌い)
FROM alpine
RUN apk update
RUN apk add curl nano
ENV EDITOR=/usr/bin/nano
# start crond with log level 8 in foreground, output to stderr
CMD ["crond", "-f", "-d", "8"]
# Shell Access
# docker exec -it <CONTAINERID> /bin/sh
# Example Cron Entry
# crontab -e
# * * * * * echo hello > /proc/1/fd/1 2>/proc/1/fd/2
# DATE/TIME WILL BE IN UTC
定期的に実行することになっているジョブを含むスクリプトファイル、たとえばrun.shを作成します。
#!/bin/bash
timestamp=`date +%Y/%m/%d-%H:%M:%S`
echo "System path is $PATH at $timestamp"
保存して終了。
Dockerコンテナー化中に実行する複数のジョブがある場合は、エントリーポイントファイルを使用してそれらをすべて実行します。
エントリポイントファイルは、docker runコマンドが発行されたときに実行されるスクリプトファイルです。したがって、実行するすべてのステップをこのスクリプトファイルに入れることができます。
たとえば、実行する2つのジョブがあります。
ジョブを1回実行:「Dockerコンテナーが開始されました」とエコー
定期的なジョブを実行する:run.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になります。
Scheduler.txt
:cronセットアップ全体がファイルにリダイレクトされます。
私の実際のcronジョブは、docker runコマンドに渡される環境変数としてほとんどの引数を期待していました。しかし、bashでは、システムまたはDockerコンテナーに属する環境変数を使用できませんでした。
次に、これはこの問題のウォークアラウンドとして登場しました:
declare -p | grep -Ev 'BASHOPTS|BASH_VERSINFO|EUID|PPID|SHELLOPTS|UID' > /container.env
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
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ジョブは/ var / spool / cron / crontabsに保存されます(私が知っているすべてのディストリビューションで共通の場所です)。ところで、あなたはそのようなものを使用してbashでcronタブを作成することができます:
crontab -l > cronexample
echo "00 09 * * 1-5 echo hello" >> cronexample
crontab cronexample
rm cronexample
これにより、cronタスクで一時ファイルが作成され、crontabを使用してプログラムされます。最後の行で一時ファイルを削除します。
cron
デーモンは通常、コンテナで実行されません。
crond
しているサービスに加えて、通常はs6などのサービスマネージャーを使用して実行する必要があります。おそらく正しい答えを得るための質問としてそれを尋ねてください
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
多分それは誰かを助ける
これまでに見つけた最も堅牢な方法は、独立したcronコンテナーを実行することです。Dockerクライアントをインストールし、Docker Sockをバインドマウントして、ホスト上のDockerサーバーと通信できるようにします。
次に、各cronジョブのenv varsとエントリポイントスクリプトを使用して、/ etc / crontabを生成します
これは、この原則を使用して作成し、過去3〜4年間生産に使用した画像です。
https://www.vip-consult.solutions/post/better-docker-cron#content
時計仕掛けの宝石を使用してタスクをスケジュールしてみてください。このリンクに記載されている手順に従ってください。
以下のようにlib / clock.rbファイル内のrakeタスクを呼び出すことができます。
every(1.day, 'Import large data from csv files', :at => '5:00') do |job|
`rake 'portal:import_data_from_csv'`
end
docker-composeファイルに別のコンテナーを作成し、コンテナー内で以下のコマンドを実行します。
command: bundle exec clockwork lib/clock.rb
RUN apt-get update && apt-get install cron