67154


Railsのwheneverを利用して、docker-
compose.ymlの`command`でcronを実行後、ジョブの登録をしたいのですが、ジョブ登録コマンドの動作がうまくいかない状況です。

[code]

    command: >
          bash -c "
          cron -f; # cron起動
          bundle exec whenever --update-crontab; # ジョブ登録
          "
    
[/code]

`docker-compose up`時に、cron起動コマンドからジョブ登録コマンドまで一通りは実行されるものの、  
`docker-compose exec railsコンテナのサービス名 bash`でbashに入り、登録されたジョブを確認（`crontab
-l`）すると、何も登録されていないと表示されてしまいます。

[code]

    no crontab for root
    
[/code]

ただbashに入ってから、ジョブ登録コマンドを実行すると正常に登録されるのが不思議でわかりません。  
一般的にDocker上でcronを扱うのは結構ネックのようですが、このやり方でもできないのでしょうか？

ご教示いただけると助かります。

Debian環境ですので、手動で行う分にはスケジューラー自体の動作は正常であることを確認しました。

# ソースコード

docker-compose.yml

[code]

    version: '3'
    
    services:
      ruby_base:
        build: .
        tty: true
        stdin_open: true
        volumes:
          - .:/var/www/
        working_dir: /var/www/rails_api
        command: >
          bash -c "
          cron -f;
          bundle exec whenever --update-crontab
          "
    
[/code]

Dockerfile

[code]

    FROM ruby:2.7.1
    
    ENV LANG C.UTF-8
    ENV TZ Asia/Tokyo
    ENV LC_ALL=C
    
    # 必要なパッケージ & スケジューラー & Railsインストール
    RUN apt-get update -qq
    RUN apt-get install -y build-essential cron
    RUN gem install -v 5.2.4 rails --no-document
    
    # プロジェクトディレクトリ名を変数化
    ARG project_name="rails_api"
    
    # Gemfileのインストール
    WORKDIR /var/www/${project_name}
    COPY /${project_name}/Gemfile Gemfile
    COPY /${project_name}/Gemfile.lock Gemfile.lock
    RUN bundle install
    
[/code]

# 追記 （himenonさん） 2020/06/03

debian:busterをimageにして、railsとbusyboxを1つのコンテナとして起動しています。

main.sh

[code]

    #!/bin/sh
    # 初期のディレクトリ場所がrootディレクトリにいるため、cdでrailsのディレクトリまで移動しています
    cd /var/www/プロジェクト名/rails_api;
    bundle exec rake testtask:タスク1
    
[/code]


CC BY-SA 4.0
2020-05-29T12:56:21.987
67124
2020-06-03T06:52:58.420
2020-06-03T06:52:58.420
25223
25223
question
ruby-on-rails docker cron
docker-compose.ymlでcronを実行したい


質問に対する直接的な回答にはなりませんが、cronをdockerで利用するときにハマりがちなので別のやり方を紹介します。

dockerでcronを利用する場合、いろいろ[設定をする必要](https://serverfault.com/questions/924779/docker-
cron-not-working)がありますが、  
busyboxに含まれるcrondを利用すると比較的簡単にcronジョブを仕込むことができます。

この最小サンプル紹介します。

## ディレクトリ構成

[code]

    .
    ├── Dockerfile
    ├── crontab
    ├── docker-compose.yml
    └── main.sh
    
[/code]

### Dockerfile

  * `ruby:2.7.1`のBase Imageをたどると`debian:buster`にたどり着くので、これをベースファイルとしてDockerfileを組み立てます。
  * `busybox crond --help`を実行するとオプションが確認できます。適宜指定してください。

[code]

    FROM debian:buster
    ENV TZ Asia/Tokyo
    RUN apt-get update && apt-get install -y busybox-static
    
    WORKDIR /app
    
    COPY ./main.sh /app/
    
    CMD ["busybox", "crond", "-l", "8", "-L", "/dev/stderr", "-f"]
    
[/code]

### crontab

デバッグ用に1分毎に実行します

[code]

    * * * * * /app/main.sh
    
[/code]

### docker-compose.yml

  * crontabファイルをマウントすることで外部から実行時間を指定できるようにしています。
  * `Dockerfile`内で`CMD`を指定しているので、もしdocker-compose.ymlで`command`指定したい場合は`Dockerfile`を編集してください。

[code]

    version: '3'
    
    services:
      busybox:
        build: .
        volumes:
          - ./crontab:/var/spool/cron/crontabs/root
    
[/code]

### main.sh

  * ※`chmod +x main.sh`を実行済み
  * 質問にあるコマンドを例えばこのファイルに記述することも可能です。
  * この例では日付を出力します。

[code]

    #!/bin/sh
    date
    
[/code]

## 実行

docker-composeを利用する場合

[code]

    docker-compose build   # Docker Image絵をビルド
    docker-compose up -d   # docker-composeをdaemon化
    docker-compose logs -f # ログ出力
    
[/code]

dockerコマンドで実行する場合

[code]

    docker build -t my-busybox:0.0.1 .
    docker run -d --rm -v $(pwd)/crontab:/var/spool/cron/crontabs/root my-busybox:0.0.1
    docker logs -f [container id]
    
[/code]

## 参考

  * <https://packages.debian.org/ja/sid/busybox>


CC BY-SA 4.0
2020-05-31T03:54:46.707
67154
2020-05-31T03:54:46.707
7997
67124
answer


> docker-compose up時に、cron起動コマンドからジョブ登録コマンドまで一通りは実行されるものの、

これはどのように確認しているのでしょうか．  
ジョブ登録が正常に実行されないのは，`cron -f` がフォアグラウンド実行されているため後続の wheneverが実行されていないためです．

dockerコンテナ内でcronを起動するのがあまりよろしくないことを理解した上で実現したいのであれば，  
コマンドの実行順序を逆にするだけで実現できます．  
すなわち，docker-compose.ymlを以下のように修正します．

[code]

        command: >
          bash -c "
          bundle exec whenever --update-crontab；
          cron -f      
          "
    
[/code]


CC BY-SA 4.0
2020-06-02T03:39:22.307
67212
2020-06-02T04:20:03.147
2020-06-02T04:20:03.147
3060
7770
67124
answer