こんばんはエンジニアの眠れない夜です。
django-uwsgi-nginxをベースにcronを実行する方法です。
これからDjangoで開発を始めるという方はdjango-uwsgi-nginx-cronを作ったのでこちらをクローンして開発を始めるととてもスムーズに進められます。
git clone https://github.com/sleepless-se/django-uwsgi-nginx-cron
GitHubからクローンを作成し、その中のappフォルダの中にDjangoのプロジェクトを作成しています。(この辺は本家と同じです。Nginx uwsgi django を一気に起動してくれるのでとても重宝しています。)
cronを実行しようとDockerfileの中でいろいろやってみたのですがなかなかうまくいかなかったのでdjango-uwsgi-nginx-cronを作成しました。
その中で、cronが起動するとNginxが起動しなくなり、Nginxが起動するとcronが起動するというあっちを立てればこっちが立たず。みたいな状況になりました。
最終的にsupervisor-app.conf
を編集すればいいんだ!ということに気づいたのでその紹介です。
supervisor-appを編集
標準ではこの様になっています。
[program:app-uwsgi]
command = /usr/local/bin/uwsgi --ini /home/docker/code/uwsgi.ini
[program:nginx-app]
command = /usr/sbin/nginx
ここにcronを追加します。
[program:app-uwsgi]
command = /usr/local/bin/uwsgi --ini /home/docker/code/uwsgi.ini
[program:nginx-app]
command = /usr/sbin/nginx
[program:cron]
command =cron -f
autostart=true
autorestart=true
stdout_logfile=/var/log/supervisor/%(program_name)s.log
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
まずはこれを保存します。
cronのファイルと実行ファイルを用意
続いてcronの定義と実行ファイルを用意します。
ここで注意が必要なのがコンテナの環境変数をcronでは引き継ぎません。
なので、コンテナの環境変数を書き出して、cron実行時に読み込ませる必要があります。
[Docker]コンテナの環境変数を書き出す
コンテナを起動して docker ps でコンテナIDを確認してから
docker exec -it コンテナID /bin/bash
でコンテナに入ります。
そして、下記のコードを実行します。
printenv | awk '{print "export " $1}' > /root/env.sh
/root/env.sh にファイルが作成されるのでcat で表示します。
cat /root/env.sh
表示したら、内容をコピーします。
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
export LANG=ja_JP.utf8
export TZ=Asia/Tokyo
export PYTHONPATH=/usr/bin/python3
↑こちらに書いているコードはもう少しいろいろ表示されるのですが、コンテナを起動するたびに変わる環境変数があるので読み込んでもエラーになります。
私は不要だったので削除しました。多分必要なのはこれだけのはず。他にも必要なものがあれば各自追加してください。
保存先はローカルのPCで、下記のようにcronフォルダを作ってその中にenv.shというファイルを作って保存します。
環境変数のとり方はこちらの記事を参考にさせていただきました。
cronファイルを用意する
cronフォルダの中にcrontabというファイルを作って、その中にcronを書いていきます。
# m h dom mon dow user command
* * * * * . /home/docker/code/cron/env.sh && export >> /home/docker/code/cron/export.log
※ crontabの最後には必ず改行を1行入れましょう。これがないとcronでインポートしたときにエラーが出ます。これ↓
new crontab file is missing newline before EOF, can't install.
コマンドの解説
1 . /home/docker/code/cron/env.sh
で先程保存した環境変数を読み込んでいます。これがないとパスが通っていないのでcronを実行してもpythonやdjangoが動かない。という事態になります。.
はsource
と同意です。
2 &&
の後に実行したいコマンド
を書きます。ここでは環境変数がきちんと読み込まれているかを確認するためにexport
を実行しています。
3 最後に、そのログを出力すると行った感じです。
Dockerにcronをインストールする
DockerファイルのCMDの直前あたりに下記のコマンドを追記します。
RUN apt-get clean && apt-get update && apt-get install -y locales tzdata cron
#for encode setting
# set the locale
ENV LANG ja_JP.UTF-8
ENV TZ=Asia/Tokyo
RUN chmod 0744 /home/docker/code/cron/*
RUN crontab /home/docker/code/cron/crontab
大事なのは初めの1行と最後の2行です。1行目でcronをインストールしています。最後から2行目でcronフォルダ直下の先ほど作成したファイルに実行権限を与えています。
実行権限を与え忘れて、「あれ?動かない‥?」ってよくなるやつです。(私だけでしょうか?)
最後の1行はcronを読み込んでいます。
これだけでもいいのですが、cronを利用するということはタイムゾーンの設定が必要なのでTZとかLANGの設定を追加しています。
これがないと、標準時でcronが実行されたり、日本語を含むファイルを実行したときに文字コードでエラーになったりして苦しみます。
長くなりましたが、django-uwsgi-nginx-cronを使ってもらえばdjangoとcronをサクッと動かせる環境が手に入ります(^^)v
※ django-uwsgi-nginxを使ったことがない方はReadmeをご確認ください。
djangoのモデルなどを使ったスクリプトを作る場合はカスタムコマンドを作ってそれをcronから呼び出すといいです。カスタムコマンドの作成方法はこちら
[…] DockerでDjangoとCronを実行する方法 を御覧ください。 […]