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

コンテナ内で実行環境を構築する場合、スクリプトを定期的に動かすために、コンテナ内で cron を起動します。

Dockerfile に cron のインストールを追加します。

RUN apt update && apt install -y cron

docker-compose.yml で environment に PYTHONPATH などの環境変数を指定します。

environment:
  - PYTHONPATH=$${PYTHONPATH}:/home/user/modules

Python 側でサーバを起動する際に、subprocess.Popen() で cron を起動します:

subprocess.Popen(['cron', '-f'])

そして、定期実行のスクリプトに引数を追加し、実行対象となるシェルスクリプトを生成して、ジョブを登録します。

注意すべきなのは、環境変数 PYTHONPATH を設定し、Python インタプリタのフルパスを指定する必要があります。

import os
import subprocess
from pathlib import Path
from argparse import ArgumentParser


if __name__ == '__main__':
    parser = ArgumentParser()
    parser.add_argument('--cron', action="store_true")
    args = parser.parse_args()
    if args.cron:
        py_path = os.environ.get('PYTHONPATH')
        fp = Path(__file__).absolute()
        content = (
            '#!/bin/bash\n'
            f'export PYTHONPATH={py_path}\n'
            f'/root/miniconda3/bin/python {str(fp)}'
            ' > /root/cron.log 2>&1'
        )
        sh_fp = Path.home() / 'my_script.sh'
        with open(sh_fp, 'w') as sh:
            sh.write(content)
        # ジョブをCronに登録
        cmd = (f'crontab -l | {{ cat; echo "0 12 * * * /bin/bash {sh_fp}"; }}'
               ' | crontab -')
        subprocess.run(cmd, shell=True)