ユーザ用ツール

サイト用ツール


linux:kvm

Linux KVM関係

参考資料

ホスト側設定

カーネル

GentooのWikiに従って設定

KVMサポート

Virtualization  --->
  --- Virtualization
   <*>Kernel-based Virtual Machine (KVM) support
   <*>KVM for Intel processors support
   < >KVM for AMD processors support
   <*>Host kernel accelerator for virtio net (EXPERIMENTAL)

ネットワーク関係(ブリッジ接続用)

Device Drivers  --->
  Network device support  --->
     [*]   Network core driver support
       <*>     Universal TUN/TAP device driver support
Networking support  --->
   Networking options  --->
     <*> 802.1d Ethernet Bridging
      [*]IGMP/MLD snooping

KSM (複数のVM間でメモリを共有する)

Processor type and features  --->
  [*] Enable KSM for page merging

関連パッケージ

  • app-emulation/qemu – KVMの基本ユーティリティ
    • QEMU_SOFTMMU_TARGETS=“x86_64” – フルモードでエミュレートするアーキテクチャ
    • QEMU_USER_TARGETS=“” – ユーザランドモードでエミュレートするアーキテクチャ
  • net-misc/bridge-utils – ブリッジネットワーク関連のユーティリティ
  • sys-apps/usermode-utilities – tunctlコマンドをインストールするため

ネットワーク設定

Guest用に使う物理NICを増設したので、Host側のNICはHost専用で利用する。HostとGuestが別のネットワークに接続されることを前提に、両者の通信用に内部でローカルネットワークを構成する。QEMUでuserモードのネットワークデバイスを使うこともできるが、Guest側からもHostの物理NICが接続しているネットワークに接続する可能性を考えて、Bridgeを用意する(nftablesなどでフォワード、マスカレードすることもできるが、設定が面倒なので使わないことにする)。

/etc/conf.d/net

  • Hostの物理NICの最近の命名規則は違っているが、とりあえずeth+Nとする。
  • eth0はHost用のNIC(マザーボード)
  • eth1はGuest用に増設したNIC
## Hostのネットワーク設定(通常通り)
config_eth0="192.168.0.1/24"
routes_eth0="default via 192.168.0.254"

## Guestのネットワーク設定
## Bridgeを作成しGuest用物理NICとGuestのtapを接続する

# 物理NICにはIPを割り当てない
config_eth1="null"
# tapデバイスをtap0として構成しIPを空に(IPはGuest OSが設定)
tuntap_tap0="tap"
config_tap0="null"
# bridgeデバイスをbr0として構成しeth1とtap0を参加させる
bridge_br0="eth1 tap0"
# bridgeデバイスそのものにはIPアドレスを設定しない
# HostからGuest用NICがわのネットワークに出ていく場合は適当なIPを設定
config_br0="null"
# bridgeのオプション設定
bridge_forward_delay_br0=0
bridge_hello_time_br0=1000

# bridgeを起動する際の依存関係を記述
# 起動スクリプトが実行される際の依存関係
depend_br0() {
           # /etc/init.dのスクリプト名
           need net.eth1
           need net.tap0
}

以上の設定をしたうえで、/etc/init.dのnet.loからnet.br0、net.tap0など必要なデバイスへのシンボリックリンクを作成し、defaultのrunlevelに追加する。

GuestとHostが内部的に通信するためのBridgeも構成

# tap_local0というtapデバイスを作成しIPは空にしておく
tuntap_tap_local0="tap"
config_tap_local0="null"
# br_local0というbridgeデバイスを作成しtap_local0を参加
bridge_br_local0="tap_local0"
# bridge自体にIPアドレスを設定
# Hostが利用するIPアドレス。適当なローカルアドレスにする
config_br_local0="192.168.1.1/24"
bridge_forward_delay_br_local0=0
bridge_hello_time_br_local0=1000

depend_br_local0() {
           need net.tap_local0
}

br_local0というブリッジデバイスにGuestの2つ目のNICをtap経由で接続しておくことで、HostとGuestしか接続されないネットワークをつくる。ルーティングやIPフォワードの設定をしなければ、HostとGuestだけが参加する内部的なネットワークになる。GuestへのSSHなどは、基本的にHostにログインしてからこのローカルネットワークからアクセスするようにする。

ゲストOS

ディスクイメージの作成

# rawイメージで30GBのディスクイメージを作成
# preallocationでディスク容量分の領域を確保
> qemu-img create -f raw -o preallocation=full Disk01_raw.img 30G                   

Guestを起動するシェルスクリプトを適当に作成

/usr/bin/qemu-system-x86_64 \
  -name "exam_vm" \
  -machine type=q35,accel=kvm \
  -object rng-random,id=rng0,filename=/dev/urandom -device virtio-rng-pci,rng=rng0 \
  -cpu host \
  -smp 8 \
  -m 4G \
  -drive file=exam_vm_raw.img,driver=raw,if=virtio,index=0,media=disk,cache=writeback \
  -boot c \
  -netdev tap,id=net0,ifname=tap0,vhost=on,script=no,downscript=no -device virtio-net,netdev=net0,mac=52:54:00:87:92:31 \
  -netdev tap,id=net1,ifname=tap_local0,vhost=on,script=no,downscript=no -device virtio-net,netdev=net1,mac=52:54:00:87:92:32 \
  -monitor unix:/home/kvm-admin/monitor_socket/exam_vm.sock,server,nowait \
  -display none \
  -daemonize \
  -fsdev local,id=share,path=/home/kvm-admin/share_dir,security_model=mapped-xattr -device virtio-9p-pci,fsdev=share,mount_tag=host_share

オプション

  • -name “VM01”
    • 仮想マシンの名称
  • -machine type=q35,accel=kvm
    • 仮想マシンのタイプ:マザーボードの基本構成のようなもの
    • KVMを有効にする。QEMUは汎用的な仮想マシンエミュレータでKVMでカーネルの支援が有効になる
  • -object rng-random,id=rng0,filename=/dev/urandom -device virtio-rng-pci,rng=rng0
    • 乱数生成器などを仮想マシンから見えるようにする
  • -cpu host
    • cpuのタイプ。他の種類のCPUもエミュレートできるがHostをそのまま使うのが一番効率がよい
  • -smp 8
    • 割り当てるCPUの数。NUMA構成などもできるようだが単純にコア数だけ指定
  • -m 4G
    • 割り当てるメモリ
  • -drive file=exam_vm_raw.img,driver=raw,if=virtio,index=0,media=disk,cache=writeback
    • 仮想ハードディスクの設定。作成した仮想ディスクのイメージとフォーマットを指定。インターフェイスはvirtio
    • cacheやaioなどの設定によってディスクのパフォーマンスをが変わる。HostがSSDかHDDか、メモリの量などで調整が必要
  • boot c
    • 起動デバイスの指定。cはハードディスク。dはCD-ROM。インストール時は起動ディスクのisoをCD-ROMとして設定してdから起動。

 * CD-ROMを接続する場合は「-cdrom install-amd64-minimal-20200531T214503Z.iso」

  • -netdev tap,id=net0,ifname=tap0,vhost=on,script=no,downscript=no
    • ネットワークのバックエンドの設定。tapで先ほど作成したtap0に接続する。idは仮想マシン側に見せるデバイスの設定に利用。
    • scriptは仮想マシン起動時にtapデバイスを作成する場合に利用できる。ここでは静的に設定しているのでスクリプトは利用なし。
  • -device virtio-net,netdev=net0,mac=52:54:00:87:92:31
    • Guest側に見えるNICの設定。virtio-net経由でidで指定したバックエンド(net0)に接続。
  • -netdev tap,id=net1,ifname=tap_local0,vhost=on,script=no,downscript=no
  • -device virtio-net,netdev=net1,mac=52:54:00:87:92:32
    • 同様に、Hostと通信するためだけに作成したBridgeに接続しているNICもGuestに作成
  • -monitor unix:/foo/var/vm01.sock,server,nowait
    • QEMUモニタに接続するためのソケット。telnetでモニタにアクセスできるようにもできるが、telnetの場合、複数の仮想マシンを運用すると、各仮想マシンのモニタの区別はポート番号のみになり、管理しにくい。ソケットであれば、ソケット名をわかりやすく設定できるので便利。
    • ソケットへのアクセスはsocatコマンドで可能。
    • socat - UNIX-CONNECT:/foo/bar/vm01.sock
    • 上記コマンドにパイプでモニタコマンドを与えてやると直接モニタを操作できる。例えば「echo “system_powerdown” |socat - UNIX-CONNECT:/foo/bar/vm01.sock」とすれば、仮想マシンに電源ボタンを押下したことを伝達できる。仮想マシン上のカーネルで電源ボタンの押下を検知できるようにし、acpidなどを設定しておくとHostから手軽にシャットダウンできる。
    • telnetの場合は「-monitor telnet:127.0.0.1:10100,server,nowait」。10100番ポートにtelnetするとモニタにアクセスできる。
  • -display none
    • 本番でサーバ運用の場合はディスプレイは不要なのでnone。
    • インストール時はcursesとすれば、sshなどのコマンドラインに直接Guestのコンソールを接続できる。ただし、テキストモードの場合のみ。グラフィックモードの場合はvncなどが必要。
  • -daemonize
    • 本番時はターミナルから切り離して起動。
  • -fsdev local,id=share,path=/foo/bar/share_dir,security_model=mapped-xattr
  • -device virtio-9p-pci,fsdev=share,mount_tag=v_share
    • HostのディレクトリをGuestと共有。Guest側カーネルで9pのオプションを有効にする必要がある。
    • fsdevで共有するディレクトリのバックエンドを設定し、deviceでGuestから見えるデバイスを生成する。mount_tagはGuestからmountする場合のデバイス名となる。

ゲストOSの設定

従来はエミュレートされたハードウェアに対して通常のドライバを利用していたが、最近はGuestからHostへのアクセスは基本的にVirtio経由で行う。以下を参考に必要なドライバを組み込む。Virtio経由でアクセスするため、SATAやNICのドライバなども無効にしてよい。

時刻

Guestの時刻同期は、仮想ネットワークデバイスがハードウェアタイムスタンプをサポートしていないため、NTPではマイクロ秒レベルの正確な時刻同期ができないらしい。正確にクロックを同期するには、PTPを通してHostのクロックをハードウェアタイムスタンプで同期すればよいらしい。

カーネルのPTPドライバを有効にする

 Device Drivers  --->
    PTP clock support  --->
      [*] PTP clock support
      [*] KVM virtual PTP clock

時刻同期にPTPで時刻を同期できるchronyを利用する。

chrony.confは以下の1行のみを有効にする。server行などはすべてコメントアウト。

refclock PHC /dev/ptp0 poll 2

起動時にhwclockが走らないようにbootランレベルから削除しておく。起動時の時刻同期はカーネル機能で対応。

Device Drivers  --->
  Device Drivers  --->
    [*]   Set system time from RTC on startup and resume
    (rtc0)  RTC used to set the system time
     [*]   /sys/class/rtc/rtcN (sysfs)
     [*]   /proc/driver/rtc (procfs for rtcN)
     [*]   /dev/rtcN (character devices)
     [*]   PC-style 'CMOS'
linux/kvm.txt · 最終更新: 2020/08/11 11:33 by Wiki Editor