KVM をインストールして設定する

新しい PC を買って KVM をインストールしたので手順をまとめてみました。

# 1. Linux のインストール

まずは Linux をインストールします。今回は Ubuntu 24.04 をインストールしました。

参照: [Ubuntu 20.04 LTS インストール](https://www.server-world.info/query?os=Ubuntu_20.04&p=install)

自分の使っている PC で仮想化をサポートしているか確認します。結果が 0 などとなる場合は BIOS の CPU の設定を確認してください。

```
$ egrep -c '(vmx|svm)' /proc/cpuinfo
12
```

これはお好みですがデフォルトのエディタを vi にして sudo をパスワードなしで実行できるようにします。

```
$ sudo update-alternatives --config editor
$ sudo visudo
```

```
[ユーザー名]  ALL=(ALL:ALL) NOPASSWD:ALL
```

上記の行を以下の行より後ろに追加します。[ユーザー名] は自分が使っているユーザー名に変更します。

```
%sudo   ALL=(ALL:ALL) ALL
```

参考: [Set Vim as your default editor for Unix](https://vim.fandom.com/wiki/Set_Vim_as_your_default_editor_for_Unix)

# 2. KVM のインストール

KVM ホストに VM に関連するパッケージをインストールします。

```
$ sudo apt update
$ sudo apt install -y qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils virt-manager
$ sudo reboot
```

次に自分が使用しているユーザーを libvirt と kvm グループに追加します。既に追加されている場合は必要ありません。

```
$ sudo adduser `id -un` libvirt
Adding user '<username>' to group 'libvirt' ...
$ sudo adduser `id -un` kvm
Adding user '<username>' to group 'kvm' ...
```

virt-top や virt-df などのツールもインストールしても良いかもしれません。Python や jq なども必要あであればインストールします。

参照: [KVM/Installation](https://help.ubuntu.com/community/KVM/Installation)

libvirtd が active か、QEMU 上でもハードウェア仮想化が有効かを確認します。

```
$ sudo systemctl is-active libvirtd
active
$ virt-host-validate
  QEMU: Checking for hardware virtualization                                 : PASS
  QEMU: Checking if device /dev/kvm exists                                   : PASS
<snip>
  QEMU: Checking for secure guest support                                    : WARN (AMD Secure Encrypted Virtualization appears to be disabled in kernel. Add kvm_amd.sev=1 to the kernel cmdline arguments)
```

参照: [KVM: Bare metal virtualization on Ubuntu with KVM](https://fabianlee.org/2018/08/27/kvm-bare-metal-virtualization-on-ubuntu-with-kvm/)

AMD Secure Encrypted Virtualization は仮想マシンで使用しているメモリ暗号化をハードウェアでサポートする技術のようですが KVM ホストを共有する使い方はしないのでここでは一旦無視します。

参照: [AMD Secure Encrypted Virtualization (SEV)](https://developer.amd.com/sev/)

# 3. ディスクの構成

例えば qcow2 イメージ用にシステムディスクとは別のディスクを使用する場合はディスクのフォーマットなどを行います。まずパーティション作成で使用する parted はここら辺が参考になりました。

参照: [Parted](https://wiki.archlinux.jp/index.php/Parted)

KVM に swap が必要かという話。あっても良いようです。

参照: [第7章 KVM でのオーバーコミット](https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/6/html/virtualization_administration_guide/chap-virtualization-tips_and_tricks-overcommitting_with_kvm)

ファイルシステムの比較を[ここ](https://qiita.com/tkarube/items/7afe5c5ac2584b3c2257)で軽くしてみました。ここら辺は好みだと思います。

以下では KVM でのストレージプールの設定を変更しデフォルトで使用するディレクトリを変更しています。

現在の pool のストレージプールのリストを表示します。

```
$ virsh pool-list
 Name      State    Autostart
-------------------------------
 default   active   yes
```

default を削除します。

```
$ virsh pool-destroy default
Pool default destroyed

~$ virsh pool-undefine default
Pool default has been undefined

$ virsh pool-list
 Name     State    Autostart
------------------------------

```

新しく default を作成します。ここでは新しいストレージプールのディレクトリを /datasotore1/images としています。

```
$ virsh pool-define-as --name default --type dir --target /datastore1/images
Pool default defined

$ virsh pool-autostart default
Pool default marked as autostarted

$ virsh pool-start default
Pool default started

$ virsh pool-list
 Name      State    Autostart
-------------------------------
 default   active   yes
```

参照: [デフォルトのストレージプールをlibvirtから変更するにはどうすればよいですか？](https://www.it-swarm-ja.tech/ja/kvm-virtualization/%E3%83%87%E3%83%95%E3%82%A9%E3%83%AB%E3%83%88%E3%81%AE%E3%82%B9%E3%83%88%E3%83%AC%E3%83%BC%E3%82%B8%E3%83%97%E3%83%BC%E3%83%AB%E3%82%92libvirt%E3%81%8B%E3%82%89%E5%A4%89%E6%9B%B4%E3%81%99%E3%82%8B%E3%81%AB%E3%81%AF%E3%81%A9%E3%81%86%E3%81%99%E3%82%8C%E3%81%B0%E3%82%88%E3%81%84%E3%81%A7%E3%81%99%E3%81%8B%EF%BC%9F/959998247/)

対象のディレクトリのパーミッションは以下の通りとなっていました。

```
drwxrwxr-x 2 libvirt-qemu kvm    247 Jan 11 18:10 images
```

この作業はもしかすると virsh pool-edit --pool default として既存の設定を変更したほうが早いかもしれません。

# 4. ネットワークの確認

デフォルトでは KVM インストール時に virbr0 と言う仮想ブリッジが作成されます。

```
$ ip addr show virbr0
4: virbr0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default qlen 1000
    link/ether 52:54:00:5e:9e:a2 brd ff:ff:ff:ff:ff:ff
    inet 192.168.122.1/24 brd 192.168.122.255 scope global virbr0
       valid_lft forever preferred_lft forever
$ brctl show
bridge name     bridge id               STP enabled     interfaces
virbr0          8000.5254005e9ea2       yes             virbr0-nic
$ virsh net-list
 Name      State    Autostart   Persistent
--------------------------------------------
 default   active   yes         yes
```

このブリッジを NAT として利用して仮想マシンは外のネットワークにアクセスできます。使わない場合は消してしまっても良いと思います。もちろん消さなくても良いと思います。消すならこのあたり。

```
$ virsh net-destroy default
$ virsh net-undefine default
```

参照: [https://www.cyberciti.biz/faq/linux-kvm-disable-virbr0-nat-interface/](https://www.cyberciti.biz/faq/linux-kvm-disable-virbr0-nat-interface/)

[ここ](https://levelup.gitconnected.com/how-to-setup-bridge-networking-with-kvm-on-ubuntu-20-04-9c560b3e3991)とか見ると以下の sysctl のパラメータを 0 にするように書かれています。

```
net.bridge.bridge-nf-call-ip6tables=0
net.bridge.bridge-nf-call-iptables=0
net.bridge.bridge-nf-call-arptables=0
```

これは恐らく br_netfilter というモジュールがロードされている場合の話。Ubuntu 20.04 ではデフォルトではロードされて無かったので必要ないと思います。多分w

# 5. ネットワークの設定

仮想マシンに割り当てた IP アドレス宛に外から通信したい場合は Linux 上でブリッジを作成します。Ubuntu 20.04 で netplan を使用する場合はこんな感じ。

```
$ cat /etc/netplan/60-eno1-config.yaml
network:
    version: 2
    ethernets:
        eno1:
            dhcp4: false
            dhcp6: false
    bridges:
        br0:
            interfaces:
                - eno1
            dhcp4: false
            dhcp6: false
            addresses:
                - 10.0.0.249/24
            gateway4: 10.0.0.1
            nameservers:
                addresses:
                    - 1.1.1.1
                    - 1.0.0.1
            parameters:
                forward-delay: 0
                stp: false
            optional: true
```

上記を明示的に KVM に登録することもできるが KVM ホストでブリッジを作った時点で KVM ゲストは見えるようになります。STP をどうするかは文章に寄って違ったりしますが多いのは無効。有効でも動かない落ちうことはないみたいです。

参考: [CentOSのKVMで使う仮想ネットワークについて調べてみた](https://qiita.com/hot_study_man/items/52af652d7b20a8a998b6)

CentOS ではデフォルトで使用されているためと思いますが、Network Manager を使った例も沢山あります。ここら辺もお好みで。

作成したブリッジは brctl コマンドで確認することができます。

```
$ brctl show
bridge name     bridge id               STP enabled     interfaces
br0             8000.a0369fa9f098       no              enp4s0f0
```

上記で作成したブリッジを KVM ゲストに割り当てて IP アドレスを割り振れば該当の IP に対して KVM 環境の外からもアクセスすることができます。

# 6. 内部ネットワークを作成する

KVM の内部で使用するネットワークを作成します。virt-manager でも作れますがここでは xml ファイルから作成してみます。

まずは xml ファイルを作成します。恐らく以下が一番シンプルな記述だと思います。ここで IP アドレスや DHCP などの設定もできます。

```
$ cat virbr1.xml
<network>
  <name>virbr1</name>
  <bridge name='virbr1' stp='on' delay='0' />
</network>
```

参照: [KVM (Kernel-based Virtual Machine) による仮想環境の構築手順（KVMのインストールと仮想ネットワーク作成手順）](https://www.virment.com/kvm-configuration/)

以下のコマンドで KVM にブリッジを作成し起動時に自動で構成されるようにします。

```
$ virsh net-define ./virbr1.xml
Network virbr1 defined from ./virbr1.xml

$ virsh net-autostart virbr1
Network virbr1 marked as autostarted

$ virsh net-start virbr1
Network virbr1 started
```

正常に作成されたかは以下のコマンドで確認ができます。

```
$ brctl show
bridge name     bridge id               STP enabled     interfaces
virbr1          8000.525400a99a82       yes             virbr1-nic
$ virsh net-list
 Name      State    Autostart   Persistent
--------------------------------------------
 default   active   yes         yes
 virbr1    active   yes         yes
```

実際の設定ファイルはここにあります。uuid や mac address は自動で付与してくれます。一度登録したものは virsh net-edit コマンドで編集することができます。

```
$ sudo cat /etc/libvirt/qemu/networks/virbr1.xml
<!--
WARNING: THIS IS AN AUTO-GENERATED FILE. CHANGES TO IT ARE LIKELY TO BE
OVERWRITTEN AND LOST. Changes to this xml configuration should be made using:
  virsh net-edit virbr1
or other application using the libvirt API.
-->

<network>
  <name>virbr1</name>
  <uuid>379d3199-365e-4c99-b331-77d50ed7b2ac</uuid>
  <bridge name='virbr1' stp='on' delay='0'/>
  <mac address='52:54:00:a9:9a:82'/>
</network>
```

参照: [net-define](https://libvirt.org/sources/virshcmdref/html/sect-net-define.html)

# 7. virsh をリモートで実行する

KVM ホストに直接 ssh などでログインするのはあまり好ましくない場合もあります。virsh や virt-manager で KVM の設定をしますがリモートでの実行も可能です。

virsh をリモートから実行するにはまずクライアントに libvirt-clients をインストールします。

```
$ sudo apt install libvirt-clients
```

次に以下のようなコマンドを実行します。

```
$ virsh -c qemu+ssh://test@10.0.0.250/system list
 Id   Name   State
----------------------
 1    c20h   running
```

上記の場合は ssh で接続しているため ssh の公開鍵認証などの設定をする必要があります。また .bash_aliases などに以下のように書いておくと便利かもしれません。

```
$ cat .bash_aliases | grep vir
alias virsh='virsh -c qemu+ssh://test@10.0.0.250/system'
$ virsh list
 Id   Name   State
----------------------
 1    c20h   running
```

virt-manager は GUI の File > Add Connection から設定が可能です。virsh, virt-manager 共に Windows Subsystem for Linux（WSL）上の Linux でも実行できるので便利です。

参照: [SSHSetup](https://wiki.libvirt.org/page/SSHSetup)

# 8. KVM ゲストを移行する

KVM ゲストを移行する際に古い KVM ホストから新しい KVM ホストにコピーしなければならないファイルは最低 2 つ。KVM ゲストのイメージ本体(qcow2)と設定ファイル(xml)ファイルです。

KVM ゲストのイメージは qcow2 という拡張子を持っていて、もっと良い方法もあるかもしれないですが virsh dumpxml コマンドで場所が確認できます。qcow2 ファイルをコピーする際には予め該当の KVM ゲストを shutdown させて置いたほうが良いと思います。

```
$ virsh dumpxml c20h | grep .qcow2
      <driver name='qemu' type='qcow2'/>
      <source file='/mnt/datastore1/images/c20h.qcow2'/>
```

KVM ゲストの設定ファイル (xml) の取得は同様に virsh dumpxml コマンドを使用します。

```
$ virsh dumpxml c20h > c20h.xml
```

新しい KVM ホストに移行する KVM ゲストを登録するには以下のコマンドを実行します。

```
$ virsh define c20h.xml
```

上記コマンドを実行する前に考慮する点としてはまず qcow2 ファイルの場所です。同じディレクトリに qcow2 ファイルを配置する場合は変更しなくて構いませんがもし異なる場合はテキストエディタで xml ファイルを予め編集します。

```
<source file='/mnt/datastore1/images/c20h.qcow2'/>
```

また同じく xml ファイルの中に cpu の種類の記述がある場合があります。もし CPU の種類が異なる場合はこの記述を変更します。

```
  <cpu mode='custom' match='exact' check='partial'>
    <model fallback='allow'>Haswell-noTSX-IBRS</model>
  </cpu>
```

単に KVM ホストの CPU の情報を引き継ぐように変更してあげるのが良いと思います。

```
  <cpu mode='host-model' check='partial'/>
```

上記設定は virsh define コマンドを事項した後に virtsh や virt-manage で変更することもできます。virt-manager で変更していしまうのも簡単で良いかもしれません。

virsh define コマンドを実行すると/etc/libvirt/qemu 以下に設定ファイルが作成されます。 

```
$ ls -al /etc/libvirt/qemu/c20h.xml
-rw------- 1 root root 4663 Jan 10 18:10 /etc/libvirt/qemu/c20h.xml
```

参照: [Linux備忘録 KVM仮想化ホスト間での仮想マシン移動](https://oplern.hatenablog.com/entry/2016/11/06/212257)

移行後の KVM ゲストは起動するようであれば virt-manager や virt-viewer でコンソールに接続し設定を変更することができます。

libguestfs-tools をインストールすれば KVM ゲストのディスクをマウントし編集することができます。この方法であれば KVM ゲストの起動前に設定を変更することができます。

```
$ sudo guestmount -d c20h -i /mnt/c20h/
$ sudo ls /mnt/c20h/etc/netplan
50-cloud-init.yaml
$ sudo vi /mnt/c20h/etc/netplan
$ sudo vi /mnt/c20h/etc/netplan/50-cloud-init.yaml
```

参照: [How to mount VM virtual disk on KVM hypervisor with Libguestfs Tools](https://computingforgeeks.com/how-to-mount-vm-virtual-disk-on-kvm-hypervisor/)

参照: [virsh commands cheatsheet to manage KVM guest virtual machines](https://computingforgeeks.com/virsh-commands-cheatsheet/)