CentOS6 の cron.daily 実行時刻は、CentOS5 以前とは異なります。
※この記事に書いた手順は、RHEL8 / RHEL7 / RHEL6でも通用します。末尾参照
CentOS5 以前であれば、デフォルトでは午前4:02にスケジュールされていましたが、CentOS6 のデフォルトでは、ある幅の範囲内でランダム化されています。
まずは、このランダム化の内容を確認してみます。
最初に /etc/crontab を見てみますと、次のように空っぽです。
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
HOME=/
# For details see man 4 crontabs
# 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
CentOS5 以前であれば、次のようにエントリーされていました。
02 4 * * * root run-parts /etc/cron.daily
ランダム化は、anacron (cronie-anacron) により行われており、設定内容は /etc/anacrontab に記述されています。デフォルトの /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
いくつかのパラメータがあり、man anacrontab(5) に解説がありますが、概説しますと、赤字の
1 (左端) が実行周期 (日次実行=1) で、次の数字
5 は、実行開始タイミングになってから、5 分間の遅延を入れる指定です。実行開始する時間帯は START_HOURS_RANGE で制御され、3-22 とは、3時から22時までの範囲 (3:00 ≦ t < 22:00) を指定しています。ランダム化の幅は RANDOM_DELAY で制御され、45 とは 0~45 分の範囲 (乱数計算の実装上、正確には 44 分まで) でランダムに遅延を行うことを指定しています。
やや複雑ですが、このデフォルト設定で 24H 運用した場合、cron.daily は午前3:06から3:50の間でランダム実行されることになります。ここで 3:06 なのは、そもそも anacron が動作する周期が毎時01分であるためです。/etc/cron.d/0hourly および /etc/cron.hourly/0anacron 参照。
また、もし毎日シャットダウン電源OFF運用を行う場合、例えば、午前6:00にブートすると、その直後の午前6:06から6:50の間でランダムに cron.daily が実行されることになります。
もしも、1日以上シャットダウンしていて、午後23:00にブートした場合には、START_HOURS_RANGE の範囲外であるため、cron.daily の実行は、翌日の午前3:06から3:50の間ということになります。
このランダム化は、仮想化環境を考慮してのこと (ゲストOSの cron.daily が重ならないようにする意図) とは思いますが、ランダムに動作されるのは運用上よろしくない (混乱要因となる) と考える方も居るかと思います。CentOS6 では、CentOS5 以前のように固定の時刻に cron.daily を行わせるようにする方法も用意されており、デフォルトでインストールされる cronie-anacron パッケージの代わりに、cronie-noanacron をインストールすればよいです。
パッケージの依存関係のため、事前に cronie-noanacron をインストールし、その後に cronie-anacron を削除するという手順を踏みます。
# yum install cronie-noanacron
...途中省略...
Installed:
cronie-noanacron.x86_64 0:1.4.4-7.el6
Complete!
# rpm -e cronie-anacron
この cronie-noanacron は、ちっぽけなパッケージで、/etc/cron.d/dailyjobs ファイルだけを含んでいます。
# rpm -qi cronie-noanacron
Name : cronie-noanacron Relocations: (not relocatable)
Version : 1.4.4 Vendor: CentOS
Release : 7.el6 Build Date: Tue 19 Jul 2011 01:55:56 PM JST
Install Date: Thu 17 Jan 2013 12:02:39 AM JST Build Host: c6b5.bsys.dev.centos.org
Group : System Environment/Base Source RPM: cronie-1.4.4-7.el6.src.rpm
Size : 326 License: MIT and BSD and ISC and GPLv2
Signature : RSA/SHA1, Mon 26 Sep 2011 01:17:22 PM JST, Key ID 0946fca2c105b9de
Packager : CentOS BuildSystem
URL : https://fedorahosted.org/cronie
Summary : Utility for running simple regular jobs in old cron style
Description :
Old style of {hourly,daily,weekly,monthly}.jobs without anacron. No features.
# rpm -ql cronie-noanacron
/etc/cron.d/dailyjobs ※パッケージの中身はこれ1個
/etc/cron.d/dailyjobs の中身は次のようになっています。
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
HOME=/
# run-parts
02 4 * * * root [ ! -f /etc/cron.hourly/0anacron ] && run-parts /etc/cron.daily
22 4 * * 0 root [ ! -f /etc/cron.hourly/0anacron ] && run-parts /etc/cron.weekly
42 4 1 * * root [ ! -f /etc/cron.hourly/0anacron ] && run-parts /etc/cron.monthly
CentOS5 以前での運用経験があれば、見慣れた実行時刻かと思います。ただし、0anacron の存在チェックが行われており、cronie-anacron パッケージを削除しないと有効化されないようにガードされています。ご注意を。
すでにお分かりかとは思いますが、cron.weekly および cron.monthly も同様です。ただ、cron.hourly はランダム化されておらず、次のように /etc/cron.d/0hourly に設定が書かれています。
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
HOME=/
01 * * * * root run-parts /etc/cron.hourly
最後に、いわずもがなですが、RHEL6 でも同様です :-p
2013-01-18追記
境界値がはっきりしないので、いちおう cronie-1.4.4-7.el6 のソースを見てみました。
START_HOURS_RANGE に対応する処理は、次の通りです。こちらは簡単ですね。
422 t = localtime(&jobtime);
423 if (range_start != -1 && range_stop != -1 &&
424 (t->tm_hour < range_start || t->tm_hour >= range_stop))
425 {
426 Debug(("The job `%s' falls out of the %02d:00-%02d:00 hours range, skipping.",
427 job_array[j]->ident, range_start, range_stop));
428 job_array[j]->drop_job = 1;
429 }
430 else
"anacron/main.c"
RANDOM_DELAY に対応する処理は、次の通りです。
279 if (strncmp(env_var, "RANDOM_DELAY", 12) == 0) {
280 r = match_rx("^([[:digit:]]+)$", value, 0);
281 if (r != -1) {
282 int i = random();
283 double x = 0;
284 x = (double) i / (double) RAND_MAX * (double) (atoi(value));
285 random_number = (int)x; ※ここで小数点以下切捨てだからvalueは含まない?
286 Debug(("Randomized delay set: %d", random_number));
287 }
288 else goto reg_invalid;
289 }
"anacron/readtab.c"
これを見ても、生成される random_number の範囲に value が含まれるのか否か、頭の中だけでは判然とせず。手間ですが、実験プログラムを一筆書いてみました。
/*
test_random.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/time.h>
get_random_number(char *value)
{
int random_number;
// next 4 lines are copied from anacron/readtab.c:parse_tab_line()
int i = random();
double x = 0;
x = (double) i / (double) RAND_MAX * (double) (atoi(value));
random_number = (int)x;
return random_number;
}
main(int argc, char* argv[])
{
int i ;
int random_number ;
struct timeval tv ;
struct timezone tz ;
if (argc <= 1) exit(1) ;
gettimeofday(&tv, &tz) ;
// cronie uses this method
srandom(getpid()+tv.tv_usec) ;
for (i = 0; i < 10000; i++) {
random_number = get_random_number(argv[1]) ;
printf("%d\n", random_number) ;
}
}
# gcc -o test_random test_random.c
# ./test_random 10 | sort -n | uniq -c
993 0
1028 1
1006 2
1011 3
998 4
1030 5
999 6
966 7
985 8
984 9
# ./test_random 45 | sort -n | uniq -c | tail
210 35
207 36
218 37
250 38
197 39
221 40
217 41
217 42
209 43
233 44
というわけで、0 ≦ random_number < value ですね。
2014-05-05追記
RHEL7.0 RC を試しましたが、RHEL6/CentOS6 と同様で、もし cron.daily 実行時刻を固定化したい場合は、cronie-noanacron と入れ替えれば良いようです。デフォルトの /etc/anacrontab の設定にも変更は無いようです。
2014-07-21追記
いちいち書くまでもないと思いつつ、RHEL7/CentOS7 でも同様です。
2019-05-26追記
CentOS8 は、現在のところ準備中のようです。
https://wiki.centos.org/About/Building_8
確認したところ RHEL8 でも、cronie-noanacron は存在しており、ここに書いた手順が通用するようです。