こんにちは!
鍋が美味しくてごきげんな季節になってまいりました。おさむです。
Dockerコンテナでcronによる定期処理を実行したいなあと思いたち、
いろいろ試してみた結果をまとめてみます。
この記事のゴール
粛々と時を刻み続けるDockerコンテナを手に入れる
前提
- Dockerがインストールされており、hello-worldが動作する状態になっていること
試したこと
①あるURLに対して定期的にリクエストを送ってみる
AlpineLinuxはapkというパッケージマネージャにより、コマンドを追加することが出来ます。
この項ではcurlコマンドを追加でインストールし、
それを用いてGoogleのトップページにリクエストを送ってみます。
# 公式版でもたぶんOK
FROM gliderlabs/alpine:latest
# 必要パッケージの取得とタイムゾーンの変更処理(Asia/Tokyo)
RUN \
apk add --no-cache curl tzdata && \
cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime && \
apk del tzdata
# あらかじめ用意しておいたcrontabs用ファイルをコンテナへコピーする
RUN mkdir -p /var/spool/cron/crontabs
COPY ./resource/cron/crontabs/root /var/spool/cron/crontabs/root
CMD busybox crond -l 2 -L /dev/stderr -f
# GoogleへGETリクエストを送信し、帰ってきたレスポンスのヘッダをひたすら追記していく
* * * * * curl https://www.google.co.jp/ -I >> /root/header.txt
# POSTも出来る。JSONを特定のAPIに流し込んだり。
# * * * * * curl -X POST -H "Content-Type: application/json" -d '{"id":"114514", "num":"810"}' localhost:8080/api
②定期的に別コンテナのコマンドを実行してみる
コンテナの中にdockerのバイナリを配置し、ホストマシンにある/var/run/docker.sockをマウントすると、
Dockerコンテナの中からでも別コンテナの操作が可能になります。
これを利用して他のコンテナのコマンドを実行してみました。
ただし、ちょっとトリッキーな方法であるため、こちらで言及されている通りWebAPI化し、
①の方法でリクエストを発行したほうが良いかもしれません。お好みで。
今度は複数のコンテナで連携するため、docker-composeも使用していきます。
version: '2'
services:
app:
build: ./app
cron:
build: ./cron
volumes:
- /var/run/docker.sock:/var/run/docker.sock
volumes:
db-data:
# 公式版でもたぶんOK
FROM gliderlabs/alpine:latest
# 必要パッケージの取得とタイムゾーンの変更処理(Asia/Tokyo)
RUN \
apk add --no-cache tzdata && \
cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime && \
apk del tzdata
# dockerのバイナリを取得し、クライアントのみを/usr/local/binへコピー
RUN apk add --no-cache ssl_client && \
mkdir -p /usr/local/bin && \
wget https://get.docker.com/builds/Linux/x86_64/docker-latest.tgz -O - | tar -xzC /usr/local/bin --strip=1 docker/docker
# あらかじめ用意しておいたcrontabs用ファイルをコンテナへコピーする
RUN mkdir -p /var/spool/cron/crontabs
COPY ./resource/cron/crontabs/root /var/spool/cron/crontabs/root
CMD busybox crond -l 2 -L /dev/stderr -f
# appコンテナにあるコマンドを実行する
* * * * * docker exec example_app_1 /root/example.sh
# ちなみに、Laravelのスケジュール実行も同じ要領で起動できる
# * * * * * docker exec example_app_1 php artisan schedule:run
余談
なんでこんな事してるかと言うと、↑の「Laravelのスケジュール実行」を実現したかったから。
php-fpmをFROMに書いたDockerfileの中で無理やりbusyboxを起動するというのもアリなんですが、
それをするとphp-fpmのプロセスが上がってこないという現象が発生したりで色々と難があったため。
参考
Dockerコンテナ上でCronを動かしたい
curlコマンドを実行するだけのDockerfile
Alpine Linux でタイムゾーンを変更する
Alpine LinuxでDockerコンテナ開発を加速する
Docker コンテナから別のコンテナへコマンドを実行し、返り値を得る