2007年08月13日
Etch/Sidの上にSarge環境を作る方法
debian-usersなどでもたびたび話題になっていますが、某医療系システムのように、現行安定版のEtchではなく、旧安定版のSargeを必要とするためにセットアップに苦しんでいる人がいるようです。「SargeがだめならEtchにすればいいのに」とモヒカン・アントワネットになるところですが、まぁちょっと深追いしてみましょう。
なにぶん、Sargeで採用されているインストーラのカーネルは2.4.27か2.6.8の2択で、今時のマシンのSATAやNICのサポートについてはまったく期待できない状況です。 とはいえ、動くマシンを探してひどい型落ち品を定価購入&高額保守サービスというのも、MIL用途でもあるまいし、馬鹿馬鹿しい話です。 私のほうで2.6.*の新しめのインストーラを作っていましたが、セットアップレベルでのoldstable対応をしていないなど、まぁ結局面倒は多いですね。
せっかく簡単にインストールできるEtchがあるのに、Sargeを使い続けないといけないのでしょうか。VMwareなどの仮想化ソリューションを使えば、わりあい枯れたハードウェアがエミュレートされているので、一応簡単にSargeのセットアップなどの実現はできますが、仮想化固有のオーバーヘッドがあり、今のマシンじゃパワー不足なので買い直し…ということになりかねません。
こういうときに便利なのが「chroot」です。chrootはカーネル、ハードウェア、ネットワーク、ポート、メモリ空間、プロセス空間等々を共有しつつ、システムディレクトリ構造の頂点となるルートディレクトリを切り替えることでシステムを分離する技術です。共有しているものが多いので、セキュリティ上個々のサービスを完全に分離したいといった用途には向きませんが、今回のようにとりあえず異なるディストリビューションバージョンを共存させたいといった用途には十分です。
セットアップ手順としては、まずchrootを動かす前提となる親環境はEtch(あるいはその他の将来の安定版)を普通にインストールします。Etchのインストーラおよびカーネル(2.6.18)なら、今どきのマシンでだいたいセットアップできるでしょう。より新しいカーネルを採用したものも作っているので、うまくいかないときにはこちらを試してみてください。
以降でのシナリオは、次のとおりです。
- i386またはamd64を親環境とする。
- /var/local/sarge-chrootというディレクトリをSarge chrootのルートディレクトリにする。
- ユーザーアカウント情報、ホームディレクトリは親環境と同一のものを使う。
次に、Debianのchrootを作成するためのcdebootstrapパッケージ、chrootを親環境から簡単に扱うようにするためのschrootパッケージをインストールします。準備ができたところで、さっそくSargeのchrootをcdebootstrapコマンドで作ってみることにします。
# cdebootstrap sarge /var/local/sarge-chroot http://cdn.debian.or.jp/debian (ちなみにamd64環境でi386 chrootを作るには、「-a i386」を付けます) … P: Writing apt sources.list
これで、Debian Sargeのディレクトリ構造が/var/local/asrge-chrootに作成されました。このchroot内はrequired/import程度のパッケージが入ってるだけでほとんど何もないので、もうちょっとセットアップすることにします。この時点ではrootだけが利用できるchrootコマンドでchroot環境にアクセスできます。
# cp /etc/resolv.conf /var/local/sarge-chroot/etc # chroot /var/local/sarge-chroot aptitude update # chroot /var/local/sarge-chroot aptitude install ~pstandard ~t^japanese$ (Sargeの標準インストール状態と同じにする。個々にインストールしてもよい) # chroot /var/local/sarge-chroot aptitude remove nfs-common (多分使わないであろうnfs-commonでエラーが出るので削除しておく)
パッケージのインストール中にlocalesの質問を尋ねられるので、ja_JP.EUC-JPとja_JP.UTF-8を有効にしておきましょう(あとからchroot /var/local/sarge-chroot dpkg-reconfigure localesを実行することでも再設定できます)。サービス関連は後から手動で起動するので、聞かれたときには起動しないように設定しておくのがよさそうです。
ここで一旦親環境ごと再起動しましょう。chroot内で何のサービスが動いているか確実に把握できるなら再起動の必要はないのですが、一応安全のために、です。知らないうちに動いているサービスは怖いですからね。特にSargeは無駄にネットワークに開放するサービスがいくつかある(危険というほどではないけど)ので、こうしたほうが安全です。なお、すでに親環境で動いているサービス(sshなど)については、chroot内でポートの重複するサービスが動いてしまうことはないはずです。
再起動が済んだら、ユーザー情報を中心にセットアップを進めていきましょう。この時点ではchroot内のサービスは何も起動していません。
# cp /etc/passwd /etc/shadow /var/local/sarge-chroot/etc # vi /etc/fstab (以下の内容を追加) proc /var/local/sarge-chroot/proc proc defaults 0 0 /tmp /var/local/sarge-chroot/tmp none bind 0 0 /home /var/local/sarge-chroot/home none rbind 0 0 (ここまで追加) # mount /var/local/sarge-chroot/proc ; mount /var/local/sarge-chroot/tmp; \ mount /var/local/sarge-chroot/home
パスワードを尋ねるような状況がなさそうなら、/etc/shadowはコピーしなくてもよいでしょう。 親のproc、/tmp、/homeをchrootにマウントさせています。procディレクトリはプロセス空間をユーザーランドで得る(psコマンドやデーモン起動など)ために使います。/tmpは必須ではないのですが、Xアプリケーションを起動したいときには必要です。bindオプションで親環境と同一のものをマウントするようにしています。/homeも同様に同一のものをマウントしていますが、rbindオプションによって、親環境が/homeの中で別のファイルシステムをマウントしている場合もそれに追従できるようにしています。
ユーザーの環境ができたので、rootしか利用できないchrootコマンドの代わりに、schrootコマンドで一般のユーザー権限で入れるようにします。これには、/etc/schroot/schroot.confファイルを編集します。
[sarge] description=Debian sarge location=/var/local/sarge-chroot priority=0 users=andy root-users=andy
ここでは、andyが「sarge」という名前でSarge chrootにアクセスできるように設定し、このユーザーでrootとしてもログインを許可するようにしています。priorityはあまり意味がないらしいですが、oldstableなので0を指定しています。グループ単位での制御やフックなど、詳細についてはman schroot.confを参照してください。
これで準備はほぼ完了したので、ユーザーの状態でschrootを試します。
andy$ schroot -c sarge I: [sarge chroot] Running login shell: '/bin/bash' $ (chroot内) $ exit andy$ schroot -c sarge -p (-pは環境変数を引き継ぐ) I: [sarge chroot] Running login shell: '/bin/bash' $ (chroot内) $ xterm (chroot内のXアプリケーションも起動できる) $ exit andy$ schroot -c sarge -p xterm (当然、直接Xアプリケーションを起動する こともできる) andy$ schroot -c sarge -u root (rootとしてログイン) I: [sarge chroot] Running login shell: '/bin/bash' # (chroot内) # exit
あとは、適宜chroot内のroot権限で、/etc/apt/sources.listの修正や、追加パッケージのインストールなどを行っていきます(デフォルトではsarge mainしか入っておらず、セキュリティアップデートも入っていません)。
- デーモン起動の発生するパッケージについては、後で起動対象にするのでその名前を控えておいてください。
- chroot内に/etc/debian_chrootのようなファイルを作成し、これに「sarge」のように書いておけば、chroot内のプロンプトが「(sarge)andy@debian:~$」のようになってくれます。
- chroot内のXアプリケーションを親環境から起動したいときには、「schroot -c sarge -p アプリケーション名」を実行するアプリケーションランチャアイコンを作るのがよいでしょう。
- 印刷についても、CUPS系であればデフォルトでローカルホストのポート631に出力するだけなので、Etch以降のわかりやすいCUPS 1.2サーバを利用できます。chroot内にはcupsys-clientパッケージを入れ、lpコマンドで出力します。
では最後に、再起動時にchroot内でも必要なデーモンが起動するよう、initスクリプトを作成します。たとえば次のようなスクリプトchroot-servicesを親環境の/ec/init.dに置き、「update-rc.d chroot-services defaults 99 00」のようにして親環境の起動時にchroot内のサービスを起動するようにします(サービスを起動する順序に注意してください)。revwの関数は鵜飼さんに考えていただきました。ありがとうございます。
#!/bin/sh
revw() {
set -- "$@"
r=""
while [ $# -gt 0 ]; do
w=$1; shift
r="$w $r"
done
echo "$r"
}
echo "start services (chroot Sarge):"
services="cron sysklogd postgresql"
if [ "$1" = "stop" ]; then
services=$(revw $services)
fi
for s in $services; do
schroot -q -c sarge /etc/init.d/$s $1
done
(ちなみに、「スペースで区切られた単語の順序(単語自体のつづりは変えない)を逆にする」というこのテーマは佳境な人々の関心を喚起したようで、「sed -e ':loop;s/^\([^ ][^ ]*\) *\([^:]*\)\(:.*\)*/\2:\1\3/;t loop;s/:/ /g'」(by ukai)とかも。)
procやバインドマウントをしていない状態にしてからchrootごとアーカイブ化すれば、ほかのマシンにコピーして利用することもできます。こういうのをサービスプロバイダが配布するとよさそうです。
注意すべき点としては、セキュリティアップデートの更新があったときに、chroot内は手動で更新する必要があることです。これを怠ると、そのchroot内で起動していたネットワークサービス経由で汚染される危険があります(過去のruby-langクラックが確かこれだっけ)。上記したようにchrootはセキュリティ対策としてはあまり期待できないので、侵入されるとchroot内のみならず、chrootの親環境やほかのchrootも危険にさらされます。chrootをいっぱい抱えているようなときには、次のようなスクリプトを用意しておくのも1つでしょう。
#!/bin/sh # sarge, sarge2, etch-test というchroot環境をそれぞれ更新する for e in sarge sarge2 etch-test; do echo "[update chroot $e]" schroot -q -c $e aptitude update schroot -q -c $e aptitude upgrade schroot -q -c $e aptitude autoclean done
このほか、たとえば親環境のsysklogdをリモート受け付け可能にして(かつネットワーク外部からのアクセスは禁止して)chroot内からのメッセージは全部@127.0.0.1に送るようにする、ユーザー情報をLDAP管理などにして完全に情報を統一する(デーモンユーザーが環境によって異なる可能性があることに注意)、システムを簡単にコピーできることを生かして定期リプリケーションする、などなどいろいろやり方はあると思います。 レガシーシステムにすべてを引きずられる必要はありません。
P.S. いずれにしてもSargeはもう余命いくばくもないので、Sargeを必要とするようなシステムを提供しているベンダが、ちゃんと現安定版への安全なアップグレードパスを作るとか、Sargeを独自にサポートし続けるとか、現安定版あるいは将来の安定版でも動作するような環境セットアップツールを作成するとかしないとダメだとは思います。
![[hatena]](http://d.hatena.ne.jp/images/b_entry_de.gif)
![[RSS]](/d/rss10.png)