このページの目次

Jun Mizutani 2010/01/09

Ubuntu 9.10(Karmic Koala) で KVM

新しい記事があります。Ubuntu 16.04 LTS の KVM で仮想サーバ (2016/05/06, 2017/08/10 リンク先修正)


Ubuntu 9.10(Karmic Koala) のサーバ版 ( ubuntu-9.10-server-amd64 ) をホストとゲストともに使って、KVMによる仮想マシン環境を構築してみます。Linuxをインストールしたマシン(ホスト)上にソフトウェアで複数の仮想マシン(ゲスト)を作成し、それら仮想マシンにもLinuxをインストールすることで、一台のマシンを複数のマシンに見せかけます。一台のコンピュータのハードウェア全体をソフトウェアで実現(完全仮想化)します。


Ubuntuでは仮想マシン環境を制御するために Virtual Machine Manager(GUI) と virsh (CLI) が用意されていて、それらがlibvirtを使うことで各種の仮想マシン環境(Xen、KVM、OpenVZ、User Mode Linuxなど)の制御を抽象化しています。このページでは KVM の使い方を理解するため、 libvirt を使わずコマンドラインから直接 kvmコマンドを使って仮想マシンをコントロールすることにします。


Ubuntuはインストールにグラフィック画面を使います。Ubuntuのサーバ版はXがインストールされないため、ホスト上でUbuntuをインストールできません。Xをインストールすることは可能ですが、サーバとして運用するにはリソースの無駄になります。そこでqemu-kvmをvncサーバとして起動し、WindowsにUltraVNC(VNCビューアのみ)をインストールして、画面をWindowsに転送することで、Ubuntuをインストールしました。


KVM と QEMU

仮想化には比較的新しい KVM を使用しました。仮想環境としての Linux KVM (Kernel-based Virtual Machine) は QEMU という5年ほど前から利用されている比較的古い仮想マシンエミュレータが重要な部分を占めます。


QEMU 自身は色々なCPUを実行できるエミュレータで、CPU命令をソフトウェアでいちいち解釈実行する方法ではなく、動的にコンパイルするような方法を使ってかなり速いエミュレータとして有名でした。PCのハードウェア全体がソフトウェアで実現されていて、昔からOSの開発でも利用されていました。


Linuxカーネルのモジュールとしての KVM はintelVTやAMD-Dという機能を持つ最近のCPU(Core2Duo等)を使って、仮想環境のOSの特権命令まで直接実行する仕組みです。CPUの仮想化支援機能(intelVTまたはAMD-V)にアクセスするためのインタフェース(/dev/kvm)を提供しています。カーネルモード、ユーザモードに加えて、ゲストモードという新しい動作モードが追加されます。CPUで仮想環境の命令を直接実行してしまうので、仮想環境といえども速度の低下は全くありません。ただし、ハードディスクやネットワークカードなどの周辺機器(IO)へのアクセスはトラップされて物理的なデバイスとのインターフェイスがソフトウェアで行われるため、速度は多少遅くなります。


仮想環境としての Linux KVMはこのCPU以外の周辺機器の仮想化を、昔から使われていて安定なQEMUを使うことでPC全体を仮想化(完全仮想化)しています。したがってKVMは仮想環境として、非常に新しい部分(CPUの持つ仮想マシンモニター機能)をシンプルな仕組みでカーネル内に持ち、古い部分(QEMUによるハードウェアエミュレーション)をユーザプロセス側で受け持つ形式でうまく融合したものとなっています。KVM は2007年2月以降のLinuxのカーネル(2.6.20以降)のソースにモジュール(バイナリになると250KB程度とコンパクト)として取り込まれています。GUIが必須ではないのでホスト側のリソース(メモリ、CPU負荷)が無駄にならないため、サーバとして利用するにはよい環境ではないかと思います。

仮想環境の構成

外部のネットワークから見た場合、ホスト1台とゲスト2台の合計3台のサーバが独立して稼働しているような構成とします。 物理的にIPアドレスを別々に持つ3台のサーバがスイッチングハブで接続されているのと同じ状態になります。この例ではゲストOSが2つですが、必要ならばいくつでも増やすことができます。


外部からは以下のように見えることを目指します。ゲストは同様にいくつでも増やせます。

  +------+     +-----------------------------------+
  | GW   +-----+         Switching HUB             |
  +------+     +----+-------------+-------------+--+
 172.18.21.1        |             |             |
               +----+-----+   +---+-----+   +---+-----+
               |   HOST   |   | GUEST   |   | GUEST   |
               +----------+   +---------+   +---------+
               172.18.21.80   172.18.21.90  172.18.21.91

ホストとしての64ビット Ubuntu 9.10 サーバ版のインストール

仮想環境の入れ物(ホストOS)として 64ビット Ubuntuサーバ版(ubuntu-9.10-desktop-amd64.iso) をインストールします。ゲストOSに64ビットを使う場合は64ビット版が必要です。仮想環境のホストとする場合はメモリを豊富に積んでおく必要があるので、あえて32ビット版のUbuntuをインストールする理由は思いつきません。KVMを使うため、BIOSの設定で intelVT または AMD-V を有効にしておきます。実際のインストールは下のゲストのインストールとほぼ同じです。ホストのディスクのパーティションの構成は環境によって異なり、「Manual」を使うことになると思いますから割愛します。

ゲストのインストール準備

Ubuntuはインストールにグラフィック画面が表示されますが、標準ではUbuntuのサーバ版はグラフィック画面を表示できません。仮想マシンのqemu-kvmをvncサーバとして起動し、Windows に UltraVNC ( https://www.uvnc.com/)からUltraVNC_1.0.8.2_Setup.exe [1825KB] をダウンロードしてVNCビューアをインストールすることで、グラフィック画面をWindowsで操作することが可能となります。ついでにLinuxをインストールするスクリーンショットも取得できます。

UltraVNCのインストール

uvnc01.png


ライセンス(GPL v2)の確認を求められます。Ubuntuと同じライセンス(Ubuntuのすべてが同じではないですが)なのでUltraVNCを使用するだけなら特に問題にならないと思います。建前としては「ちゃんと読んで同意できる場合だけ使ってください」ですが...

uvnc02.png


インストールするバージョンに関する情報が表示されます。

uvnc03.png


インストールするフォルダの確認です。変更する必要はないでしょう。

uvnc04.png


インストールするプログラムの選択です。今回はVNCのサーバは不要なので「Ultra VNC Viewer」を選択しました。

uvnc05.png


スタートメニューのフォルダ名を指定します。デフォルトのままで問題ありません。

uvnc06.png


デスクトップに起動用のアイコンを作成するように指定しました。

uvnc07.png


指定した内容の確認画面です。

uvnc08.png


ライセンスなどの再確認です。

uvnc09.png


インストールが終了すると表示されます。[Finish]で終了します。

uvnc10.png


UltraVNCの使い方

UltraVNC Viewerを起動して、VNCサーバにホストのIPアドレスとポート番号を指定します。ポート番号は kvm の起動時にVNCサーバとして指定したオプションの番号に5900を加えた値を指定します。「 -vnc :0」の場合は5900になります。[Connect]ボタンを押せば仮想マシンの画面が表示されます。

uvnc11.png


仮想ディスクイメージの作成

仮想マシンのハードディスクは仮想ディスクイメージというファイルとして準備する必要があります。仮想ディスクイメージは「qemu-img」コマンドを使って作成します。次の例は 4GB のディスクイメージを qcow2 フォーマットを使って、u91064s.qcow2 というファイル名で作成します。

jun@Host:~$ qemu-img create -f qcow2 u91064s.qcow2 4GB
Formatting 'u91064s.qcow2', fmt=qcow2 size=4294967296 encryption=off cluster_size=0

qcow2 フォーマットは、使っている部分だけがファイルに記録されます。したがって実際に作成されるイメージは 4GB ではなく、次のように260KBのイメージとなります。仮想ディスクに書き込むと徐々に大きくなり、ディスクイメージの作成時に指定したサイズまで大きくなります。

jun@Host:~$ ls -l
total 140
-rw-r--r-- 1 jun jun 262144 2009-12-27 23:21 u91064s.qcow2

ゲストOSとして64ビット Ubuntu 9.10 サーバ版のインストール

ホストのCD-ROMドライブに ubuntu910-server-amd64 の CD-ROM をセットして仮想マシンを起動してインストールを開始します。仮想ディスクイメージは上で作成したファイルを指定します。「-cdrom /dev/cdrom」は CD-ROM としてホストのドライブを使う指定です。「-boot d」は起動ドライブをCD-ROMとする指定です。

sudo kvm -hda u91064s.qcow2 -cdrom /dev/cdrom -boot d -m 512 -vnc :0

VNCビューアでIPアドレスをホストマシンのIPアドレス、ポートを5900として接続するとゲストマシンの起動画面が表示されます。最初にインストールに使用する言語の指定です。ここではデフォルトのEnglishのままでいきます。

u910s01.png


Ubuntuを仮想ハードディスクにインストールするため、「Install Ubuntu Server」を選択します。

u910s02.png


使う言語の指定です。サーバとして利用するのでコンソールが日本語を表示できない場合を考えてEnglishにしました。

u910s03.png


国の指定です。日本を指定する場合は other / Asia / Japan とたどります。

u910s04.png


u910s05.png


u910s06.png


キーボードのレイアウトの指定です。日本語のキーボードは検出されないので、ここでは <No> を選択します。

u910s07.png


Japanを選択します。

u910s08.png


普通は「Japan - OADG 109A」です。

u910s09.png


ホストの名前を設定します。適当に名前を決めてください。/etc/hostname と /etc/hosts というテキストファイルの内容を書き換えれば後から変更できます。

u910s10.png


Ubuntuをインストールするハードディスクの構成を選択します。仮想マシンの仮想ディスクイメージにインストールする場合は「use entire disk」としてディスク全体を使ってインストールしても問題ありません。

u910s11.png


表示されたハードディスクが消去されるという警告です。間違いがなければエンターキーで次に進みます。

u910s12.png


フォーマットされるパーティションの情報が表示されます。

u910s13.png


ユーザの名前を入力します。

u910s14.png


アカウントに使うユーザ名を入力します。

u910s15.png


パスワードを入力します。

u910s16.png


確認のため、もう一度パスワードを入力します。

u910s17.png


ホームディレクトリを暗号化する場合は <Yes> を選択します。普通は <No> で問題ありません。

u910s18.png


インターネットへの接続がプロキシサーバを経由する場合はここで設定します。認証が必要な場合もユーザ名、パスワードをここで設定します。自宅で使う場合は何も設定しなくても大丈夫です。ここで設定しない場合でも、あとから以下の内容のテキストファイルを /etc/apt/apt.conf として置けば同じです。

Acquire::https::Proxy "https://ユーザ名:パスワード@プロキシIPアドレス:ポート番号";

u910s19.png


システムのアップデートを自動で行うかどうかを指定します。

u910s20.png


サーバをどういった目的で使うかが決まっていれば、ここでインストールするソフトウェアを指定できます。下の例は「データベースとしてPostgreSQLを使って、PHPでプログラムを作成、ApacheでWebサーバを動作させる。SSHで接続する。Windows機とファイルのやり取りもしたい。」といった場合の選択です。「LAMP Server」を選択すると MySQL もインストールされますが、不要ならば後から「apt-get remove mysql-common」を実行します。

u910s21.png


仮想環境を入れるためのホストの場合は、ほとんど何も設定しなくても大丈夫です。仮想環境用にKVMを入れる場合も「sudo apt-get install qemu-kvm」するだけなので、ここで「Virtual Machine Host」を選択することはないと思います。選択するとlibvirt-bin、libxen3 等もインストールされますが、Xenを使わないなら不要です。

u910s21h.png


LAMPサーバを選択した場合はMySQLの管理者用のパスワードが求められます。

u910s22.png


MySQLの管理者用のパスワードの再確認です。

u910s23.png


インストールの終了です。

u910s24.png


ディスクイメージのサイズを確認します。

jun@Host:~$ ls -lt
-rw-r--r-- 1 jun jun 1315045376 2009-12-28 00:22 u91064s.qcow2

仮想ハードディスクからゲストOSの起動

仮想環境の場合は自動的に再起動されないので、「kvm -hda ディスクイメージ -boot c」として仮想ディスクイメージから起動します。ゲスト用のメモリは512MB(-m 512)、ゲストの出力は vnc の場合のコマンドです。vncでなく起動したコンソール(-curses)にゲストの出力を表示することもできます。

sudo kvm -hda u91064s.qcow2 -boot c -m 512 -vnc :0

u910s30.png


ネットワークカードの設定(-net)を省略するとホストがdhcpサーバ兼ルータとして働き、ゲストのIPアドレスは以下の例のように 10.0.2.15 といったIPアドレスが自動的に設定されます。

u910s31.png


ここでは起動の確認だけにします。各種の設定は後述します。

ホスト側のネットワークの設定

物理的には1台のマシンをネットワーク的には独立した3台のサーバがスイッチングハブで接続されている状態に設定します。

  +------+     +-----------------------------------+
  | GW   +-----+         Switching HUB             |
  +------+     +----+-------------+-------------+--+
 172.18.21.1        |             |             |
               +----+-----+   +---+-----+   +---+-----+
               |   HOST   |   | GUEST0  |   | GUEST1  |
               +----------+   +---------+   +---------+
               172.18.21.80   172.18.21.90  172.18.21.91

ホストとなるマシンのネットワークカード(eth0)の内側にブリッジ(br0)があり、仮想マシンはtap デバイスを介してブリッジに接続します。

            +-----------------------------------------+
            |     Host : Ubuntu 9.10 amd64 sever      |
            |                                         |
        +---+----+         +---------------+          |
        | eth0   +---------+ Switching HUB |          |
        +---+----+         |     br0       |          |
            |              +-+----------+--+          |
            |                |          |             |
            |         +------+-+      +-+------+      |
            |         | tap0   |      | tap1   |      |
            |         +---+----+      +---+----+      |
            |             |               |           |
            |         +---+----+      +---+----+      |
            |         |  KVM   |      |  KVM   |      |
            |         |  QEMU  |      |  QEMU  |      |
            |         +--------+      +--------+      |
            |         | Guest0 |      | Guest1 |      |
            |         | LINUX  |      | LINUX  |      |
            |         +--------+      +--------+      |
            +-----------------------------------------+

ブリッジの生成

最初にホストのネットワークカード(NIC)を自分宛のEthernetフレーム以外も受け付けるプロミスキャスモード(promiscuous mode)に変更します。プロミスキャスモードにすることでEthernetフレームの宛先MACアドレスが自分と異なる場合でも読み込むことができるため、ブリッジとして動作できるようになります。

次にホスト内にブリッジを生成して、eth0をブリッジに繋ぎかえます。ブリッジとは Ethernet Bridge のことで、物理的には普通のスイッチングハブ(レイヤー2スイッチ)と考えることができます。 qemu-kvm をインストールすると自動的にインストールされる bridge-utils パッケージのコマンド 「brctl addbr ブリッジ名」で生成できます。

ブリッジを生成して、eth0を繋ぎかえる時にネットワークは一旦切断されるため、シェルスクリプトにしておけばリモートからでも連続してコマンドを実行できます。ブリッジにIPアドレスを設定するとホストも外部ネットワークに接続できます。ネットワークは一旦切断されるため、リモートからSSHで接続している場合は再接続する必要があります。

次に示す「bridge.sh」で上記の設定を一気に行います。最初にあるシェル変数のIPとGATEWAYの値は環境にあわせて変更してください。「sudo sh bridge.sh」で実行できます。 ホストの起動時に自動的にブリッジを生成する方法は後述します。

jun@Host:~$ cat bridge.sh
#!/bin/sh

IP=172.18.21.80                          # ホストのIPアドレス
GATEWAY=172.18.21.1                      # ルータのLAN側IPアドレス

echo "change IP address : $IP"
ifconfig eth0 0.0.0.0 promisc up         # プロミスキャスモードに設定
brctl addbr br0                          # ブリッジの作成
brctl addif br0 eth0                     # ブリッジにeth0を接続
ifconfig br0 up                          # ブリッジを起動
ifconfig br0 $IP netmask 255.255.255.0   # ブリッジにIP設定
route add default gw $GATEWAY            # ゲートウェイ設定

実行すると ifconfig の出力は以下のようになります。ブリッジのbr0にIPアドレスが設定され、eth0 はプロミスキャスモード(PROMISC)になっていることが確認できます。

jun@Host:~$ ifconfig
br0       Link encap:Ethernet  HWaddr 00:1d:60:6d:ae:b4
          inet addr:172.18.21.80  Bcast:172.18.21.255  Mask:255.255.255.0
          inet6 addr: fe80::21d:60ff:fe6d:aeb4/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:85 errors:0 dropped:0 overruns:0 frame:0
          TX packets:58 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:8515 (8.5 KB)  TX bytes:6822 (6.8 KB)

eth0      Link encap:Ethernet  HWaddr 00:1d:60:6d:ae:b4
          inet6 addr: fe80::21d:60ff:fe6d:aeb4/64 Scope:Link
          UP BROADCAST RUNNING PROMISC MULTICAST  MTU:1500  Metric:1
          RX packets:1618 errors:0 dropped:0 overruns:0 frame:0
          TX packets:1260 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:220688 (220.6 KB)  TX bytes:340693 (340.6 KB)
          Interrupt:17

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:16436  Metric:1
          RX packets:144 errors:0 dropped:0 overruns:0 frame:0
          TX packets:144 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:23876 (23.8 KB)  TX bytes:23876 (23.8 KB)

ホストの起動時に自動的にブリッジを生成するには /etc/network/interfaces を以下のように変更します。

# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).

# The loopback network interface
auto lo
iface lo inet loopback

# The primary network interface
#auto eth0
#iface eth0 inet dhcp

auto br0
iface br0 inet static
  address 172.18.21.80
  netmask 255.255.255.0
  network 172.18.21.0
  broadcast 172.18.21.255
  gateway 172.18.21.1
  pre-up ifconfig eth0 down
  pre-up ifconfig eth0 0.0.0.0 promisc up
  pre-up brctl addbr br0
  pre-up brctl addif br0 eth0
  pre-up ifconfig eth0 up
  post-down ifconfig eth0 down
  post-down brctl delif br0 eth0

ホストを起動するとブリッジが有効になっていることが「ifconfig」で確認できます。

ゲストOSの起動と設定

ゲストOSを起動して、ホスト内に作成したブリッジに接続する場合は、kvm コマンドにネットワークに関するオプション(-net)を2つ指定します。「-net nic」と「-net tap,ifname=tap0,script=/etc/qemu-ifup」です。

sudo kvm -m 512 -boot c -curses -hda u91064s.qcow2 \
    -net tap,ifname=tap0,script=/etc/qemu-ifup

/etc/qemu-ifup は kvmのオプション(-net tap,ifname=)で指定した tap デバイスとブリッジを接続する以下のようなコマンドを実行します。

/sbin/ifconfig tap0 0.0.0.0 up
/usr/sbin/brctl addif br0 tap0

qemu-ifupは引数からtapデバイス名を受け取り、ブリッジ名をip routeから取得するスクリプトになっているため、上記のコマンドが直接書いてあるわけではありません。


次のコマンドは、qcow2形式のディスクイメージ u91064s.qcow2 をhdaに接続、そのハードディスクから起動(-boot c)します。ゲスト用のメモリは 512Mバイト(-m 512)、ゲストの出力は起動したコンソール(-curses)、ネットワークカードのMACアドレスを指定(-net nic,macaddr=52:54:00:12:34:56)、TAPアダプタに接続(-net tap,ifname=tap0)します。TAPアダプタとはLinuxのプロセスからネットワークデバイスとして読み書きできる仮想デバイスです。

sudo kvm -m 512 -boot c -curses \
  -drive file=u91064s.qcow2,if=virtio,boot=on \
  -net nic,model=virtio -net tap,ifname=tap0,script=/etc/qemu-ifup

ゲスト側のIPアドレスはスクリプトで固定IPを設定しています。ネットワークカードのデバイス名がeth0とは限らないため、「ifconfig -a」から取得しています。

#!/bin/sh

IP=172.18.21.90
NIC=`/sbin/ifconfig -a| awk '$1 ~ /^eth/ {print $1}'`

echo $NIC
echo $IP
ifconfig $NIC $IP netmask 255.255.255.0
route add default gw 172.18.21.1

Virtio による準仮想化

ゲストOS上で動作する準仮想化ドライバ(Paravirtualized driver)を使ってネットワークとブロックデバイスのアクセスを高速化できます。virtioドライバはUbuntuのカーネルに用意されているため、特に何も用意する必要はありません。KVMの起動時に指定するだけです。ネットワークには「model=virtio」、ディスクには「if=virtio」を次のように追加します。ドライブの指定には「-hda」ではなく、「-drive」を使います。

kvm -m 512 -boot c -curses \
  -drive file=u91064s.qcow2,if=virtio,boot=on \
  -net nic,model=virtio -net tap,ifname=tap0,script=/etc/qemu-ifup

速度の比較

1000baseT(1Gbps)で接続されたLAN内の無印玄箱(100Mbps)のWebページから400MBのファイルをダウンロードしてホストとゲストの速度を比較します。

ホスト

2.66GHzのCore2Duo(E6750)、メモリ6GBでUbuntu9.10-server-amd64上で直接ダウンロードします。ダウンロードしたファイルを伸張する時間も測定しました。

jun@Host:~/tmp$ time wget https://172.18.21.69/u91064s.qcow2.tgz
--2009-12-31 01:16:55--  https://172.18.21.69/u91064s.qcow2.tgz
Connecting to 172.18.21.69:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 406601328 (388M) [application/x-gzip]
Saving to: `u91064s.qcow2.tgz'

100%[======================================>] 406,601,328 9.39M/s   in 41s

2009-12-31 01:17:37 (9.39 MB/s) - `u91064s.qcow2.tgz' saved [406601328/406601328]


real    0m41.352s
user    0m0.400s
sys     0m3.240s

jun@Host:~/tmp$ time tar zxf u91064s.qcow2.tgz

real    0m23.582s
user    0m9.890s
sys     0m3.140s

ダウンロードしたファイルと伸張したファイルのサイズです。

jun@Guest0:~$ ls -l
-rw-r--r-- 1 jun jun 1315045376 2009-12-28 00:22 u91064s.qcow2
-rw-r--r-- 1 jun jun  406601328 2009-12-28 00:37 u91064s.qcow2.tgz

玄箱HG(1Gbps)からもダウンロード

jun@Host:~/tmp$ time wget https://172.18.21.70/u91064s.qcow2.tgz
--2009-12-31 02:16:11--  https://172.18.21.70/u91064s.qcow2.tgz
Connecting to 172.18.21.70:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 406601328 (388M) [application/x-gzip]
Saving to: `u91064s.qcow2.tgz.1'

100%[======================================>] 406,601,328 13.8M/s   in 28s

2009-12-31 02:16:39 (13.9 MB/s) - `u91064s.qcow2.tgz.1' saved [406601328/406601328]


real    0m27.982s
user    0m0.310s
sys     0m2.600s

ゲスト

ゲストOSでの評価は仮想ディスクイメージをコピーして、全く同じ状態で評価しています。コピーしているため、ホストのドライブ上のディスクイメージの状態は全く同じではありません。

sudo kvm -m 512 -boot c -curses -hda u91064s.qcow2 \
     -net nic -net tap,ifname=tap0,script=/etc/qemu-ifup

カーネルモジュールを表示すると、QEMUが用意している Realtek RTL8139 というネットワークカードのエミュレーションを使っていることがわかります。

jun@Guest0:~$ lsmod
Module                  Size  Used by
iptable_filter          3872  0
ip_tables              21168  1 iptable_filter
x_tables               25768  1 ip_tables
ppdev                   8232  0
virtio_balloon          5412  0
parport_pc             37352  1
lp                     11908  0
psmouse                57124  0
serio_raw               6596  0
parport                40528  3 ppdev,parport_pc,lp
i2c_piix4              11728  0
floppy                 65192  0
8139too                27360  0
virtio_pci              9160  0
virtio_ring             5344  1 virtio_pci
virtio                  5956  2 virtio_balloon,virtio_pci
8139cp                 23200  0
mii                     6368  2 8139too,8139cp

QEMUのモニターでも Realtek RTL8139 が使われていることが確認できます。

QEMU 0.11.0 monitor - type 'help' for more information
(qemu) info network
VLAN 0 devices:
  tap.0: ifname=tap0,script=/etc/qemu-ifup,downscript=/etc/qemu-ifdown
  rtl8139.0: model=rtl8139,macaddr=52:54:00:12:34:56
(qemu) info block
ide0-hd0: type=hd removable=0 file=u91064s.qcow2 ro=0 drv=qcow2 encrypted=0
ide1-cd0: type=cdrom removable=1 locked=0 [not inserted]
floppy0: type=floppy removable=1 locked=0 [not inserted]
sd0: type=floppy removable=1 locked=0 [not inserted]
(qemu) c

400MBのファイルを玄箱においてHTTPでダウンロードしました。ダウンロードしたファイルを伸張する時間も測定しました。

jun@Guest0:~$ time wget https://172.18.21.69/u91064s.qcow2.tgz
--2009-12-31 01:02:13--  https://172.18.21.69/u91064s.qcow2.tgz
Connecting to 172.18.21.69:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 406601328 (388M) [application/x-gzip]
Saving to: `u91064s.qcow2.tgz'

100%[======================================>] 406,601,328 9.17M/s   in 42s

2009-12-31 01:02:55 (9.26 MB/s) - `u91064s.qcow2.tgz' saved [406601328/406601328]


real    0m41.912s
user    0m0.360s
sys     0m17.500s

jun@Guest0:~$ time tar zxf u91064s.qcow2.tgz

real    0m38.769s
user    0m10.830s
sys     0m3.020s

玄箱HGでも測定

jun@Guest0:~$ time wget https://172.18.21.70/u91064s.qcow2.tgz
--2009-12-31 02:13:54--  https://172.18.21.70/u91064s.qcow2.tgz
Connecting to 172.18.21.70:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 406601328 (388M) [application/x-gzip]
Saving to: `u91064s.qcow2.tgz'

100%[======================================>] 406,601,328 14.6M/s   in 27s

2009-12-31 02:14:20 (14.6 MB/s) - `u91064s.qcow2.tgz' saved [406601328/406601328]


real    0m26.623s
user    0m0.220s
sys     0m14.710s

ゲスト virtio

ネットワークとブロックデバイスにvirtioを使って準仮想化します。

sudo kvm -m 512 -boot c -curses \
    -drive file=u91064s.qcow2,if=virtio,boot=on \
    -net nic,model=virtio -net tap,ifname=tap0,script=/etc/qemu-ifup

カーネルモジュールを表示すると、Realtek RTL8139 用のモジュールがロードされていません。そのかわり virtio_net が使われています。

jun@Guest0:~$ lsmod
Module                  Size  Used by
iptable_filter          3872  0
ip_tables              21168  1 iptable_filter
x_tables               25768  1 ip_tables
ppdev                   8232  0
virtio_balloon          5412  0
parport_pc             37352  1
psmouse                57124  0
serio_raw               6596  0
lp                     11908  0
i2c_piix4              11728  0
parport                40528  3 ppdev,parport_pc,lp
virtio_blk              7816  3
virtio_net             16896  0
floppy                 65192  0
virtio_pci              9160  0
virtio_ring             5344  1 virtio_pci
virtio                  5956  4 virtio_balloon,virtio_blk,virtio_net,virtio_pci

QEMUのモニターでも virtio が使われていることが確認できます。

QEMU 0.11.0 monitor - type 'help' for more information
(qemu) info network
VLAN 0 devices:
  tap.0: ifname=tap0,script=/etc/qemu-ifup,downscript=/etc/qemu-ifdown
  virtio.0: model=virtio,macaddr=52:54:00:12:34:56
(qemu) info block
virtio0: type=hd removable=0 file=u91064s.qcow2 ro=0 drv=qcow2 encrypted=0
ide1-cd0: type=cdrom removable=1 locked=0 [not inserted]
floppy0: type=floppy removable=1 locked=0 [not inserted]
sd0: type=floppy removable=1 locked=0 [not inserted]

400MBのファイルを玄箱においてHTTPでダウンロードしました。

jun@Guest0:~$ time wget https://172.18.21.69/u91064s.qcow2.tgz
--2009-12-31 01:10:42--  https://172.18.21.69/u91064s.qcow2.tgz
Connecting to 172.18.21.69:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 406601328 (388M) [application/x-gzip]
Saving to: `u91064s.qcow2.tgz'

100%[======================================>] 406,601,328 9.53M/s   in 47s

2009-12-31 01:11:29 (8.26 MB/s) - `u91064s.qcow2.tgz' saved [406601328/406601328]


real    0m47.004s
user    0m0.620s
sys     0m5.080s

jun@Guest0:~$ time tar zxf u91064s.qcow2.tgz

real    0m48.037s
user    0m12.110s
sys     0m4.880s

玄箱HGでも測定

jun@Guest0:~$ time wget https://172.18.21.70/u91064s.qcow2.tgz
--2009-12-31 02:19:39--  https://172.18.21.70/u91064s.qcow2.tgz
Connecting to 172.18.21.70:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 406601328 (388M) [application/x-gzip]
Saving to: `u91064s.qcow2.tgz'

100%[======================================>] 406,601,328 13.0M/s   in 30s

2009-12-31 02:20:09 (13.0 MB/s) - `u91064s.qcow2.tgz' saved [406601328/406601328]


real    0m29.820s
user    0m0.360s
sys     0m5.510s

結果

100Mbps程度の転送ではホストとゲストに大した差は出ません。virtioを使用するとゲストのシステムの負荷はかなり小さくなることが分かります。

複数のゲストOSを使う

ゲストOSを複数起動するためには、ゲストのディスクイメージを別々に用意して起動します。1つのディスクイメージを複数の仮想マシンで共有することはできません。同じ環境のゲストを使う場合でもイメージをコピーする必要があります。今回はサーバとして使用するのでゲストごとにホスト名、ネットワーク設定が必要となります。

1番目のゲストをゲスト0、2番目のゲストをゲスト1とします。/etc/hostname もそれぞれ Guest0、Guest1としました。

ゲスト0の起動

ゲストを起動するためのKVMコマンドのオプションはMACアドレス(macaddr=52:54:00:12:34:00)とTAPデバイスの名称の指定(ifname=tap0)を行います。

sudo kvm -m 512 -boot c -curses \
    -drive file=u91064s.qcow2,if=virtio,boot=on \
    -net nic,macaddr=52:54:00:12:34:00,model=virtio \
    -net tap,ifname=tap0,script=/etc/qemu-ifup

ネットワークの設定

ゲストのネットワークを設定するシェルスクリプトを用意しました。ここでは固定IPを起動後に設定します。ネットワークカードのデバイス名がeth0とは限らないため、「ifconfig -a」から取得しています。ゲストのIPアドレスとルータのIPアドレスの下位バイトを最初に書き込んでおくことにしています。

#!/bin/sh

IP=172.18.21.90
GW=.1
#GW=.254

IP24=`expr $IP : "\(.*\)\.[0-9]"`
NIC=`/sbin/ifconfig -a| awk '$1 ~ /^eth/ {print $1}'`

echo $NIC
echo "ip address :" $IP
echo "broadcast  :" $IP24.255
echo "gateway    :" $IP24$GW
ifconfig $NIC $IP netmask 255.255.255.0 broadcast $IP24.255
route add default gw $IP24$GW
root@Guest0~# ifconfig -a
eth1      Link encap:Ethernet  HWaddr 52:54:00:12:34:00
          inet addr:172.18.21.90  Bcast:172.18.21.255  Mask:255.255.255.0
          inet6 addr: fe80::5054:ff:fe12:3400/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:46 errors:0 dropped:0 overruns:0 frame:0
          TX packets:28 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:13303 (13.3 KB)  TX bytes:3005 (3.0 KB)

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:16436  Metric:1
          RX packets:52 errors:0 dropped:0 overruns:0 frame:0
          TX packets:52 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:17113 (17.1 KB)  TX bytes:17113 (17.1 KB)

ゲスト1の起動

ゲスト1を起動するにはゲスト0と異なる仮想ディスクイメージファイル(file=u91064sB.qcow2)、MACアドレス(macaddr=52:54:00:12:34:01)とTAPデバイスの名称(ifname=tap1)の指定が必要です。

sudo kvm -m 512 -boot c -curses \
    -drive file=u91064sB.qcow2,if=virtio,boot=on \
    -net nic,macaddr=52:54:00:12:34:01,model=virtio \
    -net tap,ifname=tap1,script=/etc/qemu-ifup

ネットワークの設定

ゲスト0と同様にネットワークを設定するシェルスクリプトを用意しました。ゲスト0と異なる固定IP(IP=172.18.21.91)を起動後に設定します。

#!/bin/sh

IP=172.18.21.91
GW=.1
#GW=.254

IP24=`expr $IP : "\(.*\)\.[0-9]"`
NIC=`/sbin/ifconfig -a| awk '$1 ~ /^eth/ {print $1}'`

echo $NIC
echo "ip address :" $IP
echo "broadcast  :" $IP24.255
echo "gateway    :" $IP24$GW
ifconfig $NIC $IP netmask 255.255.255.0 broadcast $IP24.255
route add default gw $IP24$GW
root@Guest0~# ifconfig
eth1      Link encap:Ethernet  HWaddr 52:54:00:12:34:01
          inet addr:172.18.21.91  Bcast:172.18.21.255  Mask:255.255.255.0
          inet6 addr: fe80::5054:ff:fe12:3401/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:199 errors:0 dropped:0 overruns:0 frame:0
          TX packets:16 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:53407 (53.4 KB)  TX bytes:1677 (1.6 KB)

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:16436  Metric:1
          RX packets:109 errors:0 dropped:0 overruns:0 frame:0
          TX packets:109 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:26401 (26.4 KB)  TX bytes:26401 (26.4 KB)

ホスト

ホスト側のネットワークの状態です。eth0 以外にも br0、tap0、tap1 が動作していることがわかります。

jun@Host:~$ ifconfig -a
br0       Link encap:Ethernet  HWaddr xx:xx:xx:xx:xx:xx
          inet addr:172.18.21.80  Bcast:172.18.21.255  Mask:255.255.255.0
          inet6 addr: fe80::21d:60ff:fe6d:aeb4/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:4382 errors:0 dropped:0 overruns:0 frame:0
          TX packets:3590 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:678128 (678.1 KB)  TX bytes:1546751 (1.5 MB)

eth0      Link encap:Ethernet  HWaddr xx:xx:xx:xx:xx:xx
          inet6 addr: fe80::21d:60ff:0e6d:aeb4/64 Scope:Link
          UP BROADCAST RUNNING PROMISC MULTICAST  MTU:1500  Metric:1
          RX packets:4555 errors:0 dropped:0 overruns:0 frame:0
          TX packets:3724 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:748183 (748.1 KB)  TX bytes:1562023 (1.5 MB)
          Interrupt:17

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:16436  Metric:1
          RX packets:11 errors:0 dropped:0 overruns:0 frame:0
          TX packets:11 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:744 (744.0 B)  TX bytes:744 (744.0 B)

tap0      Link encap:Ethernet  HWaddr da:5b:2f:45:26:e0
          inet6 addr: fe80::d85b:2fff:fe45:26e0/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:58 errors:0 dropped:0 overruns:0 frame:0
          TX packets:247 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:500
          RX bytes:6378 (6.3 KB)  TX bytes:67099 (67.0 KB)

tap1      Link encap:Ethernet  HWaddr ae:2c:bf:35:91:98
          inet6 addr: fe80::ac2c:bfff:fe35:9198/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:22 errors:0 dropped:0 overruns:0 frame:0
          TX packets:227 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:500
          RX bytes:2400 (2.4 KB)  TX bytes:62453 (62.4 KB)

ゲストOSをサーバとして使う

ここまでコンソールでkvmコマンドを実行することでゲストOSを起動し、ゲストOSのコンソール出力は vnc 経由(-vnc)、または起動コンソール(-curses)で表示していました。 vnc 経由では仮想マシンのグラフィック出力を転送する方法、cursesオプションはVGAへの文字出力を抽出してkvmを起動したコンソールに表示する方法となっています。どちらもPCのグラフィックカードへのコンソール出力を利用するものです。 ゲストで実行する Linux をサーバとして使用する場合は、常にコンソール出力を表示する必要はなく、ホストのバックグラウンドプロセス(デーモン)として動作すれば十分です。


ここでは仮想マシン上のゲストOSをホストと独立してサーバとして利用します。デスクトップでLinuxを使う場合と異なり、ネットワークさえつながっていればキーボードも画面もほとんど必要ありません。ホストの起動時に自動的にゲストもサーバとして起動し、メンテナンス等で必要なときだけコンソール経由でアクセスできれば理想的です。「ゲストOSはホストのバックグラウンドプロセスとして黙ってサーバとしての動作を続け、必要なときだけコンソールを表示する。」という動作をカーネルのコンソール出力をシリアル端末に切り替えて、コンソールの接続、切断を screen コマンドを利用して実現します。



以上の機能を実現する方法を試してみました。

ゲストのネットワーク設定

/etc/network/interfaces のeth0 に関する部分をコメントアウトしました。

jun@Guest0:~$ cat /etc/network/interfaces
# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).

# The loopback network interface
auto lo
iface lo inet loopback

# The primary network interface
#auto eth0
#iface eth0 inet dhcp

今回は起動の最後に実行される(/etc/init.d/rc.localから呼ばれる) /etc/rc.local でネットワークを設定することにしました。exit 0 の前にネットワークの設定を追加します。

root@Guest0/etc# cat /etc/rc.local
#!/bin/sh -e
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will "exit 0" on success or any other
# value on error.
#
# In order to enable or disable this script just change the execution
# bits.
#
# By default this script does nothing.

IP=172.18.21.90
GW=.1
#GW=.254

IP24=`expr $IP : "\(.*\)\.[0-9]"`
NIC=`/sbin/ifconfig -a| awk '$1 ~ /^eth/ {print $1}'`
ifconfig $NIC $IP netmask 255.255.255.0 broadcast $IP24.255
route add default gw $IP24$GW

exit 0

/etc/rc.localが実行可能(x)になっていることを確認します。

jun@Guest0/etc$ ls -l rc.local
-rwxr-xr-x 1 root root 517 2010-01-06 01:17 rc.local

ゲストを再起動すると /etc/rc.local で設定した固定IPで起動されます。

カーネルのシリアル出力設定

ゲスト側のカーネルのコンソール出力をシリアルに出力するように変更するため、ゲスト側の grub のカーネルのコマンドラインをシリアル用に設定します。Ubuntu 9.10 は GRUB2を使っているため、/boot/grub/menu.lst ではなく、/etc/default/grub を変更した後、「update-grub」を実行します。

jun@Guest0/etc/init$ cat /etc/default/grub
# If you change this file, run 'update-grub' afterwards to update
# /boot/grub/grub.cfg.

GRUB_DEFAULT=0
GRUB_HIDDEN_TIMEOUT=0
GRUB_HIDDEN_TIMEOUT_QUIET=true
GRUB_TIMEOUT="10"
GRUB_DISTRIBUTOR=`lsb_release -i -s 2> /dev/null || echo Debian`
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"
GRUB_CMDLINE_LINUX="console=tty0 console=ttyS0,115200n8"

# Uncomment to disable graphical terminal (grub-pc only)
#GRUB_TERMINAL=console

# The resolution used on graphical terminal
# note that you can use only modes which your graphic card supports via VBE
# you can see them in real GRUB with the command `vbeinfo'
#GRUB_GFXMODE=640x480

# Uncomment if you don't want GRUB to pass "root=UUID=xxx" parameter to Linux
#GRUB_DISABLE_LINUX_UUID=true

# Uncomment to disable generation of recovery mode menu entrys
#GRUB_DISABLE_LINUX_RECOVERY="true"

Ubuntu 9.10 は Upstart を使っているため、inittab がありません。ゲスト側の /etc/init/tty1.conf を変更して、シリアル回線からログインできるようにします。

jun@Guest0/etc/init$ cat /etc/init/tty1.conf
# tty1 - getty
#
# This service maintains a getty on tty1 from the point the system is
# started until it is shut down again.

start on stopped rc RUNLEVEL=[2345]
stop on runlevel [!2345]

respawn
exec /sbin/getty -L ttyS0 115200 vt100
#exec /sbin/getty -8 38400 tty1

kvm の起動オプションに「-serial stdio」を指定することで、ゲストOSのシリアル出力を起動コンソールの標準入出力(stdio)に表示させます。

jun@Host:~$ sudo kvm -m 512 -boot c -nographic -serial stdio \
    -drive file=u91064s.qcow2,if=virtio,boot=on \
    -net nic,macaddr=52:54:00:12:34:00,model=virtio \
    -net tap,ifname=tap0,script=/etc/qemu-ifup

Ubuntu 9.10 u91064s ttyS0

u91064s login: jun
Password:
Last login: Wed Jan  6 23:10:05 JST 2010 on tty1
Linux u91064s 2.6.31-14-server #48-Ubuntu SMP Fri Oct 16 15:07:34 UTC 2009 x86_64

To access official Ubuntu documentation, please visit:
https://help.ubuntu.com/

  System information as of Wed Jan  6 23:12:43 JST 2010

  System load: 0.0               Memory usage: 12%   Processes:       78
  Usage of /:  23.6% of 3.71GB   Swap usage:   0%    Users logged in: 0

  Graph this data and manage this system at https://landscape.canonical.com/

コントロールと「a」を同時に押した後、「c」を押すことで QEMU(kvm)のモニター画面に切り替えられます。もう一度「C-a c」を押すとコンソール出力に切り替えることができます。

jun@Guest0:~$
C-a h    print this help
C-a x    exit emulator
C-a s    save disk data back to file (if -snapshot)
C-a t    toggle console timestamps
C-a b    send break (magic sysrq)
C-a c    switch between console and monitor
C-a C-a  sends C-a
QEMU 0.11.0 monitor - type 'help' for more information
(qemu)

jun@Guest0:~$

ゲストのコンソール出力

screen コマンドは端末の出力を物理的な端末と切り離したり、再接続したりすることができるコマンドです。screen からゲストを起動してゲストのコンソール出力を実端末(ターミナル画面)と切り離したり、再接続したりできると便利です。

以下のコマンドを入力して1番目のゲストを起動します。「screen -S Guest0」の行は、screen のセッション(ウィンドウの集合)にGuest0という名前を付けるオプションです。ゲストOSで動作させるサーバの名前などをセッション名として指定すると再接続する場合に識別しやすくなります。

screen -S Guest0
sudo kvm -m 512 -boot c -nographic -serial stdio \
    -drive file=u91064s.qcow2,if=virtio,boot=on \
    -net nic,macaddr=52:54:00:12:34:00,model=virtio \
    -net tap,ifname=tap0,script=/etc/qemu-ifup

ゲストのLinuxが起動して、ログインプロンプトが表示されるまで私の環境で 5 秒程度の時間がかかります。kvmコマンドの応答と考えるとちょっと長く感じますが、サーバが5秒で起動すると考えると非常に速いです。

jun@Host:~$ sudo kvm -m 512 -boot c -nographic -serial stdio \
>     -drive file=u91064s.qcow2,if=virtio,boot=on \
>     -net nic,macaddr=52:54:00:12:34:00,model=virtio \
>     -net tap,ifname=tap0,script=/etc/qemu-ifup
[sudo] password for jun:

Ubuntu 9.10 Guest0 ttyS0

Guest0 login: jun
Password:
Last login: Thu Jan  7 01:42:06 JST 2010 on ttyS0
Linux Guest0 2.6.31-14-server #48-Ubuntu SMP Fri Oct 16 15:07:34 UTC 2009 x86_64

To access official Ubuntu documentation, please visit:
https://help.ubuntu.com/

  System information as of Thu Jan  7 01:45:33 JST 2010

  System load: 0.0               Memory usage: 9%   Processes:       78
  Usage of /:  23.6% of 3.71GB   Swap usage:   0%   Users logged in: 0

  Graph this data and manage this system at https://landscape.canonical.com/

jun@Guest0:~$

screenの機能で切断(デタッチ)、接続(アタッチ)ができることを確認するため、Guest0で「top」を起動しておきます。

top - 01:46:16 up 1 min,  1 user,  load average: 0.00, 0.00, 0.00
Tasks:  74 total,   1 running,  73 sleeping,   0 stopped,   0 zombie
Cpu(s):  0.0%us,  0.0%sy,  0.0%ni, 99.3%id,  0.0%wa,  0.7%hi,  0.0%si,  0.0%st
Mem:    504128k total,   125356k used,   378772k free,    10728k buffers
Swap:   240932k total,        0k used,   240932k free,    66612k cached

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
  894 jun       20   0 19112 1268  980 R  0.7  0.3   0:00.13 top
    1 root      20   0 19320 1459 1196 S  0.0  0.3   0:00.31 init
    2 root      15  -5     0    0    0 S  0.0  0.0   0:00.01 kthreadd
    3 root      RT  -5     0    0    0 S  0.0  0.0   0:00.00 migration/0
    4 root      15  -5     0    0    0 S  0.0  0.0   0:00.00 ksoftirqd/0
    5 root      RT  -5     0    0    0 S  0.0  0.0   0:00.00 watchdog/0
    6 root      15  -5     0    0    0 S  0.0  0.0   0:00.00 events/0
    7 root      15  -5     0    0    0 S  0.0  0.0   0:00.00 cpuset
    8 root      15  -5     0    0    0 S  0.0  0.0   0:00.00 khelper
    9 root      15  -5     0    0    0 S  0.0  0.0   0:00.00 netns
   10 root      15  -5     0    0    0 S  0.0  0.0   0:00.00 async/mgr
   11 root      15  -5     0    0    0 S  0.0  0.0   0:00.00 kintegrityd/0
   12 root      15  -5     0    0    0 S  0.0  0.0   0:00.00 kblockd/0
   13 root      15  -5     0    0    0 S  0.0  0.0   0:00.00 kacpid
   14 root      15  -5     0    0    0 S  0.0  0.0   0:00.00 kacpi_notify
   15 root      15  -5     0    0    0 S  0.0  0.0   0:00.00 kacpi_hotplug
   16 root      15  -5     0    0    0 S  0.0  0.0   0:00.02 ata/0

ctrl-A d を入力してホストに戻ります。次に以下のコマンドを入力して2番目のゲストを起動します。セッション名は「Guest1」と指定します。

screen -S Guest1
sudo kvm -m 512 -boot c -nographic -serial stdio \
    -drive file=u91064sB.qcow2,if=virtio,boot=on \jun
    -net nic,macaddr=52:54:00:12:34:01,model=virtio \
    -net tap,ifname=tap1,script=/etc/qemu-ifup

2つ目の仮想マシンも5秒程度で起動します。

jun@Host:~$ sudo kvm -m 512 -boot c -nographic -serial stdio \
>     -drive file=u91064sB.qcow2,if=virtio,boot=on \
>     -net nic,macaddr=52:54:00:12:34:01,model=virtio \
>     -net tap,ifname=tap1,script=/etc/qemu-ifup

Ubuntu 9.10 Guest1 ttyS0

Guest1 login: jun
Password:
Last login: Thu Jan  7 01:41:14 JST 2010 on ttyS0
Linux Guest1 2.6.31-14-server #48-Ubuntu SMP Fri Oct 16 15:07:34 UTC 2009 x86_64

To access official Ubuntu documentation, please visit:
https://help.ubuntu.com/

  System information as of Thu Jan  7 01:47:29 JST 2010

  System load: 0.0               Memory usage: 9%   Processes:       78
  Usage of /:  23.6% of 3.71GB   Swap usage:   0%   Users logged in: 0

  Graph this data and manage this system at https://landscape.canonical.com/

Guest1と同様にGuest1でも「top」を起動しておきます。

top - 01:48:28 up 1 min,  1 user,  load average: 0.00, 0.00, 0.00
Tasks:  74 total,   1 running,  73 sleeping,   0 stopped,   0 zombie
Cpu(s):  0.0%us,  0.0%sy,  0.0%ni, 99.3%id,  0.0%wa,  0.7%hi,  0.0%si,  0.0%st
Mem:    504128k total,   125184k used,   378944k free,    10716k buffers
Swap:   240932k total,        0k used,   240932k free,    66552k cached

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
  885 jun       20   0 19112 1268  980 R  0.7  0.3   0:00.09 top
    1 root      20   0 19320 1459 1196 S  0.0  0.3   0:00.34 init
    2 root      15  -5     0    0    0 S  0.0  0.0   0:00.01 kthreadd
    3 root      RT  -5     0    0    0 S  0.0  0.0   0:00.00 migration/0
    4 root      15  -5     0    0    0 S  0.0  0.0   0:00.00 ksoftirqd/0
    5 root      RT  -5     0    0    0 S  0.0  0.0   0:00.00 watchdog/0
    6 root      15  -5     0    0    0 S  0.0  0.0   0:00.00 events/0
    7 root      15  -5     0    0    0 S  0.0  0.0   0:00.00 cpuset
    8 root      15  -5     0    0    0 S  0.0  0.0   0:00.00 khelper
    9 root      15  -5     0    0    0 S  0.0  0.0   0:00.00 netns
   10 root      15  -5     0    0    0 S  0.0  0.0   0:00.00 async/mgr
   11 root      15  -5     0    0    0 S  0.0  0.0   0:00.00 kintegrityd/0
   12 root      15  -5     0    0    0 S  0.0  0.0   0:00.00 kblockd/0
   13 root      15  -5     0    0    0 S  0.0  0.0   0:00.00 kacpid
   14 root      15  -5     0    0    0 S  0.0  0.0   0:00.00 kacpi_notify
   15 root      15  -5     0    0    0 S  0.0  0.0   0:00.00 kacpi_hotplug
   16 root      15  -5     0    0    0 S  0.0  0.0   0:00.01 ata/0

ctrl-A d を入力してGuest1の画面を切り離し、端末をホストのシェルに切り替えます。ネットワーク越しにSSHで端末を使っている場合に「exit」でシェルを終了して切断しても、ゲストは動作したまま残ります。後日「screen -r セッション名」で元の画面に戻ることができます。


必要な作業が終われば、ctrl-A d を入力してホストに戻ります。ここでログオフして端末を閉じても、screen で動作しているセッションの一覧は「screen -ls」で次のように表示されます。

jun@Host:~$ screen -ls
There are screens on:
        2382.Guest1     (01/07/2010 01:47:08 AM)        (Detached)
        2501.Guest0     (01/07/2010 01:44:31 AM)        (Detached)
2 Sockets in /var/run/screen/S-jun.

「screen -r Guest0」で最初のゲストの画面を、「screen -r Guest1」で2番目に起動したLinuxのコンソール画面を表示して通常に操作することができます。

                                             +-----------------+
                                             |  ゲスト 0       |
                            +---------+      |                 |
    +-----------------+     | screen  |      |  コンソール画面 |
    | ホスト端末画面  |     | session +------+                 |
    |                 | <---| Guest0  |      |                 |
    |                 |     +---------+      +-----------------+
    |                 |
    |                 |                      +-----------------+
    |                 |     +---------+      |  ゲスト 1       |
    |                 | <---| screen  |      |                 |
    +-----------------+     | session +------+  コンソール画面 |
                            | Guest1  |      |                 |
                            +---------+      |                 |
                                             +-----------------+

このようにゲストのコンソールは screen コマンドのセッションとして残すことができ、必要なときにはいつでも、どこからでもゲストのコンソールを操作することができるようになります。

screen は ctrl-A を使って非常に多彩な機能を提供します。しかし、QEMUのモニター画面への切り替えにも ctrl-A を使う必要があります。その場合は 「ctrl-A a」と入力することで ctrl-A がQEMUに送られます。したがってQEMUのモニターへの切り替えは「ctrl-A ac」と入力する必要があります。

screenをスクリプト内で使用

上で書いた方法では起動した後、手動(ctrl-A d)で実端末から切断(デタッチ)する必要があります。ホストの起動時に自動的にゲストを起動することができません。そこで、スクリーン起動、ゲスト起動、screenをデタッチを連続して行うスクリプトにしてみました。

Guest0用スクリプト

Guest0を screen 内で起動してデタッチするスクリプトです。

jun@Host:~$ cat start-g0.sh
#!/bin/sh
screen -S Guest0 -d -m kvm -m 512 -boot c \
    -localtime -nographic  -serial stdio \
    -drive file=u91064s.qcow2,if=virtio,boot=on \
    -net nic,macaddr=52:54:00:12:34:00,model=virtio \
    -net tap,ifname=tap0,script=/etc/qemu-ifup
Guest1用スクリプト

Guest1を screen 内で起動してデタッチするスクリプトです。

jun@Host:~$ cat start-g1.sh
#!/bin/sh
screen -S Guest1 -d -m kvm -m 512 -boot c \
    -localtime -nographic  -serial stdio \
    -drive file=u91064sB.qcow2,if=virtio,boot=on \
    -net nic,macaddr=52:54:00:12:34:01,model=virtio \
    -net tap,ifname=tap1,script=/etc/qemu-ifup
実行結果

Guest0とGuest1というセッション名でscreenからkvmが起動していることが確認できます。

root@Host:~$ screen -ls
There are screens on:
        1285.Guest1     (01/08/2010 12:58:34 AM)        (Detached)
        1181.Guest0     (01/08/2010 12:53:23 AM)        (Detached)
2 Sockets in /var/run/screen/S-root.

root@Host:~$ pstree
init─┬─atd
      ├─cron
      ├─dd
      ├─6*[getty]
      ├─nmbd
      ├─rsyslogd───3*[{rsyslogd}]
      ├─2*[screen───kvm───{kvm}]
      ├─smbd───smbd
      ├─sshd───sshd───sshd───bash───su───bash───pstree
      ├─udevd───2*[udevd]
      ├─upstart-udev-br
      └─winbindd───winbindd

/etc/rc.local内に記述することでホストの起動直後に自動的にゲストを起動することができます。

これで3台の普通のサーバができました。後はサーバの使い方を考えるだけです。


メモ

ディスクイメージの縮小

qcow2形式のディスクイメージは使っている部分だけを記録する形式ですが、使っているうちに大きくなってきます。イメージ中の未使用の部分を削除するには qemu-img の件肝機能を使います。以下のように qcow2 から qcow2 への変換を行うことで、イメージが再構築されて小さくすることができます。u91064s.qcow2 というディスクイメージファイルを縮小して u91064s.qcow2.new にする例です。

jun@Host:~$ sudo qemu-img convert -O qcow2 u91064s.qcow2 u91064s.qcow2.new
jun@Host:~$ ls -lt
-rw-r--r-- 1 jun jun 1235615744 2010-01-03 20:17 u91064s.qcow2.new
-rw-r--r-- 1 jun jun 1315110912 2009-12-30 22:33 u91064s.qcow2

Apacheの設定

Ubuntu でApache を設定する方法は httpd.conf を編集するスタイルではありません。忘れてしまうのでメモ。

/home/jun/public_html/index.html を https://exsample.mztn.org/~jun/ でアクセスできるようにします。

root@Guest0/etc/apache2# a2enmod userdir
Enabling module userdir.
Run '/etc/init.d/apache2 restart' to activate new configuration!

設定を有効にするため、httpd を再起動します。

root@Guest0/etc/apache2# /etc/init.d/apache2 restart
 * Restarting web server apache2
apache2: Could not reliably determine the server's fully qualified domain name,
using 127.0.1.1 for ServerName
 ... waiting apache2: Could not reliably determine the server's fully qualified
domain name, using 127.0.1.1 for ServerName
                                                                         [ OK ]

新しい記事があります。Ubuntu 16.04 LTS の KVM で仮想サーバ (2016/05/06)