daemontools でプロセス監視 (svscan, supervise, multilog)


[daemontools](http://cr.yp.to/daemontools.html)でプロセス監視を運用上よくやりますが、毎度ググってを繰り返すので自分で書いとこうと思います。

daemontools は以下のツールで構成されるプロセス監視のユーティリティです

| svscan    | サービスディレクトリの監視 |
| supervise | プロセスの監視および制御 |
| multilog  | ロギング |

http://ja.wikipedia.org/wiki/Daemontools

## daemontools のインストール

yum も rpm もイマイチこれや!ってのがないので、本家?からソース毎ダウンロードしてインストールします

```sh
$ curl -O http://cr.yp.to/daemontools/daemontools-0.76.tar.gz
$ tar zxvf daemontools-0.76.tar.gz
$ cd admin/daemontools-0.76/
$ curl -O http://djbware.csi.hu/patches/daemontools-0.76.errno.patch
$ patch -p1 < daemontools-0.76.errno.patch
$ sudo ./package/install 
```

インストールが完了すると /usr/local/bin, /command あたりにそれらしい実行ファイルが作成されていると思いますが、<span style="color: #cc0000">すべての実体がソースを展開したところに配置されている</span>のでまじめに運用するときにはそこからちゃんと検討しないといけない。

## svscan

まずはdaemontoolsの本丸である <span style="color: #cc0000">svscan</span> を起動しなければいけない。起動は <span style="color: #cc0000">svscanboot</span> コマンドで行うがインストールでは <span style="color: #cc0000">/etc/inittab</span> にそれが記載されている

```
SV:123456:respawn:/command/svscanboot
```

が、CentOSでは?これが効かないのでこれはコメントアウトして<span style="color: #cc0000">upstart</span>による起動に変更する。以下のような内容の <span style="color: #cc0000">/etc/init/svscan.conf</span> を作成する

```
start on runlevel [12345]
respawn
exec /command/svscanboot
```

これでOS起動時に svscan が立ち上がるし、このプロセスが落ちても自動復旧(再立ち上げ)される。

```sh
$ ps ax | grep svscan
  586 ?        Ss     0:00 /bin/sh /command/svscanboot
  594 ?        S      0:00 svscan /service
```

試しにsvscanのプロセスをkillしてみると、/var/log/messages に

```
Feb 12 22:49:01 localhost init: svscan main process ended, respawning
```

と記録され再びsvscanが立ち上がってます。これでsvscanがプロセスから消えることは無い状態になりました.

## supervise

次にパッケージ(デーモンサービス)を監視する supervise です。パッケージはそれぞれひとつのディレクトリ内で管理されます。

```
daemon_name/run   #デーモンの実行ファイルをrunとして配置する。
```

としてそれを

```
/service/daemon_name
```

として配置することでsvscanの管理下となります。( daemon_name を別のパスで作成してシンボリックリンクを貼ることで配置することも一般的です)
今回は動作確認のため簡単なデーモン?をシェルで作ってみました。

```
$ cat run 
#!/bin/sh

i=1
while [ 1 ];
do
  echo $i
  i=`expr $i + 1`
  sleep 1
done;
```

実際にはrunはデーモンで動作するプログラムを起動するシェルになる場合が一般的です。その場合は run のシェルの中で exec を利用して目的のプログラムを起動します。
今回のディレクトリ構成は

```sh
$ find ~/test_job/
/home/keisyu/test_job/
/home/keisyu/test_job/run
$ chmod +t test_job
```

とします。test_job にスティッキービットを立てる必要があるのでそうします (chmod +t)
これ(test_jobディレクトリ)を/serviceにリンクします。すると run が起動します。 

```sh
$ sudo ln -s /home/keisyu/test_job 
$ ps ax 
 1221 ?        S      0:00 supervise test_job
 1222 ?        S      0:00 /bin/sh ./run
$ sudo svstat /service/test_job/    #サービスの状態を確認するコマンド
/service/test_job/: up (pid 1222) 197 seconds
```

test_job/supervise というフォルダが自動的に作成されますがdaemontoolsの管理用なので触らないです.

```sh
$ sudo svc -u /service/test_job  # サービス(run)を起動します
$ sudo svc -d /service/test_job  # サービス(run)を停止させます
```

-d -u 以外にも run に各種シグナルが送れますので必要であればググってください。

## multilog

デーモンが標準/エラー出力等を行う情報を記録するためのコマンドです。supervise と合わせて使うことで deamontoolsで管理しているプロセスにおけるロギングの管理が用意になります。
先ほどの test_job におけるロギングを行うということで実際にやってみます

```
test_job/
test_job/run
test_job/supervise #これは自動的に作られる
test_job/log
test_job/log/run
test_job/log/supervise #これは自動的に作られる
test_job/log/main #これは自動的に作られる
```

という形で log のフォルダとその直下に run というファイルを配置します。 run はmultilogを起動するシェルであり最低限の内容として以下にします。

```
#!/bin/sh
exec multilog t ./main
```

すると log/main フォルダ以下に current ファイルが生成され run の出力がロギングされます。

```sh
# tail -f current 
...
@4000000052fb885a329f8e7c 89
@4000000052fb885b32d7b57c 90
@4000000052fb885c32f7439c 91
@4000000052fb885d3320861c 92
...
```

### なんかよくわからんくなった時の対応

run コマンドを修正したいとかそうした時にsvscanの管理下にある状態で修正すると混乱します
その場合は以下の手順でやる。

```sh
# cd /service
# mv test_job .test_job
# svc -dx /service/.test_job
# log 以下の supervise, multilogってプロセスが死んでくれないのでkillする。正しい方法がわからん...
# 色々修正
# mv .test_job test_job
# svc -u /service/test_job
```