2009年11月20日金曜日

自分で作るネットワークストレージ (2)

ファイルシステムを作ると言っても、OSネイティブのファイルシステムを作るのは大変です。しかしながら、最近はFUSE (Filesystem in Userspace)を使って手軽にファイルシステムを試作できるようになりました。以前だったら躊躇していたところですが、気軽に試せそうです。

FUSEはOS内部で発生したファイルシステムイベントをユーザー空間のプログラムに通知し、そこで必要な操作を代行させることでOSネイティブのファイルシステムと同様の操作性をファイルシステム利用者に提供しています。イベントの処理といっても、実際はイベントに対応したコールバック関数を記述する形になりますから、特に実装が複雑なわけではありません。FUSEでは様々なイベントに対応するコールバック関数が定義されていますが、すべての関数を実装しなければならないわけではありません。たとえば、シンボリックリンクをサポートしないのであれば、シンボリックリンクに関係する関数を実装する必要はありません。とりあえず今回対応するのは以下の関数です。試作にMacOS XのXcodeテンプレートを使うので、関数名がCocoa APIっぽく書かれていますが、簡単に読み替えることができると思います。

  • ディレクトリ一覧 (contentsOfDirectoryAtPath:error:, opendir(2), readdir(2)など)
  • ファイル情報取得 (attributesOfItemAtPath:userData:error:, stat(2))
  • ファイル情報設定 (setAttributes:ofItemAtPath:userData:error:, chmod(2)など)
  • ファイルオープン (openFileAtPath:mode:userData:error:, open(2))
  • ファイルクローズ (releaseFileAtPath:userData:, close(2))
  • ファイル読み込み (readFileAtPath:userData:buffer:size:offset:error:, read(2))
  • ファイル書き込み (writeFileAtPath:userData:buffer:size:offset:error:, write(2))
  • 新規ディレクトリ作成 (createDirectoryAtPath:attributes:error:, mkdir(2))
  • 新規ファイル作成 (createFileAtPath:attributes:userData:error:, open(2))
  • ファイル移動 (moveItemAtPath:toPath:error:, rename(2))
  • ディレクトリ削除 (removeDirectoryAtPath:error:, rmdir(2))
  • ファイル削除 (removeItemAtPath:error:, unlink(2))

FUSEで読み書き可能なファイルシステムを作る場合、上記の関数を実装すればとりあえず動きます。あとは、これらのイベントの裏で、適切に版管理システムと連携させてあげればよいわけです。版管理システムが提供するインターフェースは以下のようなものになるでしょう。

  • チェックアウト (checkout)
  • 更新 (update)
  • 追加 (add)
  • 複製 (copy)
  • 移動 (move)
  • 削除 (delete)
  • コミット (commit)

今回、版管理システムとしてSubversionを念頭に置いています。ですが、Subversionと同様の概念で構築されているシステムであれば、上記のような抽象化された版管理インターフェースと実際の動作を対応させることで、差し替えもできるのではないかと思います。

FUSEが提供するファイル操作と、版管理システムが提供するファイル操作をじっと見比べてみると、お互いの機能が似ていることがわかります。FUSE側に存在せず、版管理側に存在する操作としてチェックアウトとコミット、逆にFUSEには存在し、版管理システムに存在しない操作としてはファイルのオープンやクローズ、ファイル情報の操作などがあります。これらの差を埋めれば二つのシステムが相互に繋がりそうです。Subversionを前提にがっつり実装してもよいのですが、将来の拡張性を考えて、版管理抽象層を定義し、以下のAPIを版管理抽象層からFUSEファイルシステム側に提供することにしました。

  • 初期化 (revisionControlSetup:)
  • チェックアウト (revisionControlSetup:)
  • 追加 (revisionControllAdd:)
  • 削除 (revisionControlRemove:)
  • 複製 (revisionControlCopy:)
  • 更新 (revisionControlUpdate:)
  • コミット (revisionControlCommit:)
  • タッチ (revisionControlTouch:)
  • 終了処理 (revisionControlCleanup:)
  • 実パス名取得 (revisionControlRealPathForPath:)
  • 制限ファイル名取得 (revisionControlNameIsReservedAtPath:)

いくつか、版管理システムの操作一覧にないAPIを追加しています。初期化と終了処理はよいとして、タッチ、実パス名取得、制限ファイル名取得は、手元の作業コピーでの操作と版管理されているデータを結びつけるために必要となります。

今回、版管理システムを基礎としてファイルシステムを構築するので、ファイルへの操作はオリジナルのファイルではなく、手元に作られた作業コピーに対して行われます。作業結果は、最終的に版管理システムにコミットしなければならないので、どのファイルが操作されたのか履歴を記録しておく必要があります。タッチAPIは、作業コピーで修正されたファイルを版管理抽象層に通知します。

実パス名取得APIは、版管理システム内で使われているパス名を、作業コピー上でのパス名に変換するためのAPIです。今回の試作では、版管理システム内のディレクトリ構造を、手元のPCの特定ディレクトリにマウントして使うことを想定しています。FUSEから通知されるパスはマウントされたディレクトリからの総体パスになりますが、実際に操作できるファイルは作業コピーとして取り出したファイルパスになります。作業コピーを取り出した場所は版管理抽象層しか知らないので、実際のファイルパス名を知りたい場合に抽象層に問い合わせるAPIが必要になります。

制限ファイル名取得APIは、ファイルシステムとして利用できないファイル名を判断するためのAPIです。たとえば、版管理システムとしてSubversionを使う場合、.svnという名前のファイル名、ディレクトリ名は使えません。このAPIを通じて、後ろで使われている版管理システムで禁止されているファイル名を取得します。

とりあえずFUSE関数を上述の版管理抽象層APIで実装してみると、以下のようになります。

  • (FUSE初期化関数)
    • 初期化
    • チェックアウトあるいは更新
  • ディレクトリ一覧
    • 更新
  • ファイル情報取得
    • (作業コピーのファイル情報を取得)
  • ファイル情報設定
    • (作業コピーのファイル情報を取得)
  • ファイルオープン
    • タッチ
  • ファイルクローズ
    • コミット
  • ファイル読み込み
    • (作業コピーのファイルを読み込み)
  • ファイル書き込み
    • (作業コピーのファイルに書き込み)
  • 新規ディレクトリ作成
    • (作業コピーにディレクトリ作成)
    • 追加
  • 新規ファイル作成
    • (作業コピーにファイル作成)
    • 追加
  • ファイル移動
    • (移動元を移動先に)複製
    • (移動元を)削除
  • ディレクトリ削除
    • 削除
  • ファイル削除
    • 削除
  • (FUSE終了関数)
    • コミット
    • 終了処理

まぁ、いろいろと問題はあるのですが、一応動くものにはなります。ソースコードsourceforgeに公開していますので、興味のある人は覗いてみてください。sourceforgeに登録しているコードは、上記以上の機能も実装していますが、それはまた別の機会に。

次回に続きます。

2009年11月11日水曜日

自分で作るネットワークストレージ (1)

ネットワークストレージという考え方は昔からありましたが、それが単体サービスとして有償で提供されるようになったのはここ数年でしょうか。Dropboxなどに代表されるネットワークストレージサービスには一定の利用者がいるようで、解説記事もよく見るようになりました。

データをサーバに保持しておいて、ネットワーク経由でどこからでもアクセスするという考え方は新しいものではありません。ただ、そういったサービスを構築するには、高度なサーバ設定、ネットワーク設定の知識が必要だったため、一般の人が手軽に始めるというわけにはいきませんでした。近年のネットワークストレージサービスは、サーバ設定をサービス提供者側に分離し、クライアントとネットワークの設定を専用アプリケーションにすることでその敷居を下げ、技術者以外の利用者の取り込みに成功したのだと思います。

さて、特に昔からコンピュータネットワークを使っている人には共感してもらえると思いますが、自分のデータを自分の管理の行き届かない場所に預けるのは心配なものです。便利なネットワークストレージサービスですが、大切なデータをそこに保存しても大丈夫なのかどうか、つい考えてしまいます。そうはいっても便利なサービスは使いたい、ということで、自分で運用できないものかと考えるのは技術者として自然なことです。

では、自分にとってネットワークストレージサービスに必要な機能は何か、と考えてみると、以下のような要求がでてきました。

  1. 自分で運用できる
  2. ファイルシステムとして操作できる
  3. ネットワークに接続していなくてもある程度操作できる

要求1は、そもそもの発端なので当然です。要求2は利便性を確保するために重要です。ネットワーク上にデータを保存できても、それを直接ローカルアプリケーションで操作できなければ面倒です。OSのファイルシステムの一部として見えている、もしくは同等の操作性が提供されている必要があります。要求3も、現実の環境を考えると必須といえます。ネットワーク環境は日々向上しているものの、ネットワークに接続できない場所は必ずあるものです。その間、フル機能ではないにせよ、ある程度の操作ができないと使い勝手が落ちてしまいます。

これらの条件を満たすもので、現状一番近いものは版管理システムです。旧くはRCSやCVS、その後現れたSubversion、最近使われる事が多いGitなどが有名です。これらの版管理システムは一種のファイルシステム機能を提供しています。ただ、元々プログラムのソースコードの改変履歴を記録する目的で設計されたシステムですから、OSのファイルシステムと同様には操作できません。ファイルを更新しようとした場合、まず版管理システムに保存されているデータを、通常のファイルシステム上に複製(チェックアウト)し、その複製に対して編集を行い、編集完了後に書き戻し(チェックイン)といった、通常のファイル操作とは異なる粒度でのファイル操作が必要になります。

それならば、その部分をうまく隠蔽し、通常のOSレベルでのファイル操作と同等のインターフェースを提供できれば、自分の欲しいネットワークストレージになるのではないか、しかも版管理機能のおまけ付き、という考えが浮かびます。

実際、そういう試みは過去にありました。かなり古いプロジェクトですが、CVSサーバをNFSマウントするVirtual CVS Filesystemというソフトウェアがsourceforgeに登録されています。ただし、プロジェクトが活動停止してからかなり時間が経っているようです。また、FUSEを用いたSVNレポジトリアクセス用ファイルシステムSvnFSというのもあります。こちらは開発が継続しているようです。ただ、どちらも読み取り専用ファイルシステムで、ネットワークストレージとしては中途半端な状態です。ここはやはり、読み書きできるストレージシステムが欲しいところではないでしょうか。

ということで次回に続きます。

2009年7月22日水曜日

FUSEオペレーションの可視化

FUSE (Filesystem in Userspace) はvfs/vnode APIをユーザ空間のプログラムから利用できるようにするための機構で、OSでサポートされないファイルシステムを容易に追加できます。sshサーバ上のディレクトリにアクセスするためにsshfs-fuseを使っている人も多いのではないでしょうか。

vfs/vnodeアクセスがユーザ空間から見えるので、それを利用すればファイルシステムへのアクセスの様子が見えるはず、ということでUbiGraphを使ってsshfs-fuseのアクセスを可視化してみました。

まずは、sshfs-fuseでマウントしたディレクトリ上で、次のスクリプトを実行してみました。

cd /sshfs
for i in 0 1 2 3 4 5 6 7 8 9 10
do
mkdir $i
cd $i
for j in a b c d e f g
do
mkdir $j
done
done
sleep 2
cd /sshfs
rm -rf 0


11レベルの階層ディレクトリを作り、それぞれの階層に7個のディレクトリを作成した後、すべてのディレクトリを削除しています。各ノードは、ファイル/ディレクトリの実体に最初にアクセスされた段階で描画されます。ですから、初期状態では、トップディレクトリにあるオブジェクトしか見えていません。グラフのノードはファイルかディレクトリを表しており、緑色のノードがディレクトリ、青いノードがファイルです。アクセスされたオブジェクトは、色が赤くなるとともに、そのオブジェクトのファイル名/ディレクトリ名が表示されます。

続いて、sshfs-fuseでマウントしたディレクトリ上で、wgetをコンパイルしてみました。

cd work
tar zxf wget-1.11.tar.gz
cd wget-1.11
sh configure
make
make distclean
cd ..
rm -rf wget-1.11

wget-1.11.tar.gzを展開すると、ファイルの生成に合わせてディレクトリ木が徐々に伸びていくのが分かります。



configureの過程ではwget-1.11を展開したディレクトリ直下のファイルが頻繁にアクセスされており、makeが始まると進み具合に応じて各ディレクトリのファイルが順次アクセスされていくのが見えます。

単にアーカイブを展開、コンパイル、削除しただけですが、可視化することでまた違った感じがします。

2009年6月12日金曜日

Xen Guest OSのOfflink Migration

Live Migrationの課題

ライブマイグレーションは、移動元と移動先のHost OSが、同一のサブネットワークに接続されていることを前提としています。なぜならば、Guest OSが利用するネットワーク環境はHost OSのネットワーク環境に依存しているため、Host OSとInternetとの接続状態が変更されると、それに応じてGuest OSのネットワーク設定を変更しなければなりません。

Network Mobility Basic Support (NEMO BS)

NEMO BSはIPv6モバイルルータを実現するプロトコルで、RFC3963として標準化されています。NEMO BSを実装したモバイルルータは、自身が抱えるネットワークに固定のアドレスを提供しつつ、任意のネットワークに自由に接続できるようになります。

Host OSのモバイルルータ化

Live Migrationの問題である、Host OSのネットワーク環境の変化は、NEMO BSを組み合わせることで解決できます。Guest OSが接続するネットワークを、NEMO BSの機能として提供される固定ネットワークにすることで、NEMO BSの設定情報を共有するHost OS間で、Host OSの物理的な位置に関わらずGuest OSをMigrationできます。

Interop Tokyo 2009での実験

Interop Tokyo 2009では、NEMO BS機能を追加したXenサーバを2台作成し、それぞれのサーバを異なるサブネットワークに配置しました。Guest OSは、いずれかのXenサーバで動作します。

Guest OSのMigrationは、通常のXen Guest OSのMigrationと同様の手順で実施されます。異なっている点は、Migration先のXenサーバが、同一サブネットワークではなく、異なるサブネットワーク上に配置してある点です。通常、このような構成ではGuest OSのMigrationは成功しません。Guest OSが他方のXenサーバに移動した時点で、ネットワークから切り離されてしまうためです。

本実験では、Guest OSをMigrationすると同時に、移動元のXenサーバ上で動作しているモバイルルータ機能を停止し、他方のXenサーバでモバイルルータ機能を開始します。Guest OSが接続しているネットワークには、モバイルルータによって固定のネットワークが提供されています。このネットワークは実際にはInterop Tokyo 2009のShowNetネットワーク内に配置されたホームエージェントによって管理されており、論理的にはShowNetネットワークの一部になります。

Gust OSは二つのモバイルルータ間を移動しますが、モバイルルータが提供するネットワークアドレスは変化しないため、Guest OSはHost OSが接続したネットワークが変わったことを意識する必要が無くなります。

トラフィックのグラフ

実験では、Guest OSから定常的なストリーミングトラフィックを送信しながら、5分間隔でふたつのHost OSの間をMigrationさせています。それぞれのXenサーバのインターフェースのトラフィックを示します。グラフからGuest OSがふたつのXenサーバの間を移動していたことがわかります。

謝辞

本実験の実施に際して、ShowNet NOCメンバーのみなさまに多大なご支援をいただきました。ここに感謝いたします。

2009年6月11日木曜日

Xenカーネルの再構築

XenのLive Migrationで遊ぶために、LinuxのインストールやNFS rootの設定やらに四苦八苦しつつも、なんとか基本的なMigrationまではできる環境を構築できた。本当にやりたかったことは、このLive Migrationを、異なるふたつのネットワークセグメントに配置されているXenサーバ間で実行することだったりする。

アイデアとしてはシンプルで、XenサーバをNetwork Mobility (NEMO) 機能を持ったモバイルルータとし、Guest OSが接続するネットワークをMobile Networkとして運用するというものだ。ふたつのXenサーバを用意して、それぞれを同じモバイルルータとして設定しておく。Guest OSのMigrationと同時に、元のHost OSのモバイルルータ機能を停止し、Migration先のHost OSのモバイルルータ機能を有効化すれば、Guest OSからみるとネットワーク的には移動していないように見える。

ところが、Xenを導入したDebianでNetwork Mobilityのプログラム (NEPL) を起動させようとしてみたところ、動作しないことが判明した。どうやら、NEPLが必要としているカーネル機能が組み込まれていないことが原因らしい。最近のLinuxは多くの機能が動的にロードされるモジュールとなっているが、中には動的モジュールとして分離できない拡張機能も少ないながら存在する。今回問題になったのはxfrmのポリシー拡張機能 (CONFIG_XFRM_SUB_POLICY) だった。この機能がカーネルに組み込まれていないと、そもそもMobile IPv6やNEMOの機能を利用することができない。しかし、カーネルのモジュールディレクトリには、Mobile IPv6やNEMOの基本部分を実装したmip6.koが収められており、一見Mobile IPv6/NEMOを利用できるかのように見えてしまう。これはまぎらわしい。

ともかく、カーネルの再構築が必要なので、その作業を進めることにする。XenのHost OSサポートはまだLinuxカーネルのメインラインに取り込まれていないので、再構築の際にはXenパッチを適用する必要がある。今回、Xen Host OSカーネルはAPTを使ってバイナリパッケージをインストールしているが、APTにはパッケージをソースから再構築する手段も提供されている。

今回使ったバイナリパッケージはlinux-image-2.6.26-2-xen-686なので、まずはこのパッケージをソースから再構築するために必要なツール群をインストールする。これもAPTを利用すれば簡単だ。APT便利だなぁ。

# apt-get build-dep linux-image-2.6.26-2-xen-686

これで必要なツール群がインストールされる。続いて、カーネルパッケージのソースを入手する。

# apt-get source linux-image-2.6.26-2-xen-686


カレントディレクトリにソースと必要なパッチが展開されるので、それを使ってパッケージの再構築をおこなう。単に再構築するだけならば、ここからさらに次のコマンドを実行するだけでよい。

# dpkg-buildpackage

これで、バイナリパッケージとして配布されている物と同じパッケージを再構築できる。もちろん、今回の目的はカーネルの組み込み機能を変更することなので、そのまま構築するだけでは意味がない。パッケージ構築時に参照されるカーネルスイッチは、ソースが展開されたディレクトリにあるlinux-2.6-2.6.26/debian/config/configファイルに列挙してある。なるほど確かに、先のオプションスイッチ (CONFIG_XFRM_SUB_POLICY) は定義されていない。このスイッチを有効化して、パッケージを再構築するが、単にdpkg-buidpackageコマンドで再構築すると、カーネルABIの一貫性チェックで失敗するので、linux-2.6-2.6.26/debian/abi/2.6.26-2/ディレクトリの名前を変更 (あるいは削除) しておく。このディレクトリには、コンパイルされたカーネルのシンボル情報とアドレス情報が記述されており、実際に構築されたカーネルがこの情報と一致しない限りパッケージは作成されない。

これでようやくXen + NEMOカーネルが完成した。ソースを展開したディレクトリに、.debパッケージができているはずなので、これをdpkgコマンドでインストールし、ようやく準備完了。

# dpkg -i linux-headers-2.6.26-2-common-xen_2.6.26-15lenny2_i386.deb

# dpkg -i linux-headers-2.6.26-2-xen-686_2.6.26-15lenny2_i386.deb

# dpkg -i linux-image-2.6.26-2-xen_2.6.26-15lenny2_i386.deb


# dpkg -i linux-modules-2.6.26-2-xen_2.6.26-15lenny2_i386.deb

2009年6月2日火曜日

NFS rootによるXen Guest OS

Xenには、あるHost OSから、同一セグメント上にある別のHost OSにGuest OSを移動させる機能があり、migrationと呼ばれている。今回はmigration可能なGuest OSを作成するときの手順をメモしておく。

Migrationといっても、Guest OSのすべてのコンポーネントがHost OS間を移動するわけではない。移動するのはGuest OSのメモリイメージである。すなわち、ストレージに関してはmigration前後で同じ物を参照しておかなければならない。結果として、ストレージをすべてネットワークの向こう側に配置することになるのだけれど、一点注意しておかなければならないことがある。それは、Guest OSの起動に使われるrootパーティションもネットワークストレージに置いておかなければならないと言う点だ。

今回はネットワークストレージとしてNFSを使うこととし、以下の手順でNFS rootパーティションから起動するGuest OSを準備した。
  1. 通常のXen Guest OSイメージを作成する。
  2. 作成したイメージをNFS公開ディレクトリに展開する。
  3. NFS機能を組み込んだkernelを作成する。
  4. 作成したkernelでGuest OSを起動する。
Debianにはxen-toolsAPTパッケージが用意されており、簡単にDebianのXen Guest OSを作成することができる。
# xen-create-image --hostname=guest --ip=10.0.0.64 --netmask=255.255.255.0 --gateway=10.0.0.1 --dir
--hostname--ip--netmask--gatewayはそれぞれ、作成されるGuest OSのノード情報となる。--dirスイッチを指定するとGuest OSのディスクイメージが/home/xen/domains/ディレクトリの下に作成される。evmslvmといったボリューム管理システムを使っている場合は、オプションスイッチで新しいボリュームにGuest OSイメージを作成することもできる。他にも多くのスイッチがあるので、細かく制御したい方はマニュアルページを参照のほど。

作成されるディスクイメージは単一ファイル (上記の例の場合は /home/xen/domains/guest/disk.img) になっているので、ループバックマウントしてNFS公開ディレクトリにコピーする。

続いてGuest OS用のkernelを再構築する。通常、Host OSにXenをインストールした時点で、Guest OSのkernelとして利用できるkernelイメージが/boot/ディレクトリにインストールされている。しかし、このイメージはrootパーティションをNFS上に置く場合は利用できない。Debian kernel では (おそらく他の多くのDistributionでも)、NFS機能はダイナミックモジュールとして提供されるのが普通である。そのため、rootパーティションがNFS上にあると、NFS機能を有効化するためのダイナミックモジュールを読み込むことができなくなる。よって、NFS機能をモジュールとしてではなく、kernel組み込み機能として作成しておかなければならない。また、NFSをrootパーティションとしてマウントするための特別なkernelスイッチも有効にする必要がある。

Linux kernel再構築の詳細は省略するが、以下のスイッチ、および関連スイッチを調整することでNFS機能をkernelに組み込むことができる。
CONFIG_NFS_FS=y
CONFIG_ROOT_NFS=y
スイッチには依存関係があるので、make menuconfigを使って依存関係を壊さないように調整するようにしよう。少なくとも、僕は依存関係を手動で調整するのはあきらめた。今回はさらに、NFS関連設定に加え、XenのGuest OSとして動作するためのスイッチも有効化することを忘れないように。

作成したカーネルを適当な位置にコピーし、Xen Guest OSの設定ファイルを作成する。
kernel = '/boot/bzImage'
memory = '128'
root = '/dev/nfs'
nfs_server = '10.0.0.2'
nfs_root = '/export/xen/domains/guest'
extra = 'ip=10.0.0.64:10.0.0.2:10.0.0.1:255.255.255.0::eth0:'
name = 'guest'
vif = [ '10.0.0.64',mac=00:16:3E:E2:0A:2F' ]
on_poweroff = 'destroy'
on_reboot = 'restart'
on_crash = 'restart'
通常のGuest OSの設定ファイルと異なるのは、rootディレクティブに/dev/nfsが指定されること、nfs_serverディレクティブでNFSサーバのIPアドレスを指定する必要があること、nfs_rootディレクティブでNFSサーバのマウントポイントを指定する必要があること、extraディレクティブにNFSのrootパーティションから起動するためのkernelスイッチを指定する必要があるあたりだろうか。kernelスイッチに関しては、Linuxのソースを展開したディレクトリにある、Documentation/filesystems/nfsroot.txtに詳しい説明が書かれている。それによれば、ip=スイッチの意味は
ip=[client-ip]:[server-ip]:[gw-ip]:[netmask]:[hostname]:[device]:[autoconf]
とのことだ。hostnameは今回利用しないので空欄にしてある。autoconfについては、dhcpbootprarpなどを指定することでIPアドレスを自動設定できるようだが、今回は静的にアドレスをつけているので、ここも空欄にしてある。

後は、NFSサーバで適切に公開設定を行い、通常の手順でXen Guest OSを作成する。設定に問題がなければ、Guest OSの設定ファイルで指定したkernelを読み込み、起動した後、NFSサーバ経由でrootパーティションがマウントされ、通常のブートプロセスが開始する。

さて、現在のところ、LinuxのNFS実装は、まだIPv4しかサポートしていないようだ。少なくとも、Debianの通常のNFSサポートではIPv6アドレスを指定してNFSマウントすることができない。もちろん、NFS rootパーティションをIPv6経由でマウントすることもできない。少しGoogleしてみたところ、NFSのIPv6サポートを進めている開発者は存在するようで、2008年のLinux Storage & Filesystems WorkshopにてIPv6 support for Linux NFSという発表が行われていたようだ。2008年後半を目標に開発を進めると書かれていたので、近いうちにIPv6サポートが利用できるようになるのかもしれない。

2009年5月30日土曜日

Xenのインストールに苦労する

仮想化が注目されるようになって久しいが、ようやくXenに手をつけてみた。かなり流行に乗り遅れた感があるけれども、いろいろとはまったところもあるので、メモ代わりに記録を残す事にする。知っている人にとっては当たり前の内容だが、自分自身が後でまた同じ苦労をしそうなので、未来の自分に向けてはまった点を書いておこう。

はまった理由は、Linuxの知識の少なさに由来する部分も大きい。ずっとBSD系のOSを使ってきたので、Linux世界の暗黙の前提が分からない事も多く、Linux使いの同僚や知り合いにたくさん質問をするはめになってしまった。おかげで、多少なりともLinuxの使い方が上手になったかもしれない。

Xenは、Host OSとしてLinuxNetBSDをサポートしている。今回は、Xenと平行してLinuxのMobile IPv6スタック (NEPL) を利用する予定にしているので、ホストOSとしてLinuxを選択した。

今回使うDistributionはDebian。まわりのLinuxカーネル開発者の多くが使っているので、それに倣ってみた。
  • Debian testingリリース (2009年5月時点)
  • Xen 3.2.1
Debianは現時点での最新開発リリース (testing) を使ったけれども、実際はstableでもよいはずだ。NEPLが前提とするカーネル機能が、比較的新しいLinuxカーネル (2.6.23以降) にしか入っていないため、それに合うリリースを使う。stableリリースのカーネルも、十分条件を満たしているのだけれど、なんとなくtestingを使ってカーネル最前線を楽しんでみる。

Xenの最新バージョンは3.4 (2009年5月時点) だが、インストール作業などをざっくり省略したかったので、APTパッケージとして準備してある3.2.1を利用することにした。

最初の問題は、DebianやXenのインストールは問題なく完了しているにもかかわらず、実際にXenを使おうとするとうまく動作していないことだった。この、「何もしていないのに動かない」系の問題は、作業をしている本人が本当に何も分かっていない場合、特に始末が悪い。Googleで同じ問題を経験した人を探してみるものの、全くそういう報告が見当たらない。これは逆にめずらしい。つまり、普通の人なら、絶対にやらない間違いをやっているということになる。

調べてみると、どうやらGuest OSを接続するためのブリッジインターフェースの作成と、Host OSが実際のネットワークと接続する物理インターフェースの作成に失敗しているようだった。

Xenサービスが起動する際、Host OSのネットワークインターフェースは、だいたい以下の手順で操作される。
  1. Guest OSを収容するためのブリッジインターフェース (tdev) を作成する。
  2. Host OSが、Xenサービス開始前に利用していたインターフェース (通常はeth0) のネットワーク情報 (IPアドレス、経路情報など) を、1.で作成したtdevインターフェースに移動する。
  3. eth0インターフェースをpeth0に名称変更する。
  4. tdevインターフェースをeth0に名称変更する。
  5. peth0インターフェースをブリッジインターフェース (この時点ではeth0) のスレーブとして追加する。
この操作の結果、Host OS上にeth0というブリッジインターフェースが新規に作成され、もともとeth0という名前だったインターフェースはpeth0に名前を変えることになる。なぜこのような複雑な手順が必要かというと、Host OS上で動作するアプリケーション群から、インターフェース名の変更を隠蔽するためだろう。Xenサービス開始前と後では、eth0の構成状態が異なる (通常のインターフェースからブリッジインターフェースに変更されている) が、アプリケーションからみるとXenサービス開始前と同様、eth0のままアクセスできる。

問題なさそうだが、最初にXenを使おうとした時は、なぜかeth0peth0に同じネットワーク情報が重複して設定されるという状態に陥っていた。さんざん悩んだ挙句、問題はNetworkMmanagerと呼ばれるソフトウェアとの競合にあることが分かった。NetworkManagerは、ネットワークインターフェースの設定を半自動化するアプリケーションソフトウェアのようだ。ネットワークインターフェースのup/downに応じて、設定ファイルに記述された情報を元にアドレスを構成する。Xenの場合、前述したブリッジインターフェースの構成の途中で、インターフェースのup/downが発生する。このとき、すでにアドレスを取り除かれたeth0インターフェースが、peth0に名称変更される前にup/downが行われ、結果NewtorkManagerによって再び (不要に) アドレスが構成されていた。

当然、この問題はNetworkManagerがインストールされていなければ発生しない。どうやら原因は、Debianのインストールの際に、なにも考えずにDesktop環境を構成したことにあったようだ。NetworkManagerは、GUI統合環境のタスクバーから簡単にネットワークインターフェースを設定するために使われる事が多く、今回インストールしてしまっていたDesktop環境でも利用されていた。

あらためてDebianをCUIインターフェースのみの構成でインストールし直してみると、なんの問題もなくXenサービスが起動した。普通Xenなぞを使おうと思うような人は、Desktop環境をインストールすることもないだろうから、誰も問題に遭遇していないのだろう。

ともかく、これでようやく下準備ができた。問題はさらに続く。。。