24
20

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Docker上でpythonのプログラムをcronで定期実行する

Last updated at Posted at 2018-04-25

はじめに

docker上でpythonのプログラムを定期実行しようと思い,cronで動かそうと思ったらかなりハマったのでそのメモ.
pythonならscheduleやcronのライブラリがあるのでそれらを利用すれば早いし,そもそもdockerプロセス自体をcronで定期実行すれば良いが,1コンテナ1プロセスの精神や,移植性を考えて無理やりコンテナ内で動かした.

実験に使ったプログラムはこちら

実行するPythonプログラム

load_json.py
# coding: utf-8
import json

f = open( './test.json' )
json_data = json.load( f )
f.close()

print( json_data )
test.json
{
  "国語":90,
  "数学":100,
  "理科":85,
  "社会":100,
  "英語":20
}

テスト用に,単純にjsonを解析して,コンソール上に出力するだけのプログラムを作った.このプログラムの実行結果は以下の通り.

$ python load_json.py
{'国語': 90, '数学': 100, '理科': 85, '社会': 100, '英語': 20}

これをコンテナ上でcronで定期実行してみる.

PythonのDockerコンテナの作成

Dockerfile
FROM python:latest

RUN pip install --upgrade pip

RUN apt-get update
RUN apt-get install -y cron

# cron設定ファイルの移動
ADD python-cron /etc/cron.d/python-cron
RUN chmod 0644 /etc/cron.d/python-cron

ADD ./ /

CMD cron && touch /etc/cron.d/simple-cron && tail -f /dev/null
python-cron
* * * * * root python /load_json.py >> /var/log/cron.log 2>&1

cronでpythonプログラムの出力結果を/var/log/cron.logに出力する.コンテナにログインし.正しく実行できているかを確認する.

root@798d72ea2442:/# cat var/log/cron.log
root@798d72ea2442:/#
root@798d72ea2442:/# python /load_json.py
{'国語': 90, '数学': 100, '理科': 85, '社会': 100, '英語': 20}
root@798d72ea2442:/#

コンテナ内での実行はうまくいくのだが,cronの実行ではうまくいっていない.
cronのプログラムの実行の方でエラーが起きて,実行できていないっぽい.

シェルスクリプトにプログラムを記述してそれを実行

先人の投稿を見てみると,cronではシェルスクリプトにプログラムを記述して,それを定期実行させているケースがほとんどだった.ここは思考停止でパクってやってみる.

Dockerfile
FROM python:latest

RUN pip install --upgrade pip

RUN apt-get update
RUN apt-get install -y cron

# cron設定ファイルの移動
ADD python-cron /etc/cron.d/python-cron
RUN chmod 0644 /etc/cron.d/python-cron

ADD ./ /
RUN chmod +x /script.sh  #追加

CMD cron && touch /etc/cron.d/simple-cron && tail -f /dev/null
script.sh
python /load_json.py

ファイルが準備できたらコンテナを動かし,動作確認.

root@8004b8e2114c:/# cat /var/log/cron.log
{u'\u7406\u79d1': 85, u'\u793e\u4f1a': 100, u'\u56fd\u8a9e': 90, u'\u6570\u5b66': 100, u'\u82f1\u8a9e': 20}

実行はできたが,文字化けが起きている.

root@8004b8e2114c:/# python
Python 3.6.4 (default, Mar 14 2018, 17:49:05)
[GCC 4.9.2] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> print(sys.getdefaultencoding())
utf-8

対話モードでpython文字コードを確認して見ても,utf-8となっており,間違っていないはず...

解決:Cronの環境設定

コンテナ内ではプログラムが実行できるのに,cronで定期実行できないのは,文字コードが異なるため,エラーが出て止まっていた.調べたところ,cronではcron内部で環境変数が独立しているため,pythonなどのプログラムは,環境変数を設定しなければ実行ができなかったり,文字化けが起きることがあるらしい.

こちらを参考に,環境変数をcron実行時に読み込ませ,その後pythonプログラムを実行するようにした.

流れとしては,

  1. init.shでコンテナ内の環境変数の出力とcronの実行.
  2. cronで指定した時間にscript.shを実行.
  3. script.shで実行したいプログラムの前に,コンテナ内の環境変数をcronに反映させる.
  4. 実行したいプログラムの実行.
init.sh
#!/bin/sh
printenv | awk '{print "export " $1}' > /root/env.sh
/usr/sbin/cron -f
script.sh
#!/bin/bash
. /root/env.sh
python /load_json.py >> /var/log/cron.log

合わせてDockerfileも,init.shを実行するように修正する.

Dockerfile
FROM python:latest

RUN pip install --upgrade pip

RUN apt-get update
RUN apt-get install -y cron

# cron設定ファイルの移動
ADD python-cron /etc/cron.d/python-cron
RUN chmod 0644 /etc/cron.d/python-cron

ADD ./ /
# init.shにも実行権限の追加
RUN chmod +x /script.sh /init.sh

# CMD cron && touch /etc/cron.d/simple-cron && tail -f /dev/null
CMD /init.sh

動作確認.

root@e411646bab21:/# cat /var/log/cron.log
{'国語': 90, '数学': 100, '理科': 85, '社会': 100, '英語': 20}

まとめ

docker内で動かしたいプログラムをcron実行させるに結構手間がかかることがわかった.
もっとスマートなやり方があったら誰か教えて欲しいです.

参考

https://qiita.com/rerofumi/items/fc0126c4e985b78f769b
https://qiita.com/jmatsu/items/0a5d80abe188b09644c1

24
20
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
24
20

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?