daemontools HOW-TO (α版)

Copyright 2000 滝澤 隆史 <taki@cyber.email.ne.jp>
Last modified: Sun Nov 19 19:29:10 2000

前書き

この文書は DJB 氏の daemontools パッケージに興味を持たれる方やこれから導入・運用を行おうとする方に向けて書かれたものです。daemontools パッケージの概要、導入・設定方法、使用例などをまとめています。しかし、各ツールを詳細に説明するものではありません。そのため、この文書を読んだ後に、マニュアル*1 を読んでください。日本語訳*2もあります。 また、新山さんの daemontools FAQ*3もありますのでそちらもご覧下さい。

註記


目次


1. 概要

1.1. daemontools とは

daemontools はサービスを安全・確実かつ容易に管理するためのツール集です。 主にサービスの制御、ログの収集、環境変数・資源制限を行います。


1.2. パッケージの内容

daemontools パッケージに含まれているプログラムには次のものがあります。

プログラム名 説明
supervise サービスを開始させ、監視します。何らかのトラブルでサービスが停止したら、自動的に再起動させます。
svc supervise により監視されているサービスを制御します。
svok supervise が起動しているかを調べます。
svstat supervise により監視されているサービスの状態を出力します。
svscan サービスの集まりを開始させ、監視します。
fghack 自信をバックグランドに移すサービスがバックグランドに移るのを防ぐツールです。
multilog 標準入力から一続きの行を読み、任意の数のログに選択された行を追加します。
tai64n 各行に TAI64N 形式の正確なタイムスタンプをを付けます。
tai64nlocal TAI64N 形式のタイムスタンプを人が読める形式に変換します。
setuidgid 指定されたアカウントの uid と gid で別のプログラムを起動します。
envuidgid 指定されたアカウントの uid と gid を示す環境変数を設定して別のプログラムを起動させます。
envdir 指定したディレクトリにあるファイルによって修正された環境を設定して別のプログラムを起動させます。
softlimit 新しい資源制限を伴って別のプログラムを起動させます。
setlock ファイルをロックして別のプログラムを起動させます。

1.3. 既存の他のプログラムとの違い

既存の他のプログラムとに違いは次の通りです。


2. インストール

2.1. daemontools のインストール

daemontools のパッケージ daemontools-0.70.tar.gz を入手します。

ファイルを展開し、そのディレクトリに移動します。

$ gzip -dc daemontools-0.70.tar.gz | tar xvf -
$ cd daemontools-0.70

コンパイルして、インストールします。

$ make
# make setup check

試験を行います。何も出力しなかったら正常です。

$ ./rts > rts.out
$ cmp rts.out rts.exp

タイムスタンプを確認します。各行の前の日時と後ろの日時は同じになります。ただし、端数の関係で1秒違うかもしれません。

$ date | ./tai64n | ./tai64nlocal
2000-05-05 11:16:53.959932500 Fri May 5 11:16:53 JST 2000
$ date | sh -c './multilog t e 2>&1' | ./tai64nlocal
2000-05-05 11:17:11.739003500 Fri May 5 11:17:11 JST 2000

以上、何も問題が生じなければ、インストールは終了です。

関連リンク


2.2. svscan の起動

svscan が監視するディレクトリを作成します。svscan に関する説明は次章で行います。

# mkdir /service
# chmod 755 /service

ブートスクリプトに svscan を起動するコマンドを登録します。BSD 形式の起動スクリプトであれば、rc.local などに、次のコマンドを追加して下さい。PATH は必要だと思うものを設定してください。

env - PATH=/usr/local/bin:/usr/bin:/bin csh -cf 'svscan /service &'

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 にあります。次のようにして登録してください。

# cd /etc/rc.d/init.d
# cp /tmp/svscan .
# chmod +x svscan
# chkconfig --add svscan

起動スクリプトの登録ができたら、起動スクリプトを個別に実行したり、再起動したりして、svscan を起動してください。

関連リンク


3. サービスの制御

3.1. svscansupervise の動作

svscan は監視対象のディレクトリ /service にサブディレクトリ sub があるとき、そのディレクトリ名を引数にして supervise を起動させます。supervise は引数で渡されたディレクトリ sub に移動し、./run スクリプトを起動させ、監視します。この ./run にはサービスを実行するスクリプトを記述します。さらに、sub に sticky bit が立っていれば、svscansub に移動し、log を引数にして supervise を起動させ、sub/run の出力と sub/log/run の入力をパイプでつなぎます。このときの supervise は引数で渡されたディレクトリ log に移動し、./run スクリプトを起動させ、監視します。この ./run にはログを記録するプログラム(multilog)を実行するスクリプトを記述します。このように supervisesvscan により起動させられるので、スクリプト中に supervise を明示して記述する必要はありません。 それぞれのプログラムとその引数および作業するディレクトリを整理すると次の表のようになります。

プログラム 作業ディレクトリ
svscan /service /service
supervise sub /service/sub
supervise log /service/sub/log

上記で述べたことに加えて、svscan には次のような特徴があります。

上記で述べたことに加えて、supervise には次のような特徴があります。

関連リンク


3.2. 各サービスの起動

a) ログを取らない場合

起動させたいサービスのためのディレクトリ/path/to/fooを適当な場所に作成します。

# mkdir /path/to/foo

次に、./run を作成し、サービスを実行するスクリプトを記述します。

/service/sub から /path/to/foo へのシンボリックリンクを作ります。

# ln -s /path/to/foo /service/sub

5秒以内に supervise が起動するでしょう。svok を使って起動が成功しているか確認できます。また、svstat でもその起動の状態を確認できます。

# svok /service/sub; echo "$?"
0
# svstat /service/sub
/service/sub: up (pid 1234) 20 seconds

b) ログを取る場合

起動させたいサービスのためのディレクトリ/path/to/fooを適当な場所に作成します。ログ用のディレクトリ /path/to/foo/log も作成します。さらに foo に対して sticky bit を立てます。ログの出力を行う UID, GID を変える場合は、log の所有者も変えます。

# mkdir /path/to/foo
# mkdir /path/to/foo/log
# chmod +t /path/to/foo
# chown uid.gid /path/to/foo/log

次に、./run を作成し、サービスを実行するスクリプトを記述します。また、log/run を作成し、ログを保存するスクリプトを記述します。

/service/sub から /path/to/foo へのシンボリックリンクを作ります。

# ln -s /path/to/foo /service/sub

5秒以内に supervise が起動するでしょう。svok を使って起動が成功しているか確認できます。また、svstat でもその起動の状態を確認できます。

# svok /service/sub; echo "$?"
0
# svok /service/sub/log; echo "$?"
0
# svstat /service/sub /service/sub/log
/service/sub: up (pid 1234) 20 seconds
/service/sub/log: up (pid 1235) 20 seconds

具体例(qmailの場合)

まず、qmail の起動プログラム qmail-start 用のディレクトリを作成します。場所はどこでもかまいませんが、ここでは /var/qmail/supurvise/qmail-send とします。ログを保存するために、このディレクトリに sticky bit を立て、そのディレクトリの下にに qmail-send のログ保存用ユーザ qmaill 所有のディレクトリ log を作成します。

# mkdir /var/qmail/supervise/qmail-send
# chmod +t /var/qmail/supervise/qmail-send
# mkdir /var/qmail/supervise/qmail-send/log
# chown qmaill.nofiles /var/qmail/supervise/qmail-send/log

起動スクリプト ./runlog/run を作成します。このスクリプトの例は次節に述べます。

/service/qmail からのシンボリックリンクを作ります。

# ln -s /var/qmail/supervise/qmail-send /service/qmail

5秒以内に supervise が起動するはずなので、svok あるいは svstat で起動を確認してください。また、qmail のマニュアルに記述してある配送試験を行ってください。

次に、qmail の SMTP デーモン qmail-smtpd 用のディレクトリを作成します。ここでは /var/qmail/supervise/qmail-smtpd とします。ログを保存するために、このディレクトリに sticky bit を立て、そのディレクトリの下にに qmail-send のログ保存用ユーザ smtplog 所有のディレクトリ log を作成します。

# mkdir /var/qmail/supervise/qmail-smtpd
# chmod +t /var/qmail/supervise/qmail-smtpd
# mkdir /var/qmail/supervise/qmail-smtpd/log
# chown smtplog.nofiles /var/qmail/supervise/qmail-smtpd/log

起動スクリプト ./runlog/run を作成します。このスクリプトの例は次節に述べます。

/service/smtpd からのシンボリックリンクを作ります。

# ln -s /var/qmail/supervise/qmail-smtpd /service/smtpd

5秒以内に supervise が起動するはずなので、svok あるいは svstat で起動を確認してください。

関連リンク


3.3. 起動スクリプト ./run の例

ここでは、サービスの起動スクリプト ./run の作成例を示します。ログの収集スクリプト log/run に関してはここでは典型的な例しか示しません。応用例は次章に記述します。

./run を作成するに当たっての注意事項

qmail-send

qmail のメイル配送のプログラムを起動させ、配送のログを取る場合の例を示します。ログは qmail-send のログ保存専用のユーザ qmaill により保存されます。すべてのログはタイムスタンプを付けて ./log/main/ に保存されます。さらに現在の接続数は ./log/status に保存されます。

./run

#!/bin/sh
exec env - PATH="/var/qmail/bin:$PATH" \
qmail-start ./Maildir/

./log/run

#!/bin/sh
exec \
setuidgid qmaill \
multilog t ./main '-*' '+* status: *' =status

qmail-smtpd

qmail の SMTP デーモン qmail-smtpdtcpserver で起動させて接続制御を行い、接続状況のログを取る場合の例を示します。この場合はログ保存専用のユーザ smtplog によりログを保存します。また、接続制御ファイル tcp.cdb は同じディレクトリにあるものとします。

./run

#!/bin/sh
exec env - PATH="/var/qmail/bin:$PATH" \
tcpserver -vR -c40 -x./tcp.cdb -u7791 -g2108 0 smtp qmail-smtpd 2>&1

./log/run

#!/bin/sh
exec \
setuidgid smtplog \
multilog t ./main '-*' '+* * status: *' =status

関連リンク


3.4. サービスの制御

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 の設定の変更を有効にするためのサービスの再起動

# svc -t /service/qmail

./run の書き換え時の処理

# mv ./run.new ./run; svc -t /service/smtpd

サービスの一時的な停止および再開

# svc -d /service/ftpd
# svc -u /service/ftpd

サービスの停止後、supervise の終了(ただし、5秒以内に supervise は再起動する)

# svc -dx /service/ftpd /service/ftpd/log

サービスの停止後、supervise の終了(supervise を再開させない)

# mv /service/ftpd /service/.ftpd; svc -dx /service/.ftpd /service/.ftpd/log

svscanを終了させるとき(全てのサービスの停止後、supervise を終了し、svscan のプロセスを終了する)

# svc -dx /service/*
# svc -dx /service/*/log
# kill pid_of_svscan

関連リンク


4. ログの収集

4.1. multilog

前章で述べたログの収集スクリプト 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: 行が格納されることになります。

関連リンク


4.2. .log/run の作成例

qmail-send

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-smtpd

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

関連リンク


5. 環境変数・資源制限 (作成予定)

ここまで手が回りません。後日、時間ができたら続きを書きます。


Thanks to M.Sugimoto.