はじめに
cronの説明は参考書でもインターネット上でも豊富に得られますが、anacronについては話題が少ない気がします。私自身、/etc配下に「anacrontab」というファイルがあったことは知っていましたが、「なにこれ?」と思うだけで、実際に調べて検証までする気になりませんでした。でも、知らない中で運用していると、思わぬ所で意図しない動作をすることがわかったので、今回はまとめることに至りました。
なお以下の記事については、私が個人的に検証している環境がCentOS8なので、CentOS8で検証等を行っています。
cronについて
cronについては、違う記事で書いたので、そちらを参考にしていただければと思います。
anacronの設定ファイルと動作
上記cronに対して、anacronって何?と思いますが、まずは設定ファイルから見ていきます。
anacronの設定ファイルは、/etc/anacrontabです。こんな記述があります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
[root@localhost zabbix_logtest]# cat /etc/anacrontab # /etc/anacrontab: configuration file for anacron # See anacron(8) and anacrontab(5) for details. SHELL=/bin/sh PATH=/sbin:/bin:/usr/sbin:/usr/bin MAILTO=root # the maximal random delay added to the base delay of the jobs RANDOM_DELAY=45 # the jobs will be started during the following hours only START_HOURS_RANGE=3-22 #period in days delay in minutes job-identifier command 1 5 cron.daily nice run-parts /etc/cron.daily 7 25 cron.weekly nice run-parts /etc/cron.weekly @monthly 45 cron.monthly nice run-parts /etc/cron.monthly |
細かい仕様はありますが、ポイントは最終の3行です。/etc/cron.daily、/etc/cron.weekly、/etc/cron.monthlyそれぞれの配下のファイルをrun-partsで実行することになっています。/etc/cron.hourlyにあるファイルはanacronの対象ではないことも明記しておきます。
anacrontabの内容を実行する0anacron
/etc/anacrontabを実際に実行するのは、「0anacron」というファイルです。0anacronは/etc/cron.hourly配下にあります。/etc/cron.hourly配下にあるファイルは、/etc/cron.d配下にある「0hourly」というファイルの記述よって、1時間ごと実行されます。つまり、cronが1時間ごとに0anacronを実行し、結果的にanacrontabの内容が実行されることになります。(あくまでも実行されるまでの流れであって、必ずしも実行されないことについては続きをお読みください)
1 2 |
[root@localhost log]# ls /etc/cron.hourly/ 0anacron |
0anacronは履歴を見て実行する
ここで疑問が。「0anacronで1時間に1回実行されるって?1日に1回とか1週間に1回に実行するという話はどこへいった?」と思いますよね。たしかに、1時間に1回「0anacron」は起動しますが、その際にcronのように必ず実行するとは限りません。
anacronは1時間に1回、「anacronが持っている実行履歴を見て」実行をするか判断します。つまり、実行するかどうかは履歴の情報次第となります。
anacronの実行履歴は、「/var/spool/anacron」配下にそれぞれdaily、weekly、monthlyの履歴が記録されています。
1 2 3 4 5 6 |
[root@localhost ~]# cat /var/spool/anacron/cron.daily 20201001 [root@localhost ~]# cat /var/spool/anacron/cron.weekly 20200930 [root@localhost ~]# cat /var/spool/anacron/cron.monthly 20200930 |
anacronは1時間ごとに上記の履歴を確認しに行き、その日やるべきjobが実行されたかを履歴をもとに確認します。実行されていれば何もしないし、実行されていなかったら実行するという仕組みをとっています。
お気づきの通り、cron.hourlyの記述はありません。/etc/cron.hourly配下のファイルについては、上記でも述べた通り/etc/cron.d配下にある0hourlyが実行します。これまでの話をまとめると、次のよう表が作れます。
ディレクトリ配下のファイル | 実行するファイル |
/etc/cron.hourly/ | /etc/cron.d/0hourly |
/etc/cron.daily | anacron |
/etc/cron.weekly | anacron |
/etc/cron.monthly | anacron |
anacronを知らないと発生する問題
かつてはanacronという仕組みはありませんでした。比較的に新しい仕組みのようです。
なので、anacronが無かったかつてのcronは、以下のようにcrontabに全て書かれていたようです。
1 2 3 4 5 6 7 8 9 |
[root@localhost ~]# cat /etc/cron.d/0hourly # Run the hourly jobs SHELL=/bin/bash PATH=/sbin:/bin:/usr/sbin:/usr/bin MAILTO=root 01 * * * * root run-parts /etc/cron.hourly 01 12 * * * root run-parts /etc/cron.daily 01 12 1 * * root run-parts /etc/cron.weekly 01 12 1 1 * root run-parts /etc/cron.monthly |
上記のような書き方は、参考書などでも一例として書かれていることがあります(割と有名なIT資格の参考書とかね)。それは、anacronが動作していないことが前提になっています。
では、anacronも動いていて、crontabにも上記のように書いていたらエラーが発生するかというと、「エラーにならない」という答えになります。
上記設定を仮に書いてしまった場合、cronとanacronは独自して動くので1日1回実行して欲しいことでも、crontabに記載された分で1回、anacronで1回実行されます。
全部crontabで制御したい!という人はanacronが動作しないようにする必要があります。
全部crontabじゃだめ?
出来ないことはないけど、それなりに問題があったらかanacronが出来たという考えが自然でしょう。上記のcrontabには分かりやすい欠点がありました。それは、「指定した時刻にシステムが停止していると、実行できない」という問題です。
システム停止が続くなんてことは大事件なのでそう起こりませんが、システムメンテナンスのために定期的にシステムを一時的に落とすことはよくあります(よくと言っても毎日とかではないけどね)。メンテナンスの際に、cronのスケジュールを意識するのは、正直面倒なことですし、cronのスケジュールをその都度変えるのも億劫。ただ、実行されないのも困る…。ということが起こってしまいます。
時間の指定が曖昧なanacron
ご察しの通り、上記のような1日の中にシステムが停止している時間があっても関係なく実行してくれるのがanacronのメリットでもあります。以下、本番環境ではできないOSの時間を意図的に変えて、anacronの動作を見てみたいと思います。
検証
anacronのステータスを確認する
まず、直前に実行した履歴を確認します。
1 2 3 4 5 6 |
[root@localhost ~]# cat /var/spool/anacron/cron.daily 20201001 [root@localhost ~]# cat /var/spool/anacron/cron.weekly 20200930 [root@localhost ~]# cat /var/spool/anacron/cron.monthly 20200930 |
1日に1回実行するものは「2020年10月1日」が最後の実行履歴になっていますね。(週に1回、1か月に1回の実行するもの9月30日です)
日付を意図的にずらしてみる
dailyが20201001なので、日付をずらしてみます。
1 2 |
[root@localhost logrotate]# date 10021214 2020年 10月 2日 金曜日 12:14:00 JST |
意図的に1日進めて、10月2日になった状態で待ちます。いきなり10月2日になったので、当然10月2日分のジョブは実行されていません。
ログで確認
cronのログを見ます。
1 2 3 4 5 6 7 8 9 10 |
Oct 2 13:01:01 localhost CROND[48360]: (root) CMD (run-parts /etc/cron.hourly) Oct 2 13:01:01 localhost run-parts[48360]: (/etc/cron.hourly) starting 0anacron Oct 2 13:01:02 localhost anacron[48369]: Anacron started on 2020-10-02 Oct 2 13:01:02 localhost run-parts[48360]: (/etc/cron.hourly) finished 0anacron Oct 2 13:01:02 localhost anacron[48369]: Will run job `cron.daily' in 24 min. Oct 2 13:01:02 localhost anacron[48369]: Jobs will be executed sequentially Oct 2 13:25:02 localhost anacron[48369]: Job `cron.daily' started Oct 2 13:25:02 localhost run-parts[49031]: (/etc/cron.daily) starting logrotate Oct 2 13:25:02 localhost run-parts[49031]: (/etc/cron.daily) finished logrotate Oct 2 13:25:02 localhost run-parts[49031]: (/etc/cron.daily) starting rhsmd |
anacronが毎時1分になったら実行されていますね。
「履歴を見たら本日の分の仕事をしていないみたいだから、今から実行しまーす」という感じで実行されています。また、「Will run job `cron.daily’ in 24 min.」ということで、24分後に実行しますと言っています。このあたりもざっくりとした時間で実行されるようです。
もう一度実行履歴を見る
日付が更新されたか見てみます。
1 2 3 4 5 6 |
[root@localhost ~]# cat /var/spool/anacron/cron.daily 20201002 [root@localhost ~]# cat /var/spool/anacron/cron.weekly 20200930 [root@localhost ~]# cat /var/spool/anacron/cron.monthly 20200930 |
dailyの日付のみが更新されていることが分かります。
おまけ
dailyだけではなく、weeklyやmonthの動作見たくなったので、一気に日付をずらした際の結果を以下に記載しておきます。ご参考にどうぞ。
1 2 |
[root@localhost log]# date 11101259 2020年 11月 10日 火曜日 12:59:00 JST |
ログを確認します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
[root@localhost ~]# cat /var/log/cron Nov 10 13:01:01 localhost CROND[50078]: (root) CMD (run-parts /etc/cron.hourly) Nov 10 13:01:01 localhost run-parts[50078]: (/etc/cron.hourly) starting 0anacron Nov 10 13:01:01 localhost anacron[50087]: Anacron started on 2020-11-10 Nov 10 13:01:01 localhost anacron[50087]: Will run job `cron.daily' in 23 min. Nov 10 13:01:01 localhost anacron[50087]: Will run job `cron.weekly' in 43 min. Nov 10 13:01:01 localhost anacron[50087]: Will run job `cron.monthly' in 63 min. Nov 10 13:01:01 localhost anacron[50087]: Jobs will be executed sequentially Nov 10 13:01:01 localhost run-parts[50078]: (/etc/cron.hourly) finished 0anacron Nov 10 13:24:02 localhost run-parts[50746]: (/etc/cron.daily) finished logrotate Nov 10 13:24:02 localhost run-parts[50746]: (/etc/cron.daily) starting rhsmd Nov 10 13:29:02 localhost run-parts[50746]: (/etc/cron.daily) finished rhsmd Nov 10 13:29:02 localhost anacron[50087]: Job `cron.daily' terminated Nov 10 13:29:02 localhost anacron[50087]: Job `cron.daily' terminated Nov 10 13:44:01 localhost anacron[50087]: Job `cron.weekly' started Nov 10 13:44:01 localhost anacron[50087]: Job `cron.weekly' terminated Nov 10 14:01:01 localhost CROND[51995]: (root) CMD (run-parts /etc/cron.hourly) Nov 10 14:01:01 localhost run-parts[51995]: (/etc/cron.hourly) starting 0anacron Nov 10 14:01:01 localhost run-parts[51995]: (/etc/cron.hourly) finished 0anacron Nov 10 14:04:01 localhost anacron[50087]: Job `cron.monthly' started Nov 10 14:04:01 localhost anacron[50087]: Job `cron.monthly' terminated Nov 10 14:04:01 localhost anacron[50087]: Normal exit (3 jobs run) |
無事に実行されました。日付も更新されたか確認します。
1 2 3 4 5 6 |
[root@localhost src]# cat /var/spool/anacron/cron.daily 20201110 [root@localhost src]# cat /var/spool/anacron/cron.weekly 20201110 [root@localhost src]# cat /var/spool/anacron/cron.monthly 20201110 |
週に1回、月に1回実行する記録も変更され更新されていますね。