この文書は DJB 氏の daemontools パッケージに興味を持たれる方やこれから導入・運用を行おうとする方に向けて書かれたものです。daemontools パッケージの概要、導入・設定方法、使用例などをまとめています。しかし、各ツールを詳細に説明するものではありません。そのため、この文書を読んだ後に、マニュアル*1 を読んでください。日本語訳*2もあります。 また、新山さんの daemontools FAQ*3もありますのでそちらもご覧下さい。
daemontools はサービスを安全・確実かつ容易に管理するためのツール集です。 主にサービスの制御、ログの収集、環境変数・資源制限を行います。
daemontools パッケージに含まれているプログラムには次のものがあります。
プログラム名 | 説明 |
---|---|
supervise | サービスを開始させ、監視します。何らかのトラブルでサービスが停止したら、自動的に再起動させます。 |
svc | supervise により監視されているサービスを制御します。 |
svok | supervise が起動しているかを調べます。 |
svstat | supervise により監視されているサービスの状態を出力します。 |
svscan | サービスの集まりを開始させ、監視します。 |
fghack | 自信をバックグランドに移すサービスがバックグランドに移るのを防ぐツールです。 |
multilog | 標準入力から一続きの行を読み、任意の数のログに選択された行を追加します。 |
tai64n | 各行に TAI64N 形式の正確なタイムスタンプをを付けます。 |
tai64nlocal | TAI64N 形式のタイムスタンプを人が読める形式に変換します。 |
setuidgid | 指定されたアカウントの uid と gid で別のプログラムを起動します。 |
envuidgid | 指定されたアカウントの uid と gid を示す環境変数を設定して別のプログラムを起動させます。 |
envdir | 指定したディレクトリにあるファイルによって修正された環境を設定して別のプログラムを起動させます。 |
softlimit | 新しい資源制限を伴って別のプログラムを起動させます。 |
setlock | ファイルをロックして別のプログラムを起動させます。 |
既存の他のプログラムとに違いは次の通りです。
daemontools のパッケージ daemontools-0.70.tar.gz を入手します。
ファイルを展開し、そのディレクトリに移動します。
コンパイルして、インストールします。
試験を行います。何も出力しなかったら正常です。
タイムスタンプを確認します。各行の前の日時と後ろの日時は同じになります。ただし、端数の関係で1秒違うかもしれません。
以上、何も問題が生じなければ、インストールは終了です。
svscan が監視するディレクトリを作成します。svscan に関する説明は次章で行います。
ブートスクリプトに svscan を起動するコマンドを登録します。BSD 形式の起動スクリプトであれば、rc.local などに、次のコマンドを追加して下さい。PATH は必要だと思うものを設定してください。
SVR4 形式の起動スクリプトであれば、次のようなスクリプト svscan を作成し、登録してください。OS により少々修正する必要があると思います。
#!/bin/sh
PATH=/usr/local/bin:/usr/bin:/bin
case "$1" in
start)
echo -n "Starting svscan: "
exec env - PATH="$PATH" \
csh -cf 'svscan /service &; echo $! > /var/run/svscan.pid'
touch /var/lock/subsys/svscan
;;
stop)
if [ -f /var/run/svscan.pid ]; then
echo -n "Stopping svscan: "
kill `cat /var/run/svscan.pid`
svc -dx /service/*
svc -dx /service/*/log
rm -f /var/run/svscan.pid
rm -f /var/lock/subsys/svscan
fi
;;
*)
echo "Usage: $0 {start|stop}"
exit 1
esac
exit 0
なお、RedHat Linux 7.x用の起動スクリプトは http://www.emaillab.org/djb/daemontools/svscan にあります。次のようにして登録してください。
起動スクリプトの登録ができたら、起動スクリプトを個別に実行したり、再起動したりして、svscan を起動してください。
svscan は監視対象のディレクトリ /service にサブディレクトリ sub があるとき、そのディレクトリ名を引数にして supervise を起動させます。supervise は引数で渡されたディレクトリ sub に移動し、./run スクリプトを起動させ、監視します。この ./run にはサービスを実行するスクリプトを記述します。さらに、sub に sticky bit が立っていれば、svscan は sub に移動し、log を引数にして supervise を起動させ、sub/run の出力と sub/log/run の入力をパイプでつなぎます。このときの supervise は引数で渡されたディレクトリ log に移動し、./run スクリプトを起動させ、監視します。この ./run にはログを記録するプログラム(multilog)を実行するスクリプトを記述します。このように supervise は svscan により起動させられるので、スクリプト中に supervise を明示して記述する必要はありません。 それぞれのプログラムとその引数および作業するディレクトリを整理すると次の表のようになります。
プログラム | 作業ディレクトリ |
---|---|
svscan /service | /service |
supervise sub | /service/sub |
supervise log | /service/sub/log |
上記で述べたことに加えて、svscan には次のような特徴があります。
上記で述べたことに加えて、supervise には次のような特徴があります。
起動させたいサービスのためのディレクトリ/path/to/fooを適当な場所に作成します。
次に、./run を作成し、サービスを実行するスクリプトを記述します。
/service/sub から /path/to/foo へのシンボリックリンクを作ります。
5秒以内に supervise が起動するでしょう。svok を使って起動が成功しているか確認できます。また、svstat でもその起動の状態を確認できます。
起動させたいサービスのためのディレクトリ/path/to/fooを適当な場所に作成します。ログ用のディレクトリ /path/to/foo/log も作成します。さらに foo に対して sticky bit を立てます。ログの出力を行う UID, GID を変える場合は、log の所有者も変えます。
次に、./run を作成し、サービスを実行するスクリプトを記述します。また、log/run を作成し、ログを保存するスクリプトを記述します。
/service/sub から /path/to/foo へのシンボリックリンクを作ります。
5秒以内に supervise が起動するでしょう。svok を使って起動が成功しているか確認できます。また、svstat でもその起動の状態を確認できます。
まず、qmail の起動プログラム qmail-start 用のディレクトリを作成します。場所はどこでもかまいませんが、ここでは /var/qmail/supurvise/qmail-send とします。ログを保存するために、このディレクトリに sticky bit を立て、そのディレクトリの下にに qmail-send のログ保存用ユーザ qmaill 所有のディレクトリ log を作成します。
起動スクリプト ./run と log/run を作成します。このスクリプトの例は次節に述べます。
/service/qmail からのシンボリックリンクを作ります。
5秒以内に supervise が起動するはずなので、svok あるいは svstat で起動を確認してください。また、qmail のマニュアルに記述してある配送試験を行ってください。
次に、qmail の SMTP デーモン qmail-smtpd 用のディレクトリを作成します。ここでは /var/qmail/supervise/qmail-smtpd とします。ログを保存するために、このディレクトリに sticky bit を立て、そのディレクトリの下にに qmail-send のログ保存用ユーザ smtplog 所有のディレクトリ log を作成します。
起動スクリプト ./run と log/run を作成します。このスクリプトの例は次節に述べます。
/service/smtpd からのシンボリックリンクを作ります。
5秒以内に supervise が起動するはずなので、svok あるいは svstat で起動を確認してください。
ここでは、サービスの起動スクリプト ./run の作成例を示します。ログの収集スクリプト log/run に関してはここでは典型的な例しか示しません。応用例は次章に記述します。
qmail のメイル配送のプログラムを起動させ、配送のログを取る場合の例を示します。ログは qmail-send のログ保存専用のユーザ qmaill により保存されます。すべてのログはタイムスタンプを付けて ./log/main/ に保存されます。さらに現在の接続数は ./log/status に保存されます。
#!/bin/sh exec env - PATH="/var/qmail/bin:$PATH" \ qmail-start ./Maildir/
#!/bin/sh exec \ setuidgid qmaill \ multilog t ./main '-*' '+* status: *' =status
qmail の SMTP デーモン qmail-smtpd を tcpserver で起動させて接続制御を行い、接続状況のログを取る場合の例を示します。この場合はログ保存専用のユーザ smtplog によりログを保存します。また、接続制御ファイル tcp.cdb は同じディレクトリにあるものとします。
#!/bin/sh exec env - PATH="/var/qmail/bin:$PATH" \ tcpserver -vR -c40 -x./tcp.cdb -u7791 -g2108 0 smtp qmail-smtpd 2>&1
#!/bin/sh exec \ setuidgid smtplog \ multilog t ./main '-*' '+* * status: *' =status
svc を使って次のことができます。
svc の使い方は次の通りです。
svc opts services
opts は getopt 形式のオプションです。複数のオプションを指定でき、前から順番に実行されます。services は制御対象のディレクトリ名です。複数のディレクトリを同時に指定できます。ここで、svc のオプションの一覧を示します。
オプション | 意味 | 動作 |
---|---|---|
-u | Up | サービスが起動していなければ、開始します。サービスが停止していれば、再開します。 |
-d | Down | サービスが起動していれば、TERM シグナルを送り、それから CONT シグナルを送ります。停止した後は再開しません。 |
-o | Once | サービスが起動していなければ、開始します。サービスが停止していれば、再開しません。 |
-p | Pause | サービスに STOP シグナルを送ります。 |
-c | Continue | サービスに CONT シグナルを送ります。 |
-h | Hangup | サービスに HUP シグナルを送ります。 |
-a | Alarm | サービスに ALRM シグナルを送ります。 |
-i | Interrupt | サービスに INT シグナルを送ります。 |
-t | Terminate | サービスに TERM シグナルを送ります。 |
-k | Kill | サービスに KILL シグナルを送ります。 |
-x | Exit | サービスがダウンしたらすぐに supervise は終了します。 |
シグナルの意味は次の通りです。(値は環境により異なることがあります。)詳細は signal(7) を読んでください。
シグナル | 値 | 意味 |
---|---|---|
SIGSTOP | 17 | プロセスの停止 |
SIGCONT | 19 | 停止状態からの再開 |
SIGHUP | 1 | 制御している端末のハングアップの検出。制御しているプロセスの死。 |
SIGALRM | 14 | alarm(2)からのタイマーシグナル |
SIGINT | 2 | キーボードからの割り込み |
SIGTERM | 15 | 終了シグナル |
SIGKILL | 9 | Killシグナル |
ここで、いくつかの使用例を示します。
qmail-send の設定の変更を有効にするためのサービスの再起動
./run の書き換え時の処理
サービスの一時的な停止および再開
サービスの停止後、supervise の終了(ただし、5秒以内に supervise は再起動する)
サービスの停止後、supervise の終了(supervise を再開させない)
svscanを終了させるとき(全てのサービスの停止後、supervise を終了し、svscan のプロセスを終了する)
前章で述べたログの収集スクリプト log/run には収集プログラムとして multilog を使います。ここでは、その multilog の使い方について説明します。
multilog の使い方は次の通りです。
multilog script
script は動作(action)の集まりで、次の表に記述した動作の行の選択から出力までの組合わせを繰り返して指定することができます。(恐らくシェルの限界まで)
動作の概要 | 動作 | 備考 |
---|---|---|
タイムスタンプ | t | 各行の先頭にTAI64N形式のタイムスタンプを付ける。(最初の動作として記述した場合のみ有効) |
行の選択 | -pattern | pattern が行に合えばその行の選択が解除される。 |
+pattern | pattern が行に合えばその行は選択される。 | |
自動切り替えの動作 | ssize | 最大ファイルサイズの設定。デフォルト99999。 |
nnum | ログファイルの最大数。デフォルト10。 | |
!processor | プロセッサの設定 | |
ログ | dir | ログ dir へ選択された行を追加する。ドットやスラッシュで始まる必要がある。 |
警告 | e | 標準エラーに選択された各行(の最初の200バイト)を出力する。 |
Statusファイル | =file | file の中身を選択された各行(の最初の1000バイト)で置き換える。 |
各行は最初は選択されています。行の選択指定はいくつでも記述でき、前から順番にそのパターンの選択・解除が追加されていきます。
patternの仕様は次の通りです。
想定外の動作を防ぐために、pattern全体を引用符で囲んだ方が無難でしょう。
ここで、いくつか行の選択指定の例を示します。multilog の詳しい使用例に関しては次節をご覧ください。
動作
+hello
は hello を選択します。hello world は選択しません。
動作
-'* * > *'
は
@400000003879ded713291cfc 4357 > -ERR authorization failed
の選択を解除します。一つ目と二つ目の * はその直後のスペースを含まない任意の文字列に一致します。
動作
'-*'
は全ての行の選択を解除します。特定のパターンのみを選択する場合は通常、最初にこの動作を記述して全ての選択を解除してから、選択するパターンを追加していきます。
一続きの動作
-'*' +'* status: *' =status
は
@400000003914053c22ab2904 status: local 0/10 remote 0/20
を選択し、status というファイルの内容を置き換えます。つまり、status というファイルには常に最新の status: 行が格納されることになります。
qmail のメイル配送プログラム qmail-send のログを取る場合の例を示します。ログは qmail-send のログ保存専用のユーザ qmaill により保存されます。このスクリプトは次の3つの部分に分けることができます。
ちなみに、この例は DJB 氏がメイリングリストに投稿した例を修正したものです。
#!/bin/sh exec \ setuidgid qmaill \ multilog t ./main \ -'* status: *' \ -'* starting delivery *' \ -'* delivery * success*' \ -'* delivery * failure*' \ -'* new msg *' \ -'* info msg *' \ -'* end msg *' \ -'* bounce msg *' \ -"* delivery * deferral: Sorry,_I_couldn't_find_any_host_by_that_name*" \ -"* delivery * deferral: Sorry,_I_wasn't_able_to_establish_an_SMTP_*" \ ./alert \ -'*' \ +'* status: *' \ =status
qmail の SMTP デーモン qmail-smtpd を途中を recordio を挟んで tcpserver で起動させて接続制御を行い、接続状況のログとコマンドの応答を取る場合の例を示します。この場合はログ保存専用のユーザ smtplog によりログを保存します。このスクリプトは次の3つの動作に分けることができます。
ちなみに recordio とは、プログラムの入出力を記録するプログラムで、ucspi-tcp パッケージに含まれています。これを用いれば、ログの出力を持たないサービスであっても、セッションのコマンドの応答から、不正中継の試みなどの様々な情報を記録することができます。ただし、選択する行によってはプライバシの問題にもなるので扱いには注意が必要です。
#!/bin/sh exec \ setuidgid smtplog \ multilog t \ -'* * > *' \ -'* * < *' \ s200000 \ ./main \ -'*' \ +'* * < HELO *' \ +'* * < EHLO *' \ +'* * < MAIL *' \ +'* * < RCPT *' \ +'* * < DATA*' \ +'* * < QUIT*' \ +'* * < RSET*' \ +'* * < NOOP*' \ +'* * > 1*' \ +'* * > 2*' \ +'* * > 3*' \ +'* * > 4*' \ +'* * > 5*' \ s200000 \ ./tcp \ -'*' \ +'* * status: *' \ =status
ここまで手が回りません。後日、時間ができたら続きを書きます。