DockerでDjangoとCronを実行する方法

docker Django cron

私はこちらのDockerを使っています。

https://github.com/dockerfiles/django-uwsgi-nginx

GitHubからクローンを作成し、その中のappフォルダの中にDjangoのプロジェクトを作成しています。

Nginx uwsgi django を一気に起動してくれるのでとても重宝しています。

しかし、Cronを実行しようとDockerfileの中でいろいろやってみたのですがなかなかうまく行きませんでした。Cronが起動するとNginxが起動しなくなり、Nginxが起動するとCronが起動するというあっちを立てればこっちが立たず。みたいな状況になりました。

最終的に supervisor-app.conf を編集すればいいんだ!ということに気づいたのでその紹介です。

supervisor-appを編集

標準ではこの様になっています。

[code] [program:app-uwsgi] command = /usr/local/bin/uwsgi –ini /home/docker/code/uwsgi.ini

[program:nginx-app] command = /usr/sbin/nginx

[/code]

ここにCronを追加します。

[code] [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

[/code]

まずはこれを保存します。

Cronのファイルと実行ファイルを用意

続いてCronの定義と実行ファイルを用意します。

ここで注意が必要なのがコンテナの環境変数をCronでは引き継ぎません。

なので、コンテナの環境変数を書き出して、Cron実行時に読み込ませる必要があります。

[Docker]コンテナの環境変数を書き出す

コンテナを起動して docker ps でコンテナIDを確認してから

docker exec -it コンテナID /bin/bash でコンテナに入ります。

そして、下記のコードを実行します。

[code]
printenv | awk '{print "export " $1}' > /root/env.sh
[/code]

/root/env.sh にファイルが作成されるのでcat で表示します。

[code]cat /root/env.sh[/code]

表示したら、内容をコピーします。

[code]export TERM=xterm
export LC_ALL=en_US.UTF-8
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
export PWD=/root
export LANG=en_US.UTF-8
export TZ=Asia/Tokyo
export SHLVL=1
export HOME=/root
export LANGUAGE=en_US:en
export PYTHONPATH=/usr/bin/python3
export DEBCONF_NOWARNINGS=yes
export LESSOPEN=|
export LESSCLOSE=/usr/bin/lesspipe
export _=/usr/bin/printenv
export OLDPWD=/var/log
[/code]

↑こちらに書いているコードはもう少しいろいろ表示されるのですが、コンテナを起動するたびに変わる環境変数があるので読み込んでもエラーになります。渡しの場合は不要だったので削除しました。

保存先はローカルのPCで、下記のようにcronフォルダを作ってその中にenv.shというファイルを作って保存します。

Docker django cron実行

実行したいコマンドのシェルを作成

続いて、実行させたいコマンドのシェルを作成します。

私の場合はget_order.shとsend_mail.shがそれに当たります。

get_order.shの中身はこんな感じです。

[code]

#!/bin/sh
. /home/docker/code/cron/env.sh
/usr/bin/python3 /home/docker/code/app/manage.py get_orders >> /var/log/get_orders 2>&1
[/code]

1行目はお決まりのやつで、2行目は先程保存したenv.shをcron実行時に読み込ませるために入れています。

3行目はお好みのコマンドを入力してください。

 

こちらの記事を参考にさせてもらいました。

Cronファイルを用意する

cronフォルダの中にcrontabというファイルを作って、その中にcronを書いていきます。

[code]

# m h dom mon dow user command
* * * * * /home/docker/code/cron/get_order.sh
*/5 * * * * /home/docker/code/cron/send_mail.sh

[/code]

私の場合はこんな感じで書きました。ここで指定しているシェルは先程作成したやつです。

 

DockerにCronをインストールする

DockerファイルのCMDの直前あたりに下記のコマンドを追記します。

[code]

RUN apt-get clean && apt-get update && apt-get install -y locales tzdata cron

#for encode setting
# set the locale
RUN locale-gen en_US.UTF-8
ENV LANG en_US.UTF-8
ENV LANGUAGE en_US:en
ENV LC_ALL en_US.UTF-8
ENV TZ=Asia/Tokyo

RUN chmod 0744 /home/docker/code/cron/*
RUN crontab /home/docker/code/cron/crontab

[/code]

大事なのは初めの1行と最後の2行です。1行目でcronをインストールしています。最後から2行目でcronフォルダ直下の先ほど作成したファイルに実行権限を与えています。

実行権限を与え忘れて、「あれ?動かない‥?」ってよくなるやつです。(私だけでしょうか?)

最後の1行はcronを読み込んでいます。

これだけでもいいのですが、Cronを利用するということはタイムゾーンの設定とか必要だと思うのでロケーションとかランゲージの設定を追加しています。

これがないと、標準時でCronが実行されたり、日本語を含むファイルを実行したときに文字コードでエラーになったりして苦しみます。

 

 

1 Comment

コメントを残す

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください