シェルスクリプトを呼び出すcronjobをdockerコンテナ内で実行しようとしています。
昨日、ウェブやスタックオーバーフローをくまなく探したのですが、うまくいく解決策は本当に見つかりませんでした。
どうすればいいのでしょうか?
EDIT:
私は、(コメント付き)githubリポジトリを作成し、任意の間隔でシェルスクリプトを起動するDocker cronコンテナが動作するようにしました。
イメージにcrontabをコピーしておけば、そのイメージから起動したコンテナがジョブを実行するようになります。
Julien Boulay]2 の Ekito/docker-cron` にある "Run a cron job with 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's comment と How do I make apt-get
install less noisy?:
また、apt-get -y install -qq --force-yes cron
も有効です)
または、hugoShaka'の 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
is not working"
ビルドして実行します。
sudo docker build --rm -t ekito/cron-example .
sudo docker run -t -i ekito/cron-example
気長に2分ほど待つと、コマンドラインが表示されるはずです。
Hello world
Hello world
tail
がイメージビルド中に作成された場合、正しいファイルを表示しない可能性があることに注意してください。
この場合、tail が正しいファイルをピックアップするために、コンテナ実行時にファイルを作成するか、ファイルに触れる必要があります。
採用されたソリューションは、生産環境では危険である可能性があります。
ドッカーでは、コンテナごとに1つのプロセスのみを実行する必要があります。実行しない場合、分岐してバックグラウンドになったプロセスは監視されず、知らないうちに停止する可能性があるためです。
CMD cron&&を使用する場合tail -f / var / log / cron.log
cronプロセスは基本的にフォークしてバックグラウンドで cron
を実行すると、メインプロセスは終了し、フォアグラウンドで tailf
を実行できます。 バックグラウンドクロンプロセスは停止するか失敗する可能性がありますが、気付かないでしょう。コンテナは静かに動作し、オーケストレーションツールはそれを再起動しません。
このようなことは、クロンのコマンド出力を、それぞれ
/ proc / 1 / fd / 1
と/ proc / 1 / fd / 2
にあるドッカーstdout
とstderr
に直接リダイレクトすることで回避できます。 。
基本的なシェルリダイレクトを使用すると、次のようなことを行うことができます。
``。
そして、あなたの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 は、次の形式のcronjobsを含むファイルです。
* * * * * 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
ドッカーコンテナーを実行した後、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
これを行う別の方法は、cron(スケジューラ)をサポートするタスクランナーであるTaskerを使用することです。
なぜ。 ? ときどき、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
)実行され、それぞれが image
セクションで定義された画像内で script
コードを実行します。
「ドッカー構成」を実行して、動作していることを確認します。 完全なドキュメントが記載されたTaskerレポは次のとおりです。
[VonC's][1]答えはかなり徹底的です。 さらに、私を助けてくれたものを1つ追加したいと思います。 ファイルをテーリングせずにcronジョブを実行したい場合は、 &&を削除したくなるでしょう。 cronコマンドのtail -f / var / log / cron.log
。
ただし、これにより、Dockerコンテナーは実行直後に終了します。これは、cronコマンドが完了すると、Dockerが最後のコマンドが終了したと考え、コンテナーが殺されたためです。 これは、「cron -f」を介してフォアグラウンドでcronを実行することで回避できます。
[1]:https://stackoverflow.com/users/6309/vonc "VonC's"。
他の回答を参考に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
参考までに、画像はこちらです。
これは、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
「クラシック」なクロンのような構成も可能です。
docs、imageリポジトリです。
コンテナを別のホストにデプロイするときは、プロセスが自動的に開始されないことに注意してください。 コンテナ内で「cron」サービスが実行されていることを確認する必要があります。 私たちの場合、私は他のサービスとSupervisordを使用してcronサービスを開始しています。
[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"
だから、私の問題は同じでした。 修正は、「docker-compose.yml」のコマンドセクションを変更することでした。
から。
コマンド:crontab / etc / crontab&& tail -f / etc / crontab。
に。
コマンド:crontab / etc / crontab。
コマンド:tail -f / etc / crontab。
問題は「&&」でした。コマンド間。 これを削除した後、すべて問題ありませんでした。
ルートアクセスを制限するトリミングされた画像で実行する場合、ユーザーをスーダーに追加して、「sudo cron」として実行する必要がありました。
<。!-スニペットを開始:js hide:false console:true babel:false -->。
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ジョブは/var/spool/cron/crontabsに保存されます(私が知っているすべてのディストロで共通の場所です)。ちなみに、bashでcronタブを作成するには、以下のようなものを使用します。
crontab -l > cronexample
echo "00 09 * * 1-5 echo hello" >> cronexample
crontab cronexample
rm cronexample
これは、クーロンタスクで一時ファイルを作成し、クーロンタブでそれをプログラムするものです。最後の行で一時ファイルを削除します。
時計仕掛けの宝石を使用してタスクをスケジュールしてみてください。 このリンクで提供されている手順に従ってください。
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
別のコンテナをドッカー構成ファイルに作成&コンテナ内で次のコマンドを実行します。
command: bundle exec clockwork lib/clock.rb
これまでに見つけた最も堅 ⁇ な方法は、独立したcronコンテナを実行することです。ドッカークライアントをインストールし、ドッカーソックスをバインドして、ホスト上のドッカーサーバーと通信できるようにします。
次に、各cronジョブにenv varsを使用し、エントリポイントスクリプトを使用して/ etc / crontabを生成します。
これが、この原則を使用して、過去3〜4年間制作に使用した画像です。
https://www.vip-consult.solutions/post/better-docker-cron#content。