まだ途中ですが、KVMで仮想マシンを組もうと思いいろいろとやってみたら・・・
ちょっといろいろと相性が出てきてしまいしばらくその相性問題を解決できるかどうかの確認作業です。
LinuxでWindowsプログラムを実行するときの方法
と言うことでありがちな題名ですが、これを考えてみたいと思います。
現段階で良くある方法としては
- WineによりWindowsプログラムをLinux内でエミュレーションを行う
- KVMを用いてLinux内にWindowsをインストールしてそれを起動させる
- VMWareなどの実績のある(ほぼ)完全仮想化をおこなう仮想マシンを使ってLinux内にWindowsをインストールする
というものがあります。
Wineは動く物は高速に動くのですが、動かない物は本当に全くと言っていいほど動かないので動いたら儲けものという感覚で。
改良度は対象のプログラムの利用率に比例するのでマイナーで動かないのであれば半分あきらめてください。
今回はKVM編です。やろうとしていることの資料が日本語でほとんど無い物ですのでせめてこのblogで紹介しようと思いました。
一応テスト環境はCentOS6.3です。リポジトリはEPELおよびRepoForge(RPMForge)を有効にしています。
KVMの実行環境を整える
まず必要な物ですが、
- 仮想化支援機能が有効になっているCPUおよびBIOS
- KVMにまつわるパッケージ群
です。CPUによっては仮想化支援がない場合があります。この場合は実行できないことがあります。
特にCeleronやPentiumを名乗っている場合はこの機能がない場合がありますので、組み立て前に見ているのでしたら調べてから購入してください。
パッケージのインストールについては以下のコマンドを発行します。
# yum groupinstall "Virtualization" "Virtualization Client" "Virtualization Platform" "Virtualization Tools"
これで必要なパッケージがインストールされます。
KVMにより仮想マシンを作成
以降はGUIで行う方が簡単です。VNCServerあたりで画面を開けるようにした上で仮想マシンを手順に従って作るのが簡単です。
が、いろいろとテストしたところどうも気になる事象が出てきたのでそれの注意です。
仮想ディスクをファイルで作成するときに場所を考えること
どうもKVMの仮想ディスクをファイルで作成すると場所によってはBuffer I/O Errorを頻発して最悪ホスト側のOS(Linux)を巻き込んで(というよりKernelPanicを起こして)落ちてしまうようなのです。
今のところテスト中なので確証はありませんが、私がテストした環境で引っかかったと思われる物にbtrfsがあるようです。
CentOSは6.3の段階ではまだbtrfsは試験実装なのもあるのかもしれませんが、どうもこのあたりで不安定になるようなので気をつけてください。
ext4なら大丈夫か?と言われるとそれも確証が持てないのでとりあえずext4に変更した上で領域を切り出して別パーティションを確保するのがわかりやすいかもしれません。
仮想マシンのネットワークをNATで動かして、かつゲスト側のポートを開く動作について
ほとんどのページでゲスト側のポートを開く動作を行う必要性(つまり、ゲストOSにサーバー動作をさせる)時には必ずと言っていいほど「ネットワークをブリッジにする」という項目が書かれています。
ブリッジ動作にするとネットワークの接続速度が向上する代わりにホスト側のサーバー動作が微妙になるような「気がする」ので避けていたわけです。
おかげでKVM+NAT+ポート開放に関する資料がほとんど無くて探すのに苦労しました。
方法としては以下の手順を踏みます。
1. 仮想マシンの起動時にPortRedirectの引数を与える
シェルから起動させるのであれば“-redir”の引数を用いてポート変換を行うことが出来ます。
引数の形式は“-redir [プロトコル]:[ホスト側待ち受けポート]:[ゲスト側IP]:[ゲスト側ポート]”となり、通常はQEMUでの起動時に
-redir tcp:8022::22
のように指定します。が、GUI経由で起動させると仮想マシンの設定はXMLを参照するのでその指示をどこから与えるかが分かりづらいのですが、このようにします。
対象の仮想マシンの設定用XMLファイル(/etc/libvirt/qemu/[仮想マシン名].xml)は初めこのようになっていると思います。
<domain type='kvm'> ・・・ </devices> </domain>
これをこのように変更します。
<domain type='kvm' xmlns:qemu='http://libvirt.org/schemas/domain/qemu/1.0'> ・・・ </devices> <qemu:commandline> <qemu:arg value='-redir'/> <qemu:arg value='tcp:8022::22'/> </qemu:commandline> </domain>
qemu:commandlineタグ内で追加する引数を宣言していくわけですね。qemu:arg以外にも環境変数の設定としてqemu:envという設定も出来ますが今は必要ないですので。
また、qemu:commandlineタグを有効にするためにxmlnsによりスキーマを認識させる必要があります。
変更時には本来virshにより行う必要がありますが、面倒であれば直接エディタから書き換えてもどうせこの後再読込をすることになるのであまり問題はなかったりします。
2.libvirtdの起動時のiptables指示を変更する
KVMによる仮想マシンのネットワークをNATで行っているときは仮想マシンを管理するlibvirtdが起動すると同時にiptablesにゲスト側が通信を行うための必要なネットワーク処理のルールが設定されます。
(なお、そのためlibvirtdが起動している最中にiptablesをrestartすると設定されているNATが消えてしまうので仮想マシンは通信が出来なくなってしまいます)
そのため、このlibvirtdの起動時にiptablesに対してゲスト側のポート開放を同時に設定する必要があります。
これを行うために/etc/libvirt/hooks/qemuと言うファイル名でスクリプトを作成します。通常hooksディレクトリは存在しませんので作成してください。
スクリプトは以下のようになります。
#!/bin/sh GuestName=hoge GuestIPAddr=192.168.122.2 HostPort=8022 GuestPort=22 if [ "" = "${GuestName}" ]; then if [ "" = "stopped" -o "" = "reconnect" ]; then iptables -t nat -D PREROUTING -p tcp --dport ${HostPort} -j DNAT --to ${GuestIPAddr}:${GuestPort} iptables -D FORWARD -d ${GuestIPAddr} -p tcp -m state --state NEW --dport ${GuestPort} -j ACCEPT fi if [ "" = "start" -o "" = "reconnect" ]; then iptables -t nat -A PREROUTING -p tcp --dport ${HostPort} -j DNAT --to ${GuestIPAddr}:${GuestPort} iptables -I FORWARD -d ${GuestIPAddr} -p tcp -m state --state NEW --dport ${GuestPort} -j ACCEPT fi fi
初期の設定(GuestNameおよびGuestIPAddr)は必要な状態に変更してください。また、複数のポートを開く必要があるときはiptablesの指示を複数書けばその通りになります。
スクリプトを作成した後は
# chmod +x /etc/libvirt/hooks/qemu
で実行権を与えればOKです。あとはlibvirtdの再起動を行えば上二つの設定は確定できます。
3.ip_forwardを行う
必要かどうかは確定できませんがあるべきですね。
# sysctl -w net.ipv4.ip_forward=1
4.ゲスト側で待ち受けを行う
ゲスト側内部にあるファイアウォールを通過出来るように設定してやっとこの設定が完了します。
正しくポートが開放されたかを確認してようやくですね。
多重VNCによるキーマップの問題について
ホストOSのVNC上からゲストOS(Windows)を動かしてさらにキーを入力するとキー入力が正しく行われないことがあります。
私が確認した現象は「一部の記号の入力が正しく行われない」というものでした。
解決する方法としては
- ホストOSのキーマップを正しく認識させる([setxkbmap -model jp106 -layout jp]など)
- ゲストOSに直接VNC(この場合はRDP)でログインする
というものです。後者の方法についてはNATによる問題は解決しているはずなのでRDPによる直接ログインは可能になっているはずです。
それを利用するもので、この段階ではこちらの方がわかりやすいような気もします。二重にVNCを使うのもやっかいだと思います。
特に
Windows-(VNC)-ホストOS(Linux)-(VNC)-ゲストOS(Windows)
と言う組み合わせだと、ゲストOSに半角/全角のコードを送るのが一苦労になると言うも大変ですので。
KVMにはちゃんとドライバを当てよう
もちろん、仮想マシンなので、ちゃんと対象のOSにあったドライバを当てる必要があります。
ドライバを当てないと特にディスク処理関連とネットワークの速度関係にかなり影響があります。
Virtioのドライバをさがしてインストールした後にKVMのデバイス接続設定をVirtioに変更することでパフォーマンスが大幅にアップします。
これくらいはやっていますよね・・・?
これで使えるようになったかな?
あとは安定性の問題ですね。特に仮想ディスクへのアクセス(と思われる原因)でKernelPanicを起こした、と言う現象が未だに引っかかっています。
これを解決しないと常にKernelPanicとの戦いになってしまうので出来る限り取り除かないと問題だと思います。
仮想ディスクから物理パーティションへの変更によってこれが取り除かれるのであればとりあえずよしとします。
企業向けならこんな方法で片付けるべきではないのですが、個人で使っている物なのでこういう解決法もありだと思います。