Hyper-VとVirtual Serverの相互運用

ちょっとご無沙汰になっていましたが、今回はちょっと毛色の変わった話で、Pythonから離れたインフラの話題をやろうと思います。

物理サーバのレベルで仮想化するのが、流行ってきました。Hyper-VXenですが、Citrixが管理コンソールを発表したXenと、シングルベンダで頑張っているマイクロソフトHyper-V(こちらはWindows Server 2008 R2で高機能化しますね)を話題にします。実際のプロジェクトではHyper-Vを使っているのですが、Hyper-Vとその他の環境を移行させなければいけない困った事態に遭遇して、一応解決できたので、まとめてみます。


Windows Server 2008には、Hyper-Vというハイパーバイザ型の仮想化サービスがビルトインされています。当然、CPUが仮想化に対応していて、メモリ拡張(PAE)が使えて、といったハードウェアの制約はあるのですが、Windowsサーバで管理はしたくて、物理サーバをそんなに台数確保しにくいような場合に、かなり便利な機能となっています。

従来は、Virtual PC(たしかConnectixからの買い物でしたね)、さらには複数の仮想PCイメージをエミュレーションするVirtual Serverを使うのが一般的でした。こちらは、パフォーマンスさえ高いPCであれば、ハードウェアの制約なく仮想サーバを動作させられる、これまた便利なWindowsサービスです(Virtual Server 2005以降は無償提供されましたしね)。

このHyper-VとVirtual Serverなのですが、細かい仕組みは置いておくとして、HDDがVHDというイメージ ファイルで管理している、という意味では共通の仕組みを持っています(物理HDDをそのまま使ってもよいのですが、一般的ではないです)。そこで、誰しも考えるのが、従来Virtual Serverで運用していたサーバ イメージを、Hyper-Vマイグレーションできないだろうか、という要求です。

Virtual ServerからHyper-VVHD移行するには?

Virtual ServerからHyper-Vへの移行は、以下のような手順で可能です。

  1. 稼働中のゲストOSからVirtual Server拡張をアンインストールする
  2. VHDファイルをHyper-V管理下のディレクトリにコピー
  3. Hyper-Vマネージャで新規チャイルド パーティション(ゲストOSに相当)を作成する
  4. チャイルド パーティションの設定でIDEチャネルにコピーしたVHDファイルをマウントする
  5. チャイルド パーティションを起動する
  6. 起動したチャイルド パーティションに、Hyper-V拡張をインストールする
  7. ネットワークなどの設定を行って再起動を数回(必要な分だけ)する
  8. ハードウェア構成が変更になったようにチャイルド パーティション側では認識するので、必要であればOSのライセンス認証を行う。

まぁ、あまりハマる要素はないですよね。VHDファイルのコピー前に、かならずVirtual Serverの機能拡張(ドライバ群)をアンインストールしておくことくらいです。ちなみにこのドライバ群は、マウス/キーボードのキャプチャをサポートするドライバ、システムのハートビートをホストであるVirtual Server Serviceに返すドライバ、仮想モニタ(コンソール)をエミュレーションするドライバ、ネットワーク インターフェイスのドライバ、ゲストOSの電源ステート(ACPIステート)の管理を行うドライバなどから構成されています。おまけ的な要素が強い機能拡張ですね。抜いてしまっても、ネットワーク ドライバ部分以外は、基本的にゲストOSのサービスに決定的なダメージを与えるものではないようです。

Hyper-VからVirtual ServerへVHDを移行するには?

今度は、逆向きの移行ですね。上と同じような方法でいけるんじゃないか、と思っていたんですが、いろんな人がいろんな方法でハマっているようです(苦

いろいろ調べた結果、HALが違うからそのままじゃ動かないねん、という結論になりました。

HALって何よ

いきなりHALと言われても分からないと思いますが、Windows OSのかなり深いところで動いているハードウェアの抽象化層です(実体はDLLファイル)。もともと、Windows NTはマルチプラットフォームなOSでした。Windows NT 4.0の頃はx86だけでなく、MIPSPowerPC用のインストーラも存在していました(インストールCDがマルチブートでしたね)*1。つまり、アーキテクチャのまったく違うハードウェア(BIOSなんかも全然違う)を抽象化してしまえば、その上で動かすカーネルの骨組みは変えずに済む、という発想で作られている機能です。これは、たとえばHPの特殊なハードウェア向けであったりとか、x86のCPUであっても特殊なベンダ仕様のワークステーションであったりとか、当時はPC/AT仕様とは限らないマシンがたくさんあったので、役に立っていたようです。CPUがマルチコアか否か、によってもHALが変わっていた時期がありました(Windows Server 2003/Windows XPWhistlerコアでは共通化)。

さてこのHALですが、Hyper-Vの上で使われるものが、ちょっと特殊になっています。詳しく説明すると「ハイパーバイザ型の仮想化サービス」とは何ぞや、という長い話になるので端折りますが、ホストOSと複数のゲストOSで、マシンの物理リソースの使用にあたって競合しないように調停しあうためのインターフェイスを含んだHALになっている、というアバウトな理解をしていただければOKです。

必ず失敗する移行方法(ぁ

HALの話が長くなったので、さっそくHyper-VからVirtual ServerにVHDをコピーして動作させてみましょう。Hyper-V上で動かしているWindows OSには、ほぼ間違いなくHyper-V拡張がインストールされていると思いますので、こいつをアンインストールしてしまいましょう。*2アンインストールが完了したら、いったん該当チャイルド パーティションのOSを停止させ、エクスポートしてしまいます。エクスポート先に、いくつかフォルダが作成され、VHDファイルも作られます。

で、新規にVirtual Server上に仮想マシンを作って、エクスポートしたVHDファイルをマウントしてしまいましょう。このとき、Hyper-V上のIDEチャネルと同じチャネルにマウントしておくとトラブルが減って吉です*3。で、仮想マシンをONにしてみます。急いで仮想コンソールに移動してみましょう。

かなり残念な結果になってしまいます。仮想コンソールがブラックアウトしたままになっていますよね。CPU負荷を見てみると、NTLDRとNTDETECT.COMだけが動いてその後でフリーズしたっぽいパフォーマンス グラフになるはずです。つまり、そのままでは動かない、ということになります。

動かしてやるぜっ!

さて、前節最後で、けっこうなヒントを出しました。NTLDRとNTDETECT.COMは動いていたっぽいわけです。じゃぁ、その後に止まったとすると、HAL.DLLが怪しいな、ということになるわけです。HAL.DLLは、一般的にはACPIアーキテクチャ用のものがインストール時に選択されて、%SystemRoot%\system32ディレクトリにコピーされます。でも、Hyper-VはACPIアーキテクチャではないので、このHALイメージが選択されません。

ということは、何らかの方法でHALを入れ替えてやればいいことになりますね。HAL.DLLはカーネルがしっかりと握っているファイルなので、Hyper-Vでの稼働状態で入れ替えるのは不可能です。ということで、以下のような手順で作業します。

  1. Virtual Serverに移設したゲストOSのインストール メディア(ISOファイルか物理ディスク)をゲストOSにマウント
  2. 仮想マシンを起動
  3. 仮想コンソールで、インストール メディアからブートさせる
  4. インストールの種類を訊かれるブルーバックの画面になったら、修復インストール(R)を選択
  5. しばらく待つと修復したいOSの選択が促されるので、数字で入力する
  6. Administrator(これはドメインに参加していたOSだったとしても、ローカルのアカウントである必要がある)のパスワード入力を促されるので、注意深く入れる
  7. 制限付きのコマンド プロンプトが起動するので以下を実行する(仮想ROMドライブがゲストOSでEドライブにマッピングされているものとします)
C:\WINDOWS>cd system32
C:\WINDOWS\SYSTEM32>e:
E:\>cd i386
E:\I386>c:
C:\WINDOWS\SYSTEM32>copy e:HALACPI.DL_ c:
C:\WINDOWS\SYSTEM32>ren HALACPI.DL_ HAL.DLL
C:\WINDOWS\SYSTEM32>EXIT

すると、おそらくゲストOSが動くはずです。かなり素に近い状態で起動するので、Virtual Server用の機能拡張をインストールしたり、ハードウェア構成がガッツリ変わったように認識しているためにライセンスの再認証をしなければいけなかったり、仮想ネットワークを繋ぎ直したり、といった作業を経て、めでたくVirtual Serverへの移行は完了となります。これは、かなり乱暴な方法です。できれば、修復インストールの際に、上書きコピー前のHAL.DLLもHAL.DLL.ORGみたな名前でSYSTEM32にバックアップしておくのが良心的な方法かもしれません。

ここからはきちんと作業の中身を知っていないと気持ちが落ち着かない人向けのお話。

修復インストールのコマンドプロンプトでHAL.DLLを上書きしました。BetaNews的には、「元ファイルのHALACPI.DL_って何?」という疑問は非常に正しいわけです。このファイルは、ACPIアーキテクチャ用のHAL.DLLのマスタ ファイルなのです。Windows OSのインストーラは、拡張子の最後の文字が「_」(アンダースコア)になった元ファイルから、必要なものを選択して正規の拡張子にしてコピーするのです。OSインストーラブルーバック画面の最下行で、猛烈なスピードでファイルをコピーしているのを見たことがあると思います。アレです。

で、Virtual ServerのゲストOSでは、必ずACPIアーキテクチャのHALがデフォルトでは選択されます。でもHyper-V上のゲストOSではACPIアーキテクチャのHALが選択されません。上述の作業は、この違いを手作業で吸収してやったことになります。HAL.DLLは、あまりアップデートされるものではありませんが、サービスパックやロールアップ パッケージなどによって書き換えられることがあります。この方法でゲストOSが起動したら、必ずWindows UpdateMicrosoft Update)しておくのがよいと思います。

今はやりの仮想化ですが、Hyper-VとVirtual Serverをうまいこと行き来させて、楽に運用していければな、と思います。もしVirtual Serverへの移行でハマっているなら、この方法を試してみてください。
[[]]

*1:複数アーキテクチャ用のバイナリを詰め込んでいたからWindows NT 4.0のクセしてインストール メディアが2枚組だったんでしょうね。

*2:けっこう不安なメッセージがアンインストール中に表示されます。なにやら*.sys的なファイルの削除とかもやっていて、さらに怖い感じがしますよね。間違いなくドライバだし(爆

*3:Hyper-Vマネージャから該当チャイルド パーティションを選択して「設定」を確認するのが手っ取り早いです