OXY NOTES

サーバの処理を自動実行するcronの仕組みと応用法

面倒なルーチンワークはcronにお任せ

cronとは定期的にコマンドやスクリプトを自動実行するための機能です。

定期的なバックアップ、データベースの最適化、ウイルススキャンの実行など、人の手で行うのが億劫な処理を一手に引き受けてくれる、ありがたい存在です。


cronの動作確認

crondというプロセスで実行されます。通常はLinuxの起動と同時に実行されています。

crondの実行プロセスを確認

# service crond status

crondの起動

もし起動していない場合は以下のコマンドで起動しておいてください。

# service crond start

cronの自動起動の確認

3番がONになっているか調べます。

# chkconfig --list crond

cronの自動起動の有効にする

もし有効になっていない場合は以下のコマンドで自動起動を有効にします。

# chkconfig crond on

cronの設定と書式

cronの設定ファイルは「/etc/crontab」です。それでは設定ファイルを開いて、書式を確認しましょう。
(下の例はCentOS 5系の場合です。CentOS 6系では定期実行は「/etc/anacrontab」にまとめられています)

# vi /etc/crontab
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
HOME=/

# run-parts
01 * * * * root run-parts /etc/cron.hourly
02 4 * * * root run-parts /etc/cron.daily
22 4 * * 0 root run-parts /etc/cron.weekly
42 4 1 * * root run-parts /etc/cron.monthly

上から順番に見ていきます。

1~2行目、まずSHELLPATHでコマンドへパスを通しています。

3行目MAILTO=rootで実行結果をroot宛にメールするという設定になっています。
メールが届かないようにするには「MAILTO=””」とダブルクォーテーションを2つ付けます。※エラー等が起こった場合の出力も送信されるので、容量が許せば受け取って置くことをお勧めします。
rootだと受け取れる人が限られているので、cron専用のユーザーを作って、管理者全員にエイリアスで送信するというのもお勧めです。

※MAILTO自体を削除してもcrond実行ユーザーへメールを送信します。(デフォルトではroot)

4行目、「HOME=/」crondがスクリプトを実行する際のディレクトリを指定します。

その後に続く「# run-parts」から下が実際に定時に実行されるプログラムの設定になります。

その後にスペース区切りで数字やディレクトリ等が指定されています。
詳しくは後述するとして、数字の後の「root」はrootユーザの権限で実行するという設定。

run-parts <ディレクトリ>」はディレクトリを指定する際に記述します。

run-partsの特殊な制約について

run-partsには以下のルールが存在します。

つまり、/etc/cron.hourly内にサブディレクトリを作成しても実行されないということですね。また、シェルスクリプトなので末尾に「.sh」と付けてしまいがちですが、debianでは動作しないので避けたほうが賢明。 この名前順に実行される特性を利用して、それぞれのディレクトリ内で順番に実行して欲しいファイルに数字を付けると便利です。 ファイル名の例) 10_hoge 20_hogehoge 30_huga うまい棒blog run-partsが認識するファイル名ではまった」より

設定にあるそれぞれのフィールドについて

それぞれのフィールドは左から順番に以下のような意味になっています。

各フィールドと入力する値

フィールド 指定する値
0~59
0~23
1~31
1~12 もしくは jan~dec
曜日 0~7 (0と7は日曜日) もしくは sun~sat
コマンド 有効なコマンド(ディレクトリまたはシュルスクリプトファイル)を記述します。

*(アスタリスク)」はどんな意味かというと、それぞれのフィールドが1増加するごとに実行するという指定になります。

少し分かりにくいので実例で解説します。
設定ファイルの一番上の例では分フィールドに01が指定され、後は*です。
*の意味を省略せずに書くと「毎月・毎曜日・毎日・毎時、分数が1の時に実行」という意味になります。

01 * * * *

例えば月曜日だけ毎時実行したいという場合は週フィールドに1を指定します。

01 * * * 1

cronの便利な指定方法

cronでは複雑な指定もできるように便利な設定方法が用意されています。

複数の時間で実行する

毎時1分と30分の2回実行したい場合、「,(カンマ)」で区切ることで複数の時間を指定できます。

01,30 * * * *

連続した時間の範囲で実行する

毎時1分から10分まで毎分連続して実行したい場合は「-(ハイフン)」で指定します。

01-10 * * * *

一定の間隔で実行する

6分毎に規則的な期間で実行するには「/(スラッシュ)」を使います。

*/6 * * * *

応用として、ハイフンとスラッシュを組み合わせれば1分から20分まで6分ごとに実行ということもできます。

01-20/6 * * * *

crontabによる新しいルールの作成

rootユーザーでcronの設定ファイルを作成する場合は「/etc/crontab」を編集していましたが、crontabというコマンドを使えば、一般ユーザーでも個別にcronの設定ファイルを作成することができます。

書式

crontab [ -u ユーザ名 ] { -l | -r | -e }

新しいルールの作成

hogeユーザー用の新しいルールを作成する。

# crontab -r hoge -e

するとエディタが立ち上がるのでviと同じ要領で編集します。

MAILTO=hoge
0-59 * * * * echo "hoge"

ユーザーの指定に使う「-r hoge」を省略すると、現在実行しているユーザーのルールが追加されます。

無事終了すると以下のように表示されます。

crontab: installing new crontab

上記の設定だと、hogeユーザー宛に、Cron Demonから「hoge」と書かれたメールが毎分届きます。

ユーザー個別の設定ファイルは「/var/spool/cron/」にユーザー名ごとに作成されます。

ルールの確認

# crontab -l

ルールがない場合は以下のように表示される。

no crontab for hoge

ルールの削除

こちらのコマンドは確認もせずに全てのルールを削除するので、使用はお薦めできません。「crontab -e」で開いて、必要のなくなったルールだけ削除すると事故が減ります。

# crontab -r

cronを利用する上でのテクニック

cronを利用する上で知っておくと便利なちょっとしたテクニックを紹介します。

メールを送信するスクリプトを限定する

新規ルールを追加

# crontab -e

以下を追加します。

MAILTO=""
0-59 * * * * echo "hoge"
0-59 * * * * echo "huga" 2>&1 | Mail hoge@example.com

MAILTO=””」となっているのでメールは送信さませんが、「|(パイプ)」でつないで「Mail hoge@example.com」と渡しているので「huga」というスクリプトの実行結果だけ送信されてきます。
tちなみに「2>&1」はお決まりの、標準出力と標準エラーを合わせて出力するという指定です。

この形式の場合、メールの差出人はcronではなく、実行したユーザーとドメイン名「hoge@example.com」で送信されてきます。

出力をログファイルに書き出す

頻繁に実行されるスクリプトがあるとメールの数が多くなります。そうなるとメール送信を停止したくなります。
しかしそれではエラーが出た際に状況を把握できなくなります。そこで一般のソフトと同じようにログファイルを作成して結果を出力するようにするとメールがcronの結果で一杯になることを防げます。

まずはrootユーザーでログファイルを作ります。(通常/var/logはrootユーザーしか変更できないため)

# echo -n > /var/log/www_cronlog

実行権限の設定(一般ユーザーで作成したcronは一般ユーザーの権限で実行されるため。もちろんrootユーザーでルールをさくせする場合は必要ありません。)

# chmod 646 /var/log/www_cronlog
# crontab -e
(以下を追加)
MAILTO=""
0-59 * * * * echo "hoge" 2>&1 >>/var/log/www_cronlog

これでメールを飛ばさない代わりに、ログファイル「/var/log/www_cronlog」に結果が出力されます。
追記を行うためのリダイレクション記号は「>」が2つです。1つだと書き出すごとに上書きされてしまうので過去のログを参照できません。

また、ログファイルが肥大化しないようにrsyslog等でログローテートしてください。ログローテートの方法は「以前の投稿」をご覧ください。

cronの実行時間を0分きっかりにしない

cron力をつけよう!全てのcrontab入門者に贈る9個のテクニック」より
(RHEL6系以降は「/etc/anacrontab」があるためこのような設定は不要)

cronを実行する際に同じ時間で実行されるスクリプトが重なるとサーバが重くなってしまいます。
そこで◯時きっかりというcronで設定しがちな時間から、わざとずらすのが効果的です。

悪い例

0 * * * * echo "hoge"

良い例

5 * * * * echo "hoge"
35 * * * * echo "hoge"

また、cronのデフォルトで設定されている時間もずらすのがお勧めです。
デフォルトの設定は下記の表記から分かるように毎時1分毎日4時2分毎週4時22分毎月1日の4時42分となっています。

cronのデフォルトの設定

01 * * * * root run-parts /etc/cron.hourly
02 4 * * * root run-parts /etc/cron.daily
22 4 * * 0 root run-parts /etc/cron.weekly
42 4 1 * * root run-parts /etc/cron.monthly

特にウイルススキャンやデータベースの最適化など重い処理を行う場合はこの時間からずらしておきましょう。
複数の管理者がいる場合は時間をずらしていることを通知するのを忘れずに。

もちろん一番良いのはSysstat等でサーバのピークタイムを算出して、その時間を避ける事です。