web-dev-qa-db-ja.com

Dockerコンテナ内でcronジョブを実行する方法

シェルスクリプトを呼び出すdockerコンテナ内でcronjobを実行しようとしています。

昨日、私はウェブ全体を検索してスタックオーバーフローを起こしましたが、うまくいく解決策を本当に見つけることができませんでした。
これどうやってするの?

編集:

私は (コメント付き)githubリポジトリ を与えられた間隔でシェルスクリプトを呼び出す作業docker cronコンテナで作成しました。

154
C Heyer

イメージから起動したコンテナーがジョブを実行するために、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

Ericコメント内 を追加します。

tailは、イメージ構築中に作成された場合、正しいファイルを表示しないかもしれないことに注意してください。
その場合、tailが正しいファイルを取得するためには、コンテナの実行時にファイルを作成またはタッチする必要があります。

" dockerの最後のtail -fの出力CMDは表示されていません "を参照してください。

229
VonC

採用したソリューションは、実稼働環境では危険な場合があります。

Dockerでは、コンテナーごとに1つのプロセスのみを実行する必要があります。そうしないと、分岐してバックグラウンドになったプロセスはモニターされず、知らない間に停止する可能性があります。

CMD cron && tail -f /var/log/cron.logを使用するとき、バックグラウンドでcronを実行するためにcronプロセスは基本的にforkし、メインプロセスは終了し、tailfをフォアグラウンドで実行させます。バックグラウンドのcronプロセスは、気付かないうちに停止または失敗する可能性があります。コンテナーはまだサイレントに実行され、オーケストレーションツールは再起動しません。

このようなことを避けるには、cronのコマンド出力をそれぞれ/proc/1/fd/1/proc/1/fd/2にあるdocker stdoutstderrに直接リダイレクトします。

基本的なシェルリダイレクトを使用すると、次のようなことができます。

* * * * * root echo hello > /proc/1/fd/1 2>/proc/1/fd/2

そしてあなたのCMDは次のようになります。CMD ["cron", "-f"]

78
hugoShaka

シンプルで軽量な画像を使いたい人のために:

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
31
Oscar Fanelli

@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
25
Youness

それをする別の方法があります、 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レポジトリです。

http://github.com/opsxcq/tasker

13
OPSXCQ

VonCの 答えはかなり徹底的です。さらに、私を助けてくれたことを1つ追加したいと思います。ファイルを生成せずにcronジョブを実行したいだけの場合は、cronコマンドから&& tail -f /var/log/cron.logを削除するだけで済みます。ただし、cronコマンドが完了すると、dockerは最後のコマンドが終了したと判断してコンテナを強制終了するため、dockerコンテナは実行後すぐに終了します。これは、cron -fを介してcronをフォアグラウンドで実行することで回避できます。

私はこれをコメントとして書きますが、まだ十分なポイントがありません:)

11
vanugrah

他の答えに基づいて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
5
Gaafar

サービスに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"
4
Jakob Eriksson

コンテナを別のホストにデプロイするときは、コンテナがプロセスを自動的に起動しないことに注意してください。あなたは '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
4
Sagar Ghuge

これは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リポジトリ です。

4
funky-future

だから、私の問題は同じでした。修正は、docker-compose.ymlのコマンドセクションを変更することでした。

から

コマンド:crontab/etc/crontab && tail -f/etc/crontab

から

コマンド:crontab/etc/crontab

コマンド:tail -f/etc/crontab

problem はコマンド間の '&&'でした。これを削除した後、それはすべて大丈夫だった。

0
a223w2d

Cronジョブは/ var/spool/cron/crontabs(私が知っているすべてのディストリビューションで共通の場所)に格納されています。ところで、あなたはそのようなものを使用してbashでクーロンタブを作成することができます:

crontab -l > cronexample
echo "00 09 * * 1-5 echo hello" >> cronexample
crontab cronexample
rm cronexample

これはcronタスクで一時ファイルを作成し、そしてそれをcrontabを使ってプログラムします。最後の行で一時ファイルを削除します。

0
Jesus Segnini

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

たぶんそれは誰かを助けます

0
Senica Gonzalez