Closed3

Dockerでcronを動かす

Dockerでcronを動かそうとしているのですが、設定したPGMが実行されない(原因不明)

alpineベースだとうまくいかないのかもなので、Debianベースで試してみようかな。
または公開されているcron用イメージを使ってみるとかか。

https://hub.docker.com/r/willfarrell/crontab

https://qiita.com/YuukiMiyoshi/items/bb7f14436d60d4bd8a8b
https://qiita.com/reflet/items/7e117c246f55f0e1d87b
https://ja.stackoverflow.com/questions/67124/docker-compose-ymlでcronを実行したい
https://zenn.dev/kiyo_tech/articles/8e79e9873ff687

実装

docker-compose.yml

version: "3"
services:
  # 上に色々なサービスが記載...
  cron:
    build: ./cron
    volumes:
      - ./cron/root:/var/spool/cron/crontabs/root

./cron/DockerFile

FROM alpine:3.14

# 必要パッケージの取得とタイムゾーンの変更処理(Asia/Tokyo)
ENV TZ=Asia/Tokyo
RUN apk update
RUN apk --no-cache add 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 --chown=root:root root /var/spool/cron/crontabs/root

CMD crond -l 2 -f

./cron/root

* * * * * echo 'test' >> /var/log/test.log
* * * * * echo '=== environment variables ===' && env

状況

  • cronコンテナに入りps auxで確認したところcrondは動いている
  • cron自体の実行ログが出力されてない(/var/log/cron)
  • cronで実行される「echo 'test' >> /var/log/test.log」で吐くはずのログが出力されていない(/var/log/test.log)
# ps aux
PID   USER     TIME  COMMAND
    1 root      0:00 busybox crond -l 2 -L /dev/stderr -f
    8 root      0:00 /bin/sh
   15 root      0:00 ps aux
$ docker-compose logs cron
Attaching to docker_cron_1
cron_1          | crond: crond (busybox 1.33.1) started, log level 2
cron_1          | crond: wakeup dt=15
cron_1          | crond: wakeup dt=60
cron_1          | crond: wakeup dt=60
cron_1          | crond: wakeup dt=60
cron_1          | crond: wakeup dt=60
cron_1          | crond: wakeup dt=60
cron_1          | crond: wakeup dt=60
cron_1          | crond: wakeup dt=60
cron_1          | crond: wakeup dt=60
cron_1          | crond: wakeup dt=60
cron_1          | crond: wakeup dt=60
cron_1          | crond: wakeup dt=60
cron_1          | crond: wakeup dt=60
cron_1          | crond: wakeup dt=60
cron_1          | crond: wakeup dt=60
cron_1          | crond: wakeup dt=60
cron_1          | crond: wakeup dt=60
cron_1          | crond: wakeup dt=60
cron_1          | crond: wakeup dt=60
cron_1          | crond: wakeup dt=60
cron_1          | crond: wakeup dt=60
cron_1          | crond: wakeup dt=60

分からない

  • crondの設定ファイル(/etc/crontab)が存在しないがどこで設定されている?
  • crondのログ出力場所の設定ってどこでやっている?(実行ログは/var/log/cronとネットで調べると出てくるがそのファイルが生成されてない)

https://www.express.nec.co.jp/linux/distributions/knowledge/system/crond.html
https://stackoverflow.com/questions/58577707/alpine-service-crond-does-not-exist
https://www.mtioutput.com/entry/cron-log-notfind

alpineとは

https://qiita.com/ryuichi1208/items/6020cfabc92bd8153654
  • 組み込み系でよく使われているBusyBoxとmuslをベースにしたLinuxディストリビューション
  • BusyBox + パッケージマネージャ(apk)
  • busyboxとは:Alpine LinuxのベースとなっているLinuxのディストリビューション

willfarrell/crontabのイメージ使うことでうまくいった。

https://hub.docker.com/r/willfarrell/crontab/
https://github.com/willfarrell/docker-crontab

実装

docker-compose.yml

version: "3"
services:
  # 上に色々なサービスが設定されている
  cron:
    build: ./cron
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock

docker.sockについてはプルリクに上がっているため、今後指定しなくてもよくなりそう。

https://github.com/willfarrell/docker-crontab/issues/46
https://github.com/willfarrell/docker-crontab/pull/47

./cron/DockerFile

FROM willfarrell/crontab:1.0.0

COPY config.json ${HOME_DIR}/

./cron/config.json

[{
    "schedule":"@every 1m",
    "command":"echo 'test1111' >> /var/log/test.log"
},{
    "comment": "laravel schedule:run",
    "schedule":"* * * * *",
    "command": "php artisan schedule:run",
    "project": "docker",
    "container": "php"
}]

ログ

$ docker-compose logs cron
Attaching to docker_cron_1
cron_1          | ##### crontab generation complete #####
cron_1          | */1 * * * * /bin/bash /opt/crontab/jobs/0aef401c-844a-4b01-bf56-1daa8553d5c5.sh
cron_1          | # laravel schedule:run
cron_1          | */1 * * * * /bin/bash /opt/crontab/jobs/b15b847d-ba9b-45c1-a4ae-ff45bd6a4775.sh
cron_1          | ##### run commands with onstart #####
cron_1          | crond -f -d 6 -c /etc/crontabs
cron_1          | crond: crond (busybox 1.31.1) started, log level 6
cron_1          | crond: USER docker pid 132 cmd /bin/bash /opt/crontab/jobs/0aef401c-844a-4b01-bf56-1daa8553d5c5.sh
cron_1          | crond: USER docker pid 133 cmd /bin/bash /opt/crontab/jobs/b15b847d-ba9b-45c1-a4ae-ff45bd6a4775.sh
cron_1          | Start Cronjob **0aef401c-844a-4b01-bf56-1daa8553d5c5** null
cron_1          | End Cronjob **0aef401c-844a-4b01-bf56-1daa8553d5c5** null
cron_1          | Start Cronjob **b15b847d-ba9b-45c1-a4ae-ff45bd6a4775** laravel schedule:run
cron_1          | [2021-10-29T04:07:01+00:00] Running scheduled command: Callback
cron_1          | End Cronjob **b15b847d-ba9b-45c1-a4ae-ff45bd6a4775** laravel schedule:run

config.jsonの設定(Laravelのタスクスケジューラの実行)

cronコンテナからphpコンテナに対してphp artisan schedule:runする場合
下記シェルスクリプトが実行されます。

#!/usr/bin/env bash
set -e

CONTAINERS=$(docker ps --format '{{.Names}}' | grep -E "^docker_php.[0-9]+")
for CONTAINER_NAME in $CONTAINERS; do
    docker exec  ${CONTAINER_NAME} php artisan schedule:run
done

「docker-php-1」に対して実行する場合 「project」は「docker」で
「container」は「php」にして下さい。

$ docker-compose ps
NAME                    COMMAND                  SERVICE             STATUS              PORTS
docker-cron-1           "/sbin/tini -- /dock…"   cron                running (healthy)   
docker-https-portal-1   "/init"                  https-portal        running             0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp
docker-memcached-1      "docker-entrypoint.s…"   memcached           running             0.0.0.0:11211->11211/tcp
docker-mysql-1          "docker-entrypoint.s…"   mysql               running             0.0.0.0:3306->3306/tcp
docker-nginx-1          "/docker-entrypoint.…"   nginx               running             80/tcp
docker-php-1            "docker-php-entrypoi…"   php                 running             9000/tcp

./cron/config.json

[{
    "schedule":"@every 1m",
    "command":"echo 'test1111' >> /var/log/test.log"
},{
    "comment": "laravel schedule:run",
    "schedule":"* * * * *",
    "command": "php artisan schedule:run",
    "project": "docker",
    "container": "php"
}]

docker-composeで、自動生成されるコンテナ名がローカルと本番サーバで異なる事象が起き
cronコンテナ→phpコンテナに入れずcronが実行されなかった。
(ローカル:docker_php_1 本番:docker-php-1になっていた。container_nameは未指定のためコンテナ名は自動生成)

ログ

ローカル

$ docker-compose ps
        Name                       Command                  State                                       Ports                                 
----------------------------------------------------------------------------------------------------------------------------------------------
docker_cron_1           /sbin/tini -- /docker-entr ...   Up (healthy)                                                                         
docker_https-portal_1   /init                            Up             0.0.0.0:443->443/tcp,:::443->443/tcp, 0.0.0.0:80->80/tcp,:::80->80/tcp
docker_memcached_1      docker-entrypoint.sh memcached   Up             0.0.0.0:11211->11211/tcp,:::11211->11211/tcp                          
docker_mysql_1          docker-entrypoint.sh mysqld      Up             0.0.0.0:3306->3306/tcp,:::3306->3306/tcp, 33060/tcp                   
docker_nginx_1          /docker-entrypoint.sh ngin ...   Up             80/tcp                                                                
docker_php_1            docker-php-entrypoint php-fpm    Up             9000/tcp

本番

$ docker-compose ps
NAME                    COMMAND                  SERVICE             STATUS              PORTS
docker-cron-1           "/sbin/tini -- /dock…"   cron                running (healthy)   
docker-https-portal-1   "/init"                  https-portal        running             0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp
docker-memcached-1      "docker-entrypoint.s…"   memcached           running             0.0.0.0:11211->11211/tcp
docker-mysql-1          "docker-entrypoint.s…"   mysql               running             0.0.0.0:3306->3306/tcp
docker-nginx-1          "/docker-entrypoint.…"   nginx               running             80/tcp
docker-php-1            "docker-php-entrypoi…"   php                 running             9000/tcp

コンテナ名の自動生成ルール

docker-composeでcontainer_nameを指定するとそのコンテナ名で生成される。
container_name を指定しない場合はCOMPOSE_PROJECT_NAME 変数 + _ + サービス名 + _ + 連番

https://qiita.com/okashoi/items/1ddf3724ad5c166e417b

対応

container_nameを指定(docker_php_1)
docker_php.[0-9]+に合わせる({project}_{container}.[0-9]+)

config.json

[{
    "comment": "laravel schedule:run",
    "schedule":"* * * * *",
    "command": "php artisan schedule:run",
    "project": "docker",
    "container": "php"
}]
#!/usr/bin/env bash
set -e

CONTAINERS=$(docker ps --format '{{.Names}}' | grep -E "^docker_php.[0-9]+")
for CONTAINER_NAME in $CONTAINERS; do
    docker exec  ${CONTAINER_NAME} php artisan schedule:run
done

docker-compose.yml

version: "3"
services:
  php:
    container_name: 'docker_php_1'
    build: ./php
    volumes:
      - ../src:/usr/share/nginx/html
      - ./php/php.ini:/usr/local/etc/php/conf.d/php.ini
    depends_on: 
      - "mysql"
      - "memcached"
  # 省略
  cron:
    container_name: 'docker_cron_1'
    build: ./cron
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
このスクラップは2021/10/29にクローズされました
作成者以外のコメントは許可されていません