カテゴリー
【ラスパイでも動作可能】CronをつかってDockerコンテナのシェルスクリプトを定期実行する
※ 当ページには【広告/PR】を含む場合があります。
2020/09/03
2025/07/06
cronはLinux標準搭載のスケジューラーデーモンです。
ラズパイでcronがしたいと思い立ったが吉日、早速cronの初回設定と、ちょっとばかしの応用テクをご紹介します。
ラズパイでのcron動作環境の確認
まずはRapberry Pi OS Linuxの環境下でcron環境を有効化するための手順を確認していきましょう。
cronのサービス起動(初回)
cronは何もしないと停止したままなので、ラズパイ起動時に常駐するように設定を起こす必要があります。
まずシスログデーモンにcronを登録します。
以下、
/etc/rsyslog.conf
$ cat /etc/rsyslog.conf
#...中略
#cron.* /var/log/cron.log
#...以下略
と、cronの行がコメントアウトされているので、コメントアウトを削除します。
$ cat /etc/rsyslog.conf
#...中略
cron.* /var/log/cron.log
#...以下略
変更を反映するため、シスログデーモンを再起動します。
$ sudo /etc/init.d/rsyslog restart
次にcronのプログラム設定ファイル
/etc/default/cron
-L 15
$ cat /etc/default/cron
#Cron configuration options
#...中略
EXTRA_OPTS="-L 15"
設定変更後はデーモンの再起動します
$ sudo /etc/init.d/cron restart
これで
/var/log/
cron.log
cron設定ファイル(crontab)の確認
まずcronの大元の設定ファイルは
/etc/crontab
$ cat /etc/crontab
#/etc/crontab: system-wide crontab
#Unlike any other crontab you don't have to run the `crontab'
#command to install the new version when you edit this file
#and files in /etc/cron.d. These files also have username fields,
#that none of the other crontabs do.
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
#Example of job definition:
#.---------------- minute (0 - 59)
#| .------------- hour (0 - 23)
#| | .---------- day of month (1 - 31)
#| | | .------- month (1 - 12) OR jan,feb,mar,apr ...
#| | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
#| | | | |
#* * * * * user-name command to be executed
17 * * * * root cd / && run-parts --report /etc/cron.hourly
25 6 * * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
47 6 * * 7 root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
52 6 1 * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )
何やらワサワサと出ておりますが、この内容の下の方の
Job defination
/etc/crontab
crontab
コマンド: crontab
オプション:
-u <ユーザ名>:
設定するcrontabのユーザ名を指定する
(省略すると現在のデフォルトユーザー名, rootなど)
-e:
cron設定ファイルの編集
-l:
登録済みのスケジュール一覧を表示
-r:
登録されているスケジュールの削除
詳しくは
man crontab
余談 ~ "/etc/crontab"の直接編集 vs. "crontab -e"
まず自分専用のパソコンなどでcronを一人占めして使うなら、
/etc/crontab
/etc/cron.d/
ただし、複数のユーザーが利用する環境でcronを使いたい場合、後々ユーザー管理を考慮すると
/etc/crontab
crontab -e
crontab -e
/var/spool/cron/<ユーザー名>
なおこの記事では
crontab -e
cronの動作テスト
毎分'Hello cron'をファイルに書き込み
$ crontab -e
#エディタが開くので以下のコマンドを挿入...
* * * * * echo 'Hello cron' >> /tmp/cron.test.txt
#編集後に保存...
$ crontab -l
#...中略
* * * * * echo 'Hello cron' >> /tmp/cron.test.txt
このcronスクリプトを有効にして暫く待ってから
/tmp/cron.test.txt
$ cat /tmp/cron.test.txt
Hello cron
Hello cron
Hello cron
Hello cron
となっており、毎分文字行が書き込まれているスケジュールが正常に動作していることが分かります。
テストが延々と書き込まれていると厄介なので、このスケジュールを削除をしてみます。
$ crontab -r
$ crontab -l
no crontab for new-user
でスケジュールが削除されました。 なお、
crontab -r
crontab -e
cronからdockerコンテナ内の対象プログラムをスケジュール実行する
ここではラズパイへのDockerのインストール手順は取り上げませんが、そちらを知りたい方は
練習編 〜 hello worldイメージを使ってみる
通常ホスト側に影響を与えるようなDockerコンテナ内部のプログラムを実行する場合には、Docker側の設定を実行するプログラムに見合った権限で正しく設定する必要があり、特にラズパイ側のデバイスを利用する場合には、特権コンテナで立ち上げることもしばしばです。
Dockerコンテナ内のcronも例外ではなく、コンテナを立ち上げるときに色々と込み入った権限を与えないといけなくなります。 考えるのも面倒で
--privileged
ということで、ホスト側のOSがLinuxなら、素直にホスト側のcronからDockerコンテナ内のプログラムを実行するようにスケジュールするほうがベターです。
即席利用できる最も軽量な
hello-world
$ docker pull hello-world
$ docker images
REPOSITORY TAG SIZE
hello-world latest 4.85kB
毎回cronを実行するたびに、コンテナを生成・起動する(
run
$ docker create --name='my-hello-world' hello-world
bdfde8721d6bbfe95c200b779ec3d7653e678c63bb03995480e5065893bf44f3
$ docker ps -a
CONTAINER ID IMAGE COMMAND STATUS NAMES
bdfde8721d6b hello-world "/hello" Created my-hello-world
これで
my-hello-world
ラズパイ起動時に生成したコンテナも起動させたい場合には、生成オプションに
--restart=always
restart
no
実際にコンテナをアタッチモードで起動してみます。
$ docker start -a my-hello-world
Hello from Docker!
#...以下略
これでコンテナが起動状態になり、内部で
hello
なお停止させる場合には
docker stop <コンテナ名>
では、これをラズパイ側のcronに登録して、毎分出力のログを取るようにスケジュールを登録してみます。
$ crontab -e
#1分毎にdocker startを使用してコンテナ内のプログラムを実行
* * * * * docker start -a my-hello-world >> /tmp/cron.hello-docker.log
この設定を保存して、しばらく待ち、ログが書き込まれているかを確認します。
$ cat /tmp/cron.hello-docker.log
Hello from Docker!
#...以下出力が繰り返しログされる
Dockerコンテナ内で実行されたプログラムの結果はホスト側のログに記録されます。 (終わったら
crontab -r
実用編〜alpineイメージでの利用
とりあえずデモに使用した
hello-world
hello
せめて最小限のシェルコマンドが使いたいので、
alpine
docker exec
上の手順と同様に、まずイメージをプルして、名前付きでコンテナを生成します。
$ docker pull alpine
$ docker images
REPOSITORY TAG SIZE
alpine latest 3.74MB
今回のコンテナはインタラクティブモードに指定することでコンテナプロセスの標準入力を開き、擬似tty付きで生成します。 そうでないと
docker exec
$ docker create -it --init --name my-alpine alpine
$ docker start my-alpine
$ docker ps
CONTAINER ID IMAGE COMMAND STATUS NAMES
b5f8b73892a6 alpine "/bin/sh" Up my-alpine
ちなみですが、
docker create + docker start
docker run
$ docker run -d -it --init --name my-alpine alpine
$ docker ps
CONTAINER ID IMAGE COMMAND STATUS NAMES
b5f8b73892a6 alpine "/bin/sh" Up my-alpine
めでたく
my-alpine
docker exec
$ docker exec my-alpine echo 'Hello alpine!'
Hello alpine!
$ docker exec my-alpine date
Thu Sep 3 08:22:44 UTC 2020
動作も早くていい感じです。
これをラズパイ側のcronに登録して、毎分出力のログを取るようにスケジュールを登録してみます。
$ crontab -e
#1分毎にdocker execを使用してコンテナ内のプログラムを実行
* * * * * docker exec my-alpine date >> /tmp/cron.alpine-docker.log
しばらくしてからログを除くと、
$ cat /tmp/cron.alpine-docker.log
Thu Sep 3 08:28:02 UTC 2020
Thu Sep 3 08:29:01 UTC 2020
Thu Sep 3 08:30:02 UTC 2020
Thu Sep 3 08:31:01 UTC 2020
Thu Sep 3 08:32:02 UTC 2020
Thu Sep 3 08:33:01 UTC 2020
として一分間隔で出力が記録されています。
急なHotfix ~ ある日突然動かなくなるときに
Raspberry Pi OSをパッケージアップデートとかを気が付いた時にやってみた後などはなんだかcronが動かなったりします。
原因が定かではないけれど、普段は動いていたのに唐突に機能が停止してしまったような場合でまずはサービスデーモンの再起動をかけて様子をみましょう。
$ sudo /etc/init.d/cron restart
これで駄目なら、仕方が無いのでラズパイ本体の再起動をかけます。
それでも駄目ならスケジュール登録しているコマンドのどこかにアップデートなどの影響で誤作動を引き起こしている箇所がある可能性が高いですので、
crontab -l
まとめ
今回はラズパイ&Dockerの環境でもcronが使えることを確認しました。
例に取り上げたプログラム程度ならわざわざDockerを呼び出すことはないでしょうけれど、使いどころによっては面白い応用ができそうではあります。
記事を書いた人
ナンデモ系エンジニア
主にAngularでフロントエンド開発することが多いです。 開発環境はLinuxメインで進めているので、シェルコマンドも多用しております。 コツコツとプログラミングするのが好きな人間です。
カテゴリー