runit によるユーザ権限でのデーモン化

はじめに

ネタがなかったのでずっと更新してなかったのですが、久しぶりにブログ更新します。
今回はユーザ権限によるプログラムのデーモン化をrunitを使って試したのでそれをまとめようと思います。
今まで仕事でdaemontoolsを使うことが多かったのですがroot権限でservice登録する必要があり(私が回避方法を知らないだけかもしれませんが。。。)、runスクリプトを変更した際に毎回rootになる必要があって不便だと思っていました。
そこで最近runitというものがあることを知り調べて実際に使ってみたのでそれをまとめます。

適当なサンプルプログラムを作るのも味気ないので IRC proxy で有名な tiarra をrunit管理下においてデーモン化してみたいと思います。

tiarraのインストール・設定

まずさっそくですが tiarra 本体をインストールします。
私の環境が Debian lenny なので今回は Debian lenny 環境において話を進めます。

nhayashi@deb1:~$ mkdir deb && cd deb
nhayashi@deb1:~/deb$ wget http://hanzubon.jp/Linux/Debian/sid/tiarra/tiarra_0.20100922.orig.tar.gz
nhayashi@deb1:~/deb$ wget http://hanzubon.jp/Linux/Debian/sid/tiarra/tiarra_0.20100922-1.diff.gz
nhayashi@deb1:~/deb$ tar zxvf tiarra_0.20100922.orig.tar.gz
nhayashi@deb1:~/deb$ cd tiarra-0.20100922/
nhayashi@deb1:~/deb/tiarra-0.20100922$ zcat ../tiarra_0.20100922-1.diff.gz | patch -p1
nhayashi@deb1:~/deb/tiarra-0.20100922$ debuild -rfakeroot -uc -us
nhayashi@deb1:~/deb/tiarra-0.20100922$ cd ../
nhayashi@deb1:~/deb$ sudo dpkg -i tiarra_0.20100922-1_all.deb

次に tiarra の設定をしておきます。tiarra の設定は各自お好みの設定でお願いします。

nhayashi@deb1:~$ cd
nhayashi@deb1:~$ mkdir .tiarra
nhayashi@deb1:~$ zcat /usr/share/doc/tiarra/examples/sample.conf.gz > .tiarra/tiarra.conf
nhayashi@deb1:~$ tiarra --make-password
(ここでパスワードを生成します。)
nhayashi@deb1:~$ vi .tiarra/tiarra.conf

私の tiarra.conf の最低限の設定は下記になります。

-  nick: tiarra
-  user: tiarra
-  name: Tiarra the "Aeon"
+  nick: nhayashi
+  user: nhayashi
+  name: nhayashi

-  tiarra-password: xl7cflIcH9AwE
+  tiarra-password: ij3N65pr8dPkI

+  name: freenode

+    channel: *@freenode

+freenode {
+  server: irc.freenode.net 6667
 
+  in-encoding: utf8
+  out-encoding: utf8
 }

ここまでで最低限の tiarra の設定はできました。

rootでのrunitの設定(一般ユーザ用runsvdirサービス登録)

次に今回の本題の runit の設定についてまとめます。
まずは runit をインストールします。

nhayashi@deb1:~$ sudo apt-get install -V runit

次にユーザ権限でrunit管理下のデーモンを扱うための設定をします。

nhayashi@deb1:~$ sudo mkdir /etc/sv/runsvdir-nhayashi

ユーザ権限でデーモンを扱うためのrunスクリプトは下記のようになります。
ここでは chpst という runit 付属のプロセス状態を変更するコマンドでユーザ権限でrunsvdirを実行します。
このrunsvdirというのがサービス登録されるプログラムのディレクトリを監視してくれます。

nhayashi@deb1:~$ sudo vi /etc/sv/runsvdir-nhayashi/run
#!/bin/sh
exec 2>&1
exec chpst -unhayashi runsvdir /home/nhayashi/service

今回は /home/nhayashi/service というディレクトリをサービス登録されるプログラムの監視対象ディレクトリにしました。

忘れる前に /home/nhayashi/service ディレクトリを作っておきます。

nhayashi@deb1:~$ mkdir /home/nhayashi/service

プログラム起動できるように実行権限を与えておきます。

nhayashi@deb1:~$ sudo chmod +x /etc/sv/runsvdir-nhayashi/run

次にログ管理するrunスクリプトを用意しておきます。

nhayashi@deb1:~$ sudo mkdir /etc/sv/runsvdir-nhayashi/log

今回はログ出力先に /var/log/runsvdir/nhayashi を指定しました。
またここでも 一般ユーザでログを見れるように chpst を使って実行ユーザを一般ユーザに変えています。
runit 付属のコマンドに svlogd という daemontools でいう multilog 相当のものがあるのでこちらを利用してログ出力を行います。

nhayashi@deb1:~$ sudo vi /etc/sv/runsvdir-nhayashi/log/run
#!/bin/sh
LOG=/var/log/runsvdir/nhayashi
test -d "$LOG" || mkdir -p -m755 "$LOG" && chown nhayashi:adm "$LOG"
exec chpst -unhayashi svlogd -t "$LOG"

忘れずに実行権限を与えておきます。

nhayashi@deb1:~$ sudo chmod +x /etc/sv/runsvdir-nhayashi/log/run

runit も daemontools を参考に実装されているため サービス登録されるプログラムと同じディレクトリに supervise ディレクトリを作成してデーモン管理します。
そのままだと /etc/sv/runsvdir-nhayashi/ 以下に状態管理ファイルが作成されてしまい気持ち悪いので /var/lib/supervise に変更します。
(ちなみにこの設定は runit で管理される git-daemon の実装を参考にしました。)

nhayashi@deb1:~$ sudo mkdir /var/lib/supervise/runsvdir-nhayashi
nhayashi@deb1:~$ sudo mkdir /var/lib/supervise/runsvdir-nhayashi.log
nhayashi@deb1:~$ sudo ln -s /var/lib/supervise/runsvdir-nhayashi /etc/sv/runsvdir-nhayashi/supervise
nhayashi@deb1:~$ sudo ln -s /var/lib/supervise/runsvdir-nhayashi.log /etc/sv/runsvdir-nhayashi/log/supervise

ここまでできたらユーザ権限でrunit管理下のデーモンを管理できるようサービスを登録します。
サービス登録は /etc/service にシンボリックリンクを貼れば runsvdir が自動でサービス登録を検知してくれます。

nhayashi@deb1:~$ sudo ln -s /etc/sv/runsvdir-nhayashi /etc/service/
nhayashi@deb1:~$ sudo sv status runsvdir-nhayashi

ちゃんとサービス登録できているか確認します。

nhayashi@deb1:~$ pstree -acu
init
  ├─runsvdir -P /etc/service...
  │   └─runsv runsvdir-nhayashi
  │       ├─runsvdir,nhayashi /home/nhayashi/service
  │       └─svlogd,nhayashi -t /var/log/runsvdir/nhayashi

runsv runsvdir-nhayashi から runsvdir,nhayashi /home/nhayashi/service と svlogd,nhayashi -t /var/log/runsvdir/nhayashi が起動できていることが確認できます。

一般ユーザでのrunitの設定(tiarraサービス登録)

ここからは一般ユーザにおけるデーモン化についてまとめます。
まずサービス登録するプログラムのディレクトリを用意します。
今回は tiarra をデーモン化するので ~/.tiarra/service にその設定をまとめます。

nhayashi@deb1:~$ mkdir ~/.tiarra/service

~/.tiarra/service/run に tiarra 起動プログラムを書きます。
実行権限を与えるのを忘れずに。

nhayashi@deb1:~$ vi ~/.tiarra/service/run
#!/bin/sh
exec 2>&1
exec tiarra --config=/home/nhayashi/.tiarra/tiarra.conf
nhayashi@deb1:~$ chmod +x ~/.tiarra/service/run

tiarra のログ管理を行うrunスクリプトを用意します。ログ出力先は ~/.tiarra/log/ に設定します。

nhayashi@deb1:~$ mkdir ~/.tiarra/log
nhayashi@deb1:~$ mkdir ~/.tiarra/service/log
nhayashi@deb1:~$ vi ~/.tiarra/service/log/run
#!/bin/sh
LOG=/home/nhayashi/.tiarra/log
exec svlogd -t "$LOG"

忘れずに実行権限を与えます。

nhayashi@deb1:~$ chmod +x .tiarra/service/log/run

一般ユーザでのrunitによるtiarraサービス起動

ここまでできたら準備は整ったので tiarra を runit 管理下のデーモンとして起動してみます。
起動方法は /home/nhayashi/service にサービス登録プログラムのシンボリックリンクを貼るだけです。

nhayashi@deb1:~$ ln -s /home/nhayashi/.tiarra/service /home/nhayashi/service/tiarra

ちゃんと起動できたか確認してみます。

nhayashi@deb1:~$ pstree -acu
init
  ├─runsvdir -P /etc/service...
  │   └─runsv runsvdir-nhayashi
  │       ├─runsvdir,nhayashi /home/nhayashi/service
  │       │   └─runsv tiarra
  │       │       ├─svlogd -t /home/nhayashi/.tiarra/log
  │       │       └─tiarra /usr/share/tiarra/tiarra...
  │       │           └─{tiarra}
  │       └─svlogd,nhayashi -t /var/log/runsvdir/nhayashi

sv コマンドでサービス管理を行うのですが下記のように SVDIR=(サービス登録ディレクトリ) を指定してあげる必要があります。
SVDIR を未指定の場合は /etc/service が設定されたものと認識されてしまうので気をつけてください。
sv status コマンドで状態を確認してみます。

nhayashi@deb1:~$ SVDIR=~/service sv status tiarra
run: tiarra: (pid 11202) 187s; run: log: (pid 11173) 380s

問題なく起動できてますね。

念のためログも正しく出力されているか確認してみようと思います。
と、その前に svlogd -t と指定してログ出力を行ったのですが、このままだと日時が意味の分からないものになっているので、daemontools 付属の tai64nlocal を使って人が読める形式に変換します。まずは daemontools のインストール。

nhayashi@deb1:~$ sudo apt-get install -V daemontools

下記のようにして見ることができます。

nhayashi@deb1:~$ tail -f ~/.tiarra/log/current | tai64nlocal

svlogd -tt とすれば人が読める形式にはなるのですが UTC timestamp で出力されるので日本より9時間遅い時間が出力されてしまいます。そのため私の環境では svlogd -t と設定して tai64nlocal で変換してみるようにしています。
(UTC timestamp で出力されたものを私が見る方法を知らないだけかもしれませんが。。。)

svコマンド例

デーモンの起動・停止は sv コマンドを使って下記のように行います。

nhayashi@deb1:~$ SVDIR=~/service sv start tiarra
nhayashi@deb1:~$ SVDIR=~/service sv stop tiarra

また私が見落としていてはまったのが svlogd プログラムの停止を忘れることが多く下記のように指定します。

nhayashi@deb1:~$ SVDIR=~/service sv start tiarra/log
nhayashi@deb1:~$ SVDIR=~/service sv stop tiarra/log

他にもいくつかコマンドがあるようなので試してみることをお勧めします。

まとめ

今回、ユーザ権限でデーモン管理ができる runit を試してみて現状問題なく動いているようです。
ただ実運用で使った実績はまだないのでもう少し検証して安定性を確認しようと思います。
runit 自体 daemontools を参考に実装されたこともあり、daemontools -> runit へ乗り換えるのは簡単にできそうです。

daemontools では コマンドが多かったり multilog の記述が難解だったり 最初使うのにすごい苦労した記憶があります。
runit だと コマンドも少ないですし、プロセスの起動フローもシンプルな印象を受けました。
daemontools と runit のプロセス起動を比較すると下記のようになると思います。

(daemontools)
init
 `-svscanboot
     |-readproctitle
     `-svscan
         |-supervise prog
         |   `-exec prog
         `-supervise log
             `-multilog

(runit)
init
 `-runsvdir
     `-runsv prog
     |   `-exec prog
     `-svlogd

svscanboot, svscan が runsvdir にまとまっているためシンプルなのかなと思いました。
今回、runit を試してみて意外に簡単に感じたのはそのせい?かなと思います。
当初、想定より簡単に使えて安定性も確認できれば daemontools から runit に乗り換えるのは賢い選択なのかなと思います。