萬由無事覚書

不知物故萬由無事覚書仕候也。

Gentoo Linux (OpenRC) でinitスクリプトを書くには [多重起動編]

基本編から続く。

「楽をするためならどんな努力も惜しまない」のが、良いプログラマの条件なんだって。

それが正しいかどうかはともかく、確かに同じようなこと何度も繰り返すのは面倒だと思う。

例えば、こういう場合。

  • 複数のWebアプリ、例えばSinatraでWebアプリを作った場合を考える。
  • その場合、サービスを提供するにはWEBrickThinを使うことが多い。
  • そうすると、各Webアプリの起動方法は同じだが、起動オプションや設定ファイル (文書ルートやDBの接続先など) のみが異なることになる。

このように多くのWebアプリを、initシステムを使って管理する必要がある場合、細かいオプションのみ変えたinitスクリプトをたくさん作らないといけない……。

コピー&ペーストでもいいけど、数が多くなるとバグの温床になりそうだ。

これを解決するには、1つのinitスクリプトを異なる設定で起動できるようにして、initスクリプトと設定ファイルを分割して、多重起動できるようにする方向でがんばる。

今回は、こんなユースケースに対応するinitスクリプトをメモメモ。

initスクリプトの設定ファイル

initスクリプトは設定を外部化できる。場所は、

/etc/conf.d/

となる。ここに、サービス名と同名のファイルを置いておくと、initスクリプトを呼び出したとき、自動的に読み込んでくれる。具体的には、

# touch /etc/conf.d/hogehoge
# nano /etc/conf.d/hogehoge
# /etc/init.d/hogehoge

とすると、/etc/conf.d/hogehogeの内容が読み込まれた後、/etc/init.d/hogehogeが実行される。ここでは、hogehogeがサービス名。

/etc/conf.d/hogehogeの中には、変数 (もしかしたらちょっとしたロジックも) などを入れておく。具体例を挙げると、次の通り。

/etc/conf.d/hogehoge
config_file="sample.conf"
  ...
/etc/init.d/hogehoge
  ...
start() {
    ...
  ebegin "Starting Hogehoge with ${config_file}
    ...
}
  ...

/etc/init.d/hogehoge startすると、

* Starting Hogehoge with sample.conf

と表示されるはず。

複数の設定ファイル

設定ファイルは、1つのサービスについて複数使用できる。

ただし、命名規則があり、

/etc/conf.d/service.config

形式である必要がある。

serviceがサービス名、configが設定名。

具体的にはこんなかんじだ。

/etc/conf.d/hogehoge.app1
/etc/conf.d/hogehoge.app2
/etc/conf.d/hogehoge.app3

initスクリプトの命名規則

以上のように設定ファイルの名前をつけておくと、1つのinitスクリプトで複数の設定を使用できる。

では、どうやって設定を切り替えるのか?

それには、シンボリックリンクを使う。こんなかんじだ。

# cd /etc/init.d
# ln -s hogehoge hogehoge.app1
# ln -s hogehoge hogehoge.app2
# ln -s hogehoge hogehoge.app3

そして、

# /etc/init.d/hogehoge.app1 start

とすれば設定app1hogehogeが開始される。

設定ファイルの読み込み順序

# /etc/init.d/hogehoge.app1 start

としてサービスhogehogeを起動した場合、設定ファイルは次のような順序で読み込まれる。

  1. /etc/conf.d/hogehoge
  2. /etc/conf.d/hogehoge.app1
  3. /etc/init.d/hogehoge.app1 (実体は/etc/init.d/hogehoge)

つまり、設定名がない設定ファイルが一番最初に読み込まれる。

これを利用して、共通設定や既定の設定は、サービス名と同名の設定ファイル (例では/etc/conf.d/hogehoge) に保存しておくといい。

設定ファイルの中で依存関係を設定する

同じサービスなのに、設定によって依存関係が違ってしまう場合がある。

ある設定ではロガーが必要だけど、別の設定ではcronが必要とか。

この場合、設定ごとに依存関係を指定できる。

具体的には、設定ファイルの中で次のようにする。

rc_need cron
rc_use logger
  ...

要は、基本編で書いた依存関係を設定するコマンドに、rc_をつけたもので指定する。

設定なしでのinitスクリプトの使用を禁止する

設定なしのinitスクリプトを使わせたくない場合がある。

その場合、こんなかんじで対応できる。

#! /sbin/runscript
service="${RC_SVCNAME%%.*}"
config="${RC_SVCNAME##*.}"
  ...
start() {
    ...
  if [ ${config} == ${service} ]; then
    eerror "Cannot start ${RC_SVCNAME} directly"
    return
  fi
    ...
}
...

serviceにはサービス名が入る。configには設定名が入る。

/etc/init.d/hogehoge.app1なら、service == hogehogeconfig == app1だ。

ただし、/etc/init.d/hogehoge startとされた場合、service == hogehogeconfig == hogehogeとなる。

これを利用して、設定名が指定されていない場合、サービスを開始しないようにしているのが上記の例。

なんか黒魔法的なのですが、このあたりはbashのパラメータ展開を参照のこと。

内部で使われる変数

ついでなのでここでメモメモ。

initスクリプト内では、内部で設定するといろいろな動作に影響を与える内部変数がある。代表的なのは、

descirption サービスの説明文。

など。

こんなかんじにする。

#! /sbin/runscript
  ...
service="${RC_SVCNAME%%.*}"
config="${RC_SVCNAME##*.}"
description="Service Hogehoge"
if [ ${config} != ${service} ]; then
  description="${description} with ${config}"
fi
  ...

こうすると、

# /etc/init.d/hogehoge describe

* Service Hogehoge

となり、

# /etc/init.d/hogehoge.app1 describe

* Service Hogehoge with app1

と表示される。

 

以上、initスクリプト多重起動編でした。

次回に続く。