Ubuntu Server 22.04 LTSでKVMを使用する方法

## はじめに

Ubuntu Server 22.04 LTSでKVMを使用する方法をまとめました。

KVM自体はLinuxカーネルに組み込まれているので、実際に行うのはKVMを使用するために必要なパッケージのインストール、ブリッジの作成ということになります。

最初はUbuntu公式のドキュメントを見て、そのとおりに行えばできるだろうと考えて作業を始めましたが、断片的な情報はあれど、一連の手順を示した情報は見つけられませんでした。

AWSやRHEL、その他のOSSなどでは、使用可能になるまでの手順が一通り載っている公式ドキュメントがありますが、UbuntuのKVMについては見当たりませんでした。そのため、必要なパッケージは何か、ブリッジの設定はどうするかということを調べて回りました。その結果が、この文章です。

もし、「公式のここに一連の手順が全部載っている」ということをご存じの方は、ご指摘ください。

## 確認したドキュメント

### Ubuntu Server Document, Virtualization

https://ubuntu.com/server/docs/virtualization-introduction

## KVM - Community Help Wiki

Community Help WikiにKVMのページがありましたが、最終更新日は2021年8月9日でした。よって、22.04 LTSが出る前の情報ということになります。

https://help.ubuntu.com/community/KVM

## 環境

### マシン

2022年に中古で購入した、安価なマシンです。2万円程度で買えました。

* 機種: Lenovo ThinkCentre M710q
* CPU: Intel Core i5-7400T CPU @ 2.40GHz
* メモリ: 8GB
* ストレージ: SATA SSD 500GB

ストレージは、購入時はHDD 500GBでしたが、Ubuntu Serverをインストールするにあたり、手持ちのSSD 500GBに換装しています。

### OS

Ubuntu Server 22.04 LTSを対象としています。

```
# lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 22.04.2 LTS
Release:        22.04
Codename:       jammy
```

### ネットワークについて

* NIC
    * 有線LANを使用している。ブリッジ接続を行うため
    * インターフェース名はenp0s31f6
    * IPアドレスは192.168.1.4
* ルーター
    * IPアドレスは192.168.1.1
* プロトコル
    * IPv4を使用している
    * IPv6は使用していない

### UIについて

Ubuntu Serverを使っているので、仮想マシンの操作も含め、全てCUIで操作します。そのため、CUIで仮想マシンを操作するためのパッケージを合わせてインストールするものとします。

## 実際に行った手順

### 必要なパッケージのインストール

```bash
$ sudo apt-get install qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils virtinst libosinfo-bin
```

#### 指定したパッケージについて

* qemu-kvmはメタパッケージで、KVMを実行するために必要なQEMUパッケージをインストールしてくれるものだとのこと
    * qemu-kvmというパッケージがインストールされるのではなく、マシンに合わせたQEMUのパッケージを選んでくれる
    * 今回はqemu-system-x86というパッケージが選ばれてインストールされた
* libvirt-daemon-system、libvirt-clientsは、仮想化アプリケーション、ハイパーバイザーを抽象的に操作できるようにしてくれるlibvirtのパッケージ
* bridge-utilsは、ブリッジの設定を確認するパッケージ
    * NetworkManagerが出てくるまでは、bridge-utilsパッケージに含まれるbrctlコマンドでブリッジを作成していた
    * UbuntuのようにNetworkManagerやsystemd-networkdを使う場合はbrctlコマンドは不要だが、bridge-utilsパッケージをインストールしておくとブリッジの設定を確認するのに便利なコマンドが使えるようになる
* virtinstは、CUIで仮想マシンをインストールする際に必要なvirt-installコマンドが含まれているパッケージ
* libosinfo-binは、virt-installコマンドで--os-variantオプションを使用するために必要なパッケージ

### ブリッジの設定ファイルの編集

インターフェース名やIPアドレスは各自の環境に置き換えてください。

`br0`という名前のブリッジを作成します。

```bash
$ cd /etc/netplan
$ sudo vi 00-installer-config.yaml
# This is the network config written by 'subiquity'
network:
  ethernets:
    enp0s31f6:
      dhcp4: false
      dhcp6: false
  bridges:
    br0:
      interfaces:
        - enp0s31f6
      dhcp4: false
      addresses:
        - 192.168.1.4/24
      routes:
        - to: default
          via: 192.168.1.1
      nameservers:
        addresses:
        - 192.168.1.1
        search: []
  version: 2
```

### ブリッジを作成する

```bash
$ sudo netplan apply
```

### ブリッジの確認をする

`br0`が作成されていれば正常です。

```
$ brctl show
bridge name     bridge id               STP enabled   interfaces
br0             8000.12077df08059       no            enp0s31f6
docker0         8000.0242e8da5adf       no            veth8a07389
virbr0          8000.525400bc7587       yes
```

ここまでの作業で、KVMで仮想マシンの作成や起動・停止などの操作が行えるようになっています。

## 仮想マシンの操作

仮想マシンの操作は`virsh`コマンドで行います。

ここでは仮想マシンの作成・起動・停止を紹介します。

### 仮想マシンの作成

ここではRHEL 8.4のBoot ISOイメージ（最小限のインストール用ISOイメージ。必要なパッケージはインストール中にネットワークからダウンロードする代わりに、DVD ISOイメージよりはサイズが小さい）を使って、仮想マシンを作成します。

https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/8/html/system_design_guide/downloading-beta-installation-images_preparing-for-your-installation

```
# virt-install \
--name rhel8 \
--description "RHEL 8.4" \
--ram 2048 \
--disk path=/var/lib/libvirt/images/rhel8.img,size=20 \
--vcpus 2 \
--os-variant  rhel8.4 \
--network bridge=br0 \
--graphics vnc,listen=0.0.0.0,password=password,keymap=ja \
--video virtio \
--cdrom /tmp/rhel-8.4-x86_64-boot.iso
```

主なオプションについて。

<dl>
  <dt>--name</dt>
  <dd>仮想マシンの名前。virshコマンドで操作する仮想マシンを指定する際の名前となる。</dd>
  <dt>--ram</dt>  <dd>仮想マシンのメモリサイズ。MB単位で指定する。</dd>
  <dt>--disk</dt>
  <dd>仮想マシンのストレージ。<br>
      pathでストレージの保存先、sizeでストレージのサイズ（単位はGB）を指定する。</dd>
  <dt>--vcpus</dt>
  <dd>仮想マシンが使用するコア数を指定する。</dd>
  <dt>--os-variant</dt>
  <dd>仮想マシンのOSに合わせたOS名を指定する。<br>
      指定可能な値はosinfo-queryコマンドで確認する。RHEL 8.4のOS名は「rhel8.4」だった。<br>
      osinfo-queryコマンドは、libosinfo-binパッケージに含まれている。</dd>
  <dt>--network</dt>
  <dd>仮想マシンが使用するNICを指定する。本例ではブリッジ（br0）を指定している。</dd>
  <dt>--graphics</dt>
  <dd>仮想マシンのグラフィックの設定。<br>
      vncでVNCサーバーを起動する。VNCクライアントで接続できるので、OSのGUIインストーラーを操作できる。<br>
      listenはVNCサーバーがリッスンするIPアドレス。<br>
      passwordはVNCサーバーに接続する際のパスワード。<br>
      keymapはキーボードのキーマップ。jaを指定すると日本語配列になる。
  </dd>
  <dt>--cdrom</dt>  <dd>仮想マシンで使用するCD-ROMのデバイスを指定する。<br>
      ISOファイルが指定できるので、インストール用ISOファイルを指定する。</dd>
</dl>

### 仮想マシンの操作例

```
// 仮想マシンの一覧
// 起動しているマシンがないと、なにも表示されない
# virsh list
 Id   Name   State
--------------------

// 停止している仮想マシンまで表示させるには --all オプションを付ける
# virsh list --all
 Id   Name         State
-----------------------------
 -    rhel8        shut off

// 仮想マシンを起動する
# virsh start rhel8
Domain 'rhel8' started

// 仮想マシンのコンソールに入る
// 仮想マシンのコンソールから抜けるには Ctrl + ]
# virsh console rhel8

// 仮想マシンを停止する
# virsh shutdown rhel8
Domain 'rhel8' is being shutdown
```

## まとめ

KVMを操作するために必要なパッケージがわかり、ブリッジの作成が行えれば、意外と簡単にKVMで仮想マシンが作成できることがわかりました。