えんでぃの技術ブログ

えんでぃの技術ブログ

ネットワークエンジニアの視点で、IT系のお役立ち情報を提供する技術ブログです。

KVMの初期設定、及びvirsh, virt-installによるVM作成

linux-kvm-logo
引用元:linux-kvm.org

前の記事

前回はKVM, QEMU, libvirt の概要について紹介しました。

endy-tech.hatenablog.jp

お伝えしたいこと

本記事では、KVM+QEMUによる仮想化システムのインストール手順と、libvirt CLI (virt-install, virsh) によるVM作成手順を紹介します。
その後、KVMが本当に正しく構成されているのかを確認する手順と、正しく構成されていなかった場合の対処法について紹介します。

libvirtベースのCLI/GUIツールの概要については、前の記事のlibvirt を利用している製品を先にお読みください。
libvirt ベースのGUIツールについては、次の記事で紹介します。

QEMUKVMlibvirt のインストールは非常に簡単です。
ただ、libvirtの初期設定、使い方、KVMが動かない時のトラブルシューティングを含めた結果、記事が長くなってしまいました。
手順上読まなくても問題ない部分には (参考) をつけましたので、不要と感じたら読み飛ばしてください。

本記事の末尾にオススメの解説動画も貼りました。
Arch Linux をモデルとした内容ですが、本記事と同様の紹介がされています。
文字よりも動画がお好みの方は、ぜひチェックしてみてください。
動画中の解説は英語です。
日本語がお好みでしたら、やはり私の記事を読んでください!

QEMUのインストール手順

以下のコマンドで、KVMに対応したCPUアーキテクチャ (x86) に対応するQEMUをインストールします。

sudo dnf install qemu-kvm

KVMのインストール手順

KVMLinuxカーネルモジュールとして初めから組み込まれているので、インストールは不要です。

KVMの動作確認 (1/2)

さて、ここでKVMの動作確認をします。
KVMの動作確認は2段階に分けて行います。

まず、ここではKVMとCPUの仮想化支援機能に関わるカーネルモジュールがそれぞれロードされていることを確認します。
以下のコマンドを実行してください。

lsmod | grep kvm

# kvm_intel             319488  0
# kvm                   823296  1 kvm_intel
# irqbypass              16384  1 kvm

上述のように、kvmkvm_intel、またはkvmkvm_amdのいずれかが表示されれば、まず問題ありません。
もしkvmkvm_intelが表示されない場合は、(参考) KVMが動作しない場合のトラブルシューティングにて問題を解消してください。

その上で、VMを1つも起動していないときはkvm_intel、またはkvm_amd の行の一番右の列が 0 であることを確認してください。
これは、kvm_intel、またはkvm_amdモジュールが他のプログラムによって利用されていないことを表しています。

この後、VMを実際に作成・起動した上でもう一度lsmodコマンドを実行します。
その状態で、kvm_intel、またはkvm_amd行に対応する数値が1以上の値になっていれば、KVMは正しく動作していることになります。
VM起動後に行うKVMの動作確認は、KVMの動作確認 (2/2)にて実施します。

コンソール接続用アプリケーションのインストール

VMにコンソール接続するためのアプリケーションをインストールします。
アプリケーションはGUIのプログラムであるため、Linux上で使う場合はGUI (デスクトップ環境やWindow Manager) が必要です。
KVMLinuxで動作させつつリモートのWindowsからコンソール接続する構成であれば、Windows側にRemote Viewerを入れるのに特に制限はありません。

ここでインストールしたアプリケーションは、後に#(参考) VMへのコンソール接続で使うことになります。

Virtual Machine Viewer のインストール

Virtual Machine Viewerは、VMにコンソール接続して画面表示するGUIツールです。
従って、GUI環境がなければ起動できません。

KVM仮想化を提供しているマシンがローカルで動作している場合には導入を推奨します。
または、libvirtのconnectionでネットワーク越しにKVMサーバに接続している構成でも、Virtual Machine Viewerを使えます。

以下のコマンドでインストールします。

sudo dnf install virt-viewer

Remote Viewer のインストール

アクセス元のLinuxから見てKVM仮想マシンがリモートで起動している場合は、Remote Viewerで接続します。
SPICEやVNCなどのプロトコルにより、ネットワーク越しにコンソール接続します。
Remote Viewerを使う際もGUI環境が必要です。

余談ですが、Cockpitをお使いの方もGUI操作でコンソール接続する際、Remote Viewerがあると便利です。

localhostを指定することでローカルの仮想マシンにも接続できますが、ローカルの場合はVirtual Machine Viewerの方が使い勝手が上です。

以下のコマンドでRemote Viewerをインストールします。

sudo dnf install remote-viewer

アクセス元がWindowsの場合は、Windows版のRemote Viewer を以下の公式サイトからダウンロード、インストールします。
virt-viewerと記載がありますが、これをインストールすると実際にはRemote Viewerもインストールされます。
https://virt-manager.org/download/

libvirtの初期設定

CLIVMを作成する

今回は、デスクトップ環境がなくても動作するCLIにて今回は進めたいと思います。

必要に応じて、GUIツールを後から追加インストールすることも可能です。
どのGUIツールをインストールしたとしても、必ず依存関係でCLIツールもインストールされます。
一旦GUIツールのことは気にしないこととして、先に進みましょう。

libvirtのインストール

以下のコマンドでlibvirtをインストールします。
libvirtvirt-installは導入必須です。
virt-topは任意なので、不要と感じたらスキップしても問題ありません。

# 必須
sudo dnf install libvirt virt-install

# 任意
sudo dnf install virt-top

インストールの内訳は以下の通りです。

パッケージ名 中身
libvirt libvirtdCLI/GUIツールからハイパーバイザー (QEMU+KVM) にAPI連携する
virshコマンドにより、Disk,仮想NWを作成する
・同コマンドでVMを起動・停止・削除する
virt-install virt-installコマンドにより、VMを新規作成する
virt-cloneコマンドでVMをクローンする
virt-top virt-topコマンドにより、VMのCPU,RAM,Disk利用状況を可視化する

libvirtdの起動

以下のコマンドでlibvirtd の自動起動を有効化しつつ、今すぐ起動します。
libvirtベースのツールは、libvirtdを介してハイパーバイザーを操作するので、libvirtdの起動は必須です。

sudo systemctl enable --now libvirtd.service

ユーザーグループの設定

libvirtqemu:///systemセッションで使うにあたり、libvirtを利用するユーザーをlibvirtグループに所属させる必要があります。
qemu:///system の意味については(参考) qemu:///system と qemu:///session の違いで、グループ設定が必要な理由は1. libvirtグループへの所属で補足します。

以下のコマンドによって、現在のユーザーがlibvirtd特権プロセスにアクセスするための権限を付与します。

sudo usermod -aG libvirt "$USER"

(任意) qemu:///system をデフォルトにする

デフォルトでは、virsh uriを実行するとqemu:///sessionと表示されます。
これはvirshなどのlibvirt関連コマンドを実行したときにqemu:///session、つまり「一般ユーザー権限でローカルホストに接続している」ことを表しています。
このデフォルト挙動を上書きするためには、virsh --connect qemu:///system uriのようにコマンドラインオプションを指定する必要があります。

しかし毎回 --connect を指定するのは面倒なので、設定ファイルでデフォルト挙動を上書きしちゃいましょう。

~/.config/libvirt/libvirt.confを作成し、設定情報を記述します。

mkdir -p ~/.config/libvirt/
echo 'uri_default = "qemu:///system"' > ~/.config/libvirt/libvirt.conf

以下のコマンドにより、QEMUが接続するハイパーバイザーのURIがデフォルトでqemu:///systemになっていることを確認します。

virsh uri
# qemu:///system

以下のようにエラーが出た場合、#libvirtdの起動の手順を忘れている可能性があります。
リンク先を参照して対処してください。

virsh uri
# error: failed to connect to the hypervisor
# error: Failed to connect socket to '/var/run/libvirt/virtqemud-sock': No such file or directory

最後に補足しますが、Virtual Machine Managerのデフォルト値はqemu:///systemです。
Virtual Machine Managerとvirshで見えるVMやpoolなどが異なる場合は、利用しているConnectionが異なる可能性があるので注意してください。
このあたりは最初にハマりがちな罠だったりします。
あまり本質ではないかもしれませんが、こういった罠を回避するためにも、qemu:///systemにデフォルト値を寄せるとわかりやすくて良いかなと個人的に思います。

Virtual Machine Manager側の設定方法については、Virtual Machine Manager GUI によるKVM操作 #URIの指定を参照してください。

(参考) デフォルトURI決定の優先順位

デフォルトのURIは、以下の優先順位で探索されます。

  1. 環境変数LIBVIRT_DEFAULT_URI
  2. クライアント設定ファイル:uri_default = "qemu:///system"
  3. 応答があるまで、各種ハイパーバイザーを順に試す

ここでは、「2. クライアント設定ファイル」によって指定します。
クライアント設定ファイルは、以下の2箇所に配置します。

  • rootユーザ用:/etc/libvirt/libvirt.conf
  • 一般ユーザ用:$XDG_CONFIG_HOME/libvirt/libvirt.conf~/.config/libvirt/libvirt.conf

man libvirtdによると、$XDG_CONFIG_HOMEが未定義の場合は、$HOME/.config/になるようです。
従って、今回更新すべきファイルは~/.config/libvirt/libvirt.confということになります。

pool作成の事前準備

VMを作成する前に、poolの設定を変更します。
poolには、VMのディスクイメージファイル (*.qcow2) や、ISOイメージファイルの保管場所を設定します。
本来はstorage poolが正しい呼び方なのですが、本記事においては省略してpoolと呼ぶことにします (man virshでもしばしばpoolと省略表記されます)。

さて、poolを作成する事前準備として、まずディレクトリをどこにするか決めます。
詳細は2. イメージファイルのパーミッションに後述しますが、VM作成に必要なISOイメージファイルや、VMのディスクイメージファイルはqemuユーザーによってアクセスできるようパーミッションを設定する必要があります。
それを踏まえて、事前に保存先のディレクトリをどこにするか決めておいてください。

今回は、/home/shared/libvirt/disks/にディスクイメージファイルを、/home/shared/libvirt/isos/にISOイメージファイルを保存します。
/home/shared/libvirt/isos/配下は、rhelubuntuなどのOS/ディストリビューション名でフォルダ分けする想定です。
/home/sharedは、sharedグループに属するユーザーであれば誰でもアクセス可能なディレクトリとして作成します。

(※) 私の環境はパソコン用途を想定しているため、/homeファイルシステム容量を大きくしています。したがって、/home配下にイメージファイルやVMDKファイルなどの大容量ファイルを置くために、今回のようなフォルダ構成としました。なおご参考までに、libvirt-daemon RPMパッケージをインストールすると/var/lib/libvirt/imagesをデフォルトで生成します。今回のフォルダ構成は自分なりにアレンジを加えたものの、libvirt/images/というフォルダの切り方はデフォルト構成を踏襲しました。ファイルシステムの設計は皆様それぞれだと思いますので、自分の環境にあった置き場所をご検討ください。

以下のコマンドで上述の構成にできますので、よろしければそのままご利用ください。

# sharedグループを作成し、qemuと一般ユーザーを加える
sudo groupadd shared
sudo usermod -aG shared "$USER"

# ディレクトリを作成する
sudo mkdir -p /home/shared/libvirt/disks
sudo mkdir -p /home/shared/libvirt/isos

# 最低限の権限設定
sudo chown -R root:shared /home/shared
sudo chmod -R ug+rw /home/shared

pool作成

pool作成に先立ち、既存のpoolを確認します。
既存でdefaultというpoolがある場合、これから行うpool作成コマンドは失敗します (同名のpoolは複数作成できないため)。

# show pool list
virsh pool-list

# show pool configuration
virsh pool-dumpxml default | grep path
    # <path>XXX</path>

ということで、必要に応じてdefault poolを先に消しておきましょう。

# stop the pool
virsh pool-destroy default

# delete the pool
virsh pool-undefine default

続いてpoolを定義 (define) します。
このコマンドによりpoolの構成情報を記述したXMLファイルが生成し、libvirtによって管理されるようになります。
本記事はvirshの紹介記事なのでCLIで実施していますが、GUI環境があればvirt-managerやcockpitからもpoolの作成は可能です。

virsh \
pool-define-as default dir \
--target /home/shared/libvirt/disks/

defineやdestroyなどのlibvirt用語について知りたい方は、(参考) libvirt (virsh) の用語も参照してください。

(参考) pool作成コマンドの補足

コマンドの意味について補足します。
不要な方は読み飛ばしてください。

まず、syntax は以下のようになります。

virsh \
pool-define-as <pool-name> <type> \
--target <target-path>

各キーワードの意味は、以下のようになります。

<pool-name>は、poolの名前です。
KVMのイメージファイルを格納するpoolとして、defaultを作成することをお勧めします。
その理由は、2つあります。

  • Virtual Machine Manager (GUI)が起動時に default というプールを勝手に作ってしまうため
  • 他のvirshコマンドでも、pool名の指定を省略した場合にdefaultを自動的に指定するものがあるため

<type>は、ファイルの置き場所によって変わります。
ローカルの特定ディレクトリをpoolとして使用し、ディレクトリ配下にイメージファイルを格納する場合はdirを指定します。
その他の type に関する情報は、libvirt公式サイトに情報がありますが、dir以外はあまり使わない印象です。

--targetは、type=dirの場合に使用するオプションで、poolと対応するディレクトリパスを指定します。
--typeに指定する値によって指定すべきオプションが変わるので、CLIだと結構わかりづらいです。
Cockpit操作であればGUIの選択肢がtypeに応じて良い具合に切り替わるので、このあたりが直感的に操作できて便利です。

poolの起動・自動起動設定

virsh pool-define-asはpoolを作成しただけで起動はしていません。
poolの起動、及びOSと共に自動起動する設定も必要です。

Linuxのデーモンに対して systemctl enablesystemctl start するのと似たような考え方ですね。

virsh pool-start default
virsh pool-autostart default

poolの確認

最後に、作成したpoolを確認します。

poolを一覧表示するには、pool-list を使います。
デフォルトでは起動していないpoolが表示されないので、全て表示したい時は --all もつけます。
--details で詳細表示できます。

poolの完全な設定情報を確認したい場合は、pool-dumpxmlを使います。

virsh pool-list
virsh pool-dumpxml default

(参考) poolの停止・削除

この手順は基本実施不要です。
もしpoolを間違えて作ってしまい、削除したくなったときは以下の流れで実施します。

  • poolの停止 (destroy)
  • poolの削除 (undefine)

補足ですが、VMの通常停止を shutdown、強制停止(VMのプロセス kill) をdestroyと呼びます。
poolの停止の場合は、常に destroy と呼ばれます。

VM/poolの削除は undefine と呼びます。
pool作成時に実施した define の反対で、XMLファイルを削除します。
削除操作は、対象を停止させた上で実施する必要があります。

コマンドとしては、以下のようになります。

# virsh pool-destroy <pool-name>
# virsh pool-undefine <pool-name>

ISOファイルの準備

VMを作成するのに必要なISOファイルをダウンロードし、/home/shared/libvirt/isos/配下に格納してください。
個人的には、/home/shared/libvirt/isos/fedora/xxx.isoのようにOS/ディストリビューション名でフォルダを分けて整理するのが好きです。

ディレクトリの権限を設定する

ここで/home/shared/libvirt/配下に格納したファイルやディレクトリの権限設定を一括で書き換えます。

後続のセクションではvirt-installコマンドによりVMを作成します。
virt-installコマンドを実行すると、libvirtdを介してqemu系のコマンドが実行されます (qemu-kvmqemu-system-x86_64など)。
そしてqemuコマンドが正しく動作するためには、VMを構成する各種ファイルに対してqemuユーザーがアクセスできる必要があります。

では、必要な設定を以下に示します。

sudo chown -R root:shared /home/shared

sudo chmod -R ug+rw,o-rwx /home/shared
find /home/shared -type d | sudo xargs -I{} chmod ug+x {}

sudo setfacl -Pm u:qemu:rwx /home/shared
sudo setfacl -PRm u:qemu:rw /home/shared/libvirt/
find /home/shared/libvirt/ -type d | sudo xargs setfacl -Pm user:qemu:rwx

こちらの設定により、以下のように権限設定されます。

  • /home/shared/ディレクトリ配下はuserとgroupに対して読み書き権限が付与される
  • qemuユーザーは/home/shared/libvirt/配下にアクセスできる。/home/shared/配下のその他共有ファイルにはアクセスできない

chownchmodではこのような権限構成を表現しきれないので、今回はsetfaclコマンドを活用しました。
setfaclは、いわゆるLinux ACLを設定するコマンドです。
詳しくは@ITの【 setfacl 】コマンド(応用編その1)――デフォルトのアクセス制御リスト(ACL)を設定するが参考になります。

/home/shared/配下にファイルを配置するたびに毎回コマンドを実行するのは大変なので、私は/home/shared/set_permissions.shに以下のシェルスクリプトを配置しています。
ファイルを配置するたびにシェルスクリプトを実行すれば良くなるので楽だと思います。
よろしければご活用ください。

#!/bin/bash

# Try to cache sudo credentials first
if ! sudo true; then
    echo 'Failed to obtain root priviledges.'
    exit 1
fi

sudo chown -R root:shared /home/shared

sudo chmod -R ug+rw,o-rwx /home/shared
find /home/shared -type d | sudo xargs -I{} chmod ug+x {}

sudo setfacl -Pm u:qemu:rwx /home/shared
sudo setfacl -PRm u:qemu:rw /home/shared/libvirt/
find /home/shared/libvirt/ -type d | sudo xargs setfacl -Pm user:qemu:rwx

VMの作成

VMを作成するには、以下のコマンドを実行します。
紹介しているコマンドは例ですので、環境によって一部変更してください。

virt-install \
--name test \
--memory 1024 \
--vcpus 2 \
--disk size=8 \
--graphics spice \
--graphics vnc \
--cdrom /home/shared/libvirt/isos/fedora/Fedora-Server-dvd-x86_64-32-1.6.iso \
--os-variant fedora32 \
--noautoconsole

コマンドラインオプションの意味については、次の(参考) VM作成コマンドの補足を参照してください。

VMの作成コマンド実行時に警告やエラーが出た場合は、(参考) virt-install コマンドの WARNING/ERROR 対策を参照してください。

(参考) VM作成コマンドの補足

virt-installのオプションの意味を補足します。
補足が不要な方は読み飛ばしてください。

情報源はman virt-installです。

オプション 意味
--name VM_NAME 作成するVMの名前を指定する
--memory MEM_SIZE VMのメモリサイズをMiB単位で指定する
--vcpus CPU# 仮想CPUコア数を指定する
--disk size=VOL_SIZE 仮想ディスクのサイズをGiB単位で指定する
--graphics spice 仮想コンソールを作成し、VMにSPICEプロトコル用のポート番号をlistenさせる (※)
--graphics vnc 仮想コンソールを作成し、VMVNCプロトコル用のポート番号をlistenさせる (※)
--cdrom PATH_TO_ISO VMのOSをインストールするためのイメージファイル (ISO) へのフルパスを指定する
--os-variant OS (Distribution) の名前と紐づく値をセットする。
指定することで、libvirtdが指定したOSに最適な仮想ハードウェア (特にvirtio) を選択する
このパラメータは必須ではないが、正しく設定することで性能が著しく向上する。
指定を省略した場合、ISOファイルをURL指定で取ってくる場合のみ自動認識される。
--os-variant に指定可能な文字列は、osinfo-query osコマンドにより確認可能
--noautoconsole VM作成直後にVirtual Machine Viewer (virt-viewer) のコンソールを自動的に開かないようにする。
このオプションを入れない場合、コマンド末尾に&を付けてバックグラウンド実行とすることで、Virtual Machine Viewerが起動した後にプロンプトが戻ってくるようにするのが良い

(※) virt-viewerでローカルコンソール接続する場合は不要ですが、remote-viewerによってリモートからコンソール接続する場合はSPICEかVNCが必要です。今回は別に指定する必要はないのですが、ユースケースによっては利用することもあり得るので敢えて含めておきました

VMの起動確認

VMが起動していることを確認します。
--allオプションをつけると停止しているVMも含めて表示されます。

virsh list

KVMの動作確認 (2/2)

ここまでの手順でVMが起動できているはずですので、KVMの動作確認をします。
KVMの動作確認 (1/2)でも触れたとおり、KVMが正しく動作していれば、kvm_intel、またはkvm_amdカーネルモジュールの利用回数の部分が1以上の値になっているはずです。

以下のコマンドを実行してください。
kvm_intel に対応する一番右の値が 4 になっています。
この数字が1以上なので、KVMは正しく動作しています。

lsmod | grep kvm

# kvm_intel             319488  4
# kvm                   823296  1 kvm_intel
# irqbypass              16384  1 kvm

本セクションでKVMの動作確認ができたら、VMの削除を参照しつつ、動作確認用のVMを削除します。
ここまで問題なく完了したら、KVMのセットアップは完了です。
お疲れ様でした。

【重要】動作確認時の注意

KVMが正しく動作して作成したVMと、KVM利用に失敗してQEMU (TCG: Tiny Code Generator) にフォールバックして作成されたVMは、完全に別物と理解してください。

実際に試してみたところ、以下のような挙動になりました。

  • qemuで作成したVM
    • KVMが無効でも有効でもVMを起動できる
    • KVMが利用可能な状態でVMを起動しても、QEMU単体 (TCG) で起動する
  • kvm+qemuで作成したVM
    • KVMが利用可能な場合は、通常通り起動する
    • KVMが利用できない場合は、エラーが出て起動しない

特に重要なのは前半の事実で、トラブルシューティングが完了してKVMが利用可能となった後に、QEMUベースで作成したVMを起動しても、kvm_intel、またはkvm_amdの使われている数は0のままということです。

KVMトラブルシューティングをした後は、必ずVMを作り直した上で動作確認してください。

(参考) VMへのコンソール接続

この手順は、LinuxGUI環境 (≒デスクトップ環境) をインストールした方のみが実行可能な手順です。
CLI、またはGUIによってVirtual Machine Viewerを起動し、コンソールログインします。

Virtual Machine Viewerは、基本的にlibvirtで接続したサーバー (--connect qemu:///system) に対してローカルな接続を提供します。
言い換えると、基本的にlocalhostに対するコンソール接続に使います。

リモートで実行しているKVM仮想マシンにコンソール接続したい場合は、Remote Viewerを使用します。

Virtual Machine Viewer (CLIから起動)

まずはCLIからの起動手順を紹介します。
以下のコマンドを実行するだけです。

virt-viewer &

すると、以下の画面から起動中のVMが表示されるので、選択して接続します。

virt-viewer1

成功すれば、コンソール画面が表示されます。

virt-viewer2

以下のように、VM名を引数として指定することでVMを明示的に指定することも可能です。

virt-viewer test &

普段CLIKVMを操作する方は、virsh startVMを起動した後、virt-viewer &でコンソール接続する使い方が動線としてはスムーズかなと思います。

なお、多くのLinuxデスクトップ環境ではAlt+F2でコマンド実行できるショートカットキーがあるのではないかと思います。
もしその機能が使える場合、GUIからvirt-viewervirt-viewer testと実行する方がおすすめです。
その場合、ターミナルで実行するのと比べて余計なコンソールログが表示されない分見た目がきれいになります。

Virtual Machine Viewer (GUIから起動)

GUIのMenuからVirtual Machine Viewerを起動して接続することもできます。
以下のように、Menuから検索して起動するだけです。

virtual_machine_manager_on_the_menu

環境によっては、検索してもヒットしないこともあります。

多くのGUIアプリケーションは、Menuから起動するために必要なDesktop Entry (*.desktopファイル) を/usr/share/applications/配下などに自動配置するため、Menuから問題なく起動できます。
しかし、私の環境 (Fedora35 + Cinnamon Desktop) ではVirtual Machine Viewerのdesktopファイルが自動配置されなかったので、手動で作成します。

以下のテキストファイルを~/.local/share/applications/virt-viewer.desktopに配置してください。
そうすれば、デスクトップ環境のMenuからVirtual Machine Managerを開けるようになるはずです。
再ログインする必要はありません。

[Desktop Entry]
Name=Virtual Machine Viewer
Exec=virt-viewer
Comment=Display the graphical console
Terminal=false
Icon=virt-viewer
Type=Application

Desktop Entryについてより詳細を知りたい方は、以下の記事を参照してください。

endy-tech.hatenablog.jp

(参考) Remote Viewer

Remote Viewerとは、Remote Desktopのようなリモート接続のウィンドウを出すプログラムです。
KVMをリモートサーバーで動かしているときに使うことがあるので、参考までにやり方を書いておきます。

今回の例では私の環境の都合でlocalhostにRemote Viewerで接続していますが、基本的な考え方は同じです。

まず、Remote Viewerを使いたい場合は以下のコマンドでRemote Viewerをインストールしておきます。

sudo dnf install remote-viewer

そして、以下の手順で接続します。

まず、コンソールアクセスするためのURLを先に確認します。
1台目の起動であれば、spice://127.0.0.1:5900 と表示されます。
2台目であれば、spice://127.0.0.1:5901 とポート番号が1刻みで増えます。
慣れれば確認するまでもなくポート番号が予想できます。

virsh domdisplay test
# spice://127.0.0.1:5900

デスクトップのメニューから "Remote Viewer" で検索し、Remote Viewerを起動します。
そして、出てきたウィンドウに上記URLを入力して接続します。

virt-viewer3

成功すれば、コンソール画面が表示されます。

virt-viewer2

以下のようにCLIからRemote Viewerを起動することも可能です。

remote-viewer
# または
remote-viewer spice://localhost:5900

ポート番号の指定など面倒なので、ローカル接続にはVirtual Machine Viewerを使うことをおすすめします。

(参考) Cockpit からの起動

Cockpitの画面でVM名をクリックし、「Launch Remote Viewer」を選択するとdownloadという名前のファイルがダウンロードされます。
このファイルをクリックして開けば、Remote Viewerが開きます。

downloadファイルは、開いた直後に自動的に削除されるので、基本的にフォルダが汚れることはありません。
とても優秀です。

詳しくは、次の記事で紹介します。

VMの削除

まず、削除対象のVMを停止します。
VMの停止は、以下の2種類があります。

  • 通常停止(shutdown): VMにshutdown するよう命令を送る
  • 強制停止(destroy): VMプロセスを kill する (≒電源長押しによる停止)

強制停止は、何らかの理由で (※) 通常停止ができない場合のみ使うイメージです。
経験上、作成したばかりのVMでOSが未インストールの場合はshutdownを受け付けないので、destroyで強制停止します。
これから削除するVMに対しては、気軽に強制停止しても問題ありません。
(※) VMが無応答だったり、KVMではなくQEMU単体で動作している場合はshutdownできないこともあります

virsh shutdown test
# または、virsh destroy test

VMが停止したことを以下のコマンドで確認します。

virsh list test

VMを削除する時に気をつけたいのは、オプションを指定しない限り、VMに紐づくディスクファイルは削除されないことです。
オプションを指定するために、まずは以下のコマンドでブロックデバイス名を調べます。
ちなみに、VMのことをlibvirt用語でdomainとも呼びます。
domblklistは、"list domain's block files" という意味になります。

virt-install--os-variants を指定した場合は、最適な仮想ハードウェアとしてvda (virtio) が選択されているはずです。
逆に--os-variants を指定しなかった場合は、低速なhda (仮想IDE) が選択されます。

virsh domblklist test

続いて、以下の手順では、--storage オプションを指定することで、VMに紐づくディスクファイル(qcow2) も一緒に削除するようにしています。
--snapshots-metadata--managed-save は、関連するスナップショットや保存データも削除するオプションです。
スナップショット作成やVMの保存をしていなければ特に意味はありませんが、不要データを綺麗に削除するために指定しても損はないと思います。
--remove-all-storage は、virsh domblklist でISOファイルが表示されていた場合、ISOファイルまで削除されてしまうので、このオプションはあまり使いません。

# "vda" の部分は、virsh domblklist の出力によっては "hda" に変更する
virsh \
undefine \
--domain test \
--storage vda \
--snapshots-metadata \
--managed-save

(参考) virt-install コマンドの WARNING/ERROR 対策

virt-install コマンド実行時、警告メッセージが出ることがあります。
ここでは、警告のメッセージについて対処法を補足します。
警告が出なかった場合は読み飛ばして結構です。

WARNING KVM acceleration not available, using 'qemu'

このメッセージが出たら、KVMが正しく動作していません。
KVMの動作確認 (2/2)からKVMが動作していないことを確認できたら、(参考) KVMが動作しない場合のトラブルシューティングで原因調査の上、対処してください。

XXX may not be accessible by the hypervisor.

具体的には、以下のようなメッセージです。

WARNING  /home/shared/libvirt/isos/fedora/Fedora-Server-dvd-x86_64-32-1.6.iso may not be accessible by the hypervisor. 
You will need to grant the 'qemu' user search permissions for the following directories: ['/home/shared']

このメッセージが出た場合、その下のメッセージを確認してください。
以下のメッセージが続いていたら、VMは作成できているので無視しても問題ありません。

Starting install...
Allocating 'test.qcow2'
Domain installation still in progress. 
You can reconnect to the console to complete the installation process.

このメッセージは、libvirt側でイメージファイル(iso)、またはディスクファイル(qcow2) へのアクセス権限があると断定できない場合に発生します。
#ディレクトリの権限を設定するを再度実行することで対処ください。

なお上述の手順を実行せずともqemuユーザーをsharedグループに所属させることでも楽に権限を与えることはできるのですが、グループではなくユーザーに権限がないとエラーメッセージが発生してしまいます。
エラーメッセージが発生してもVMは作成できるのですが、なんだかもやもやしますよね。
なので私はACLによってユーザーに権限を与えるようにしています。

ERROR Guest name 'test' is already in use.

既に 'test' という名前のVMが存在しています。
virsh list --all で確認できます。

対処方法はVMの名前を被らないようにするか、VMを削除することが挙げられます。

VMを削除する場合は、事前にブロックデバイス名を確認します (vda/hda)。

# ディスクファイル (qcow2) がhdaかvdaかを確認する
virsh domblklist test

続いて、VMを削除します。
その際、--storageオプションで一緒に削除したいブロックデバイス名を指定します(vda/hda)。

# "vda" の部分は、必要に応じて "hda" に変更する
virsh destroy test
virsh undefine --storage vda test

(参考) KVMが動作しない場合のトラブルシューティング

本記事の手順を実施してもKVMが動作しなかった場合は、以下の情報を参考にしてみてください。
私の環境 (NUC10+Fedora32) では運良く全くトラブルが発生しなかったので、紹介する内容は全て未検証であり、机上で調査した情報になります。

KVMの動作要件

KVMを利用するには、以下の条件を満たしている必要があります。

  1. CPUが仮想化支援機能をサポートしていること
  2. BIOSが仮想化支援機能を無効化していないこと
  3. KVMカーネルモジュールがロードされていること
  4. /dev/kvmの権限が正しく設定されていること

上記動作要件それぞれについて、以下で確認方法と対処法を紹介します。

(参考) まずは確認ツールを実行してみる

libvirtに同梱される確認ツールを実行することで、QEMU (+KVM) の動作要件を満たしているか確認できます。

  • PASSがついていれば問題なし。
  • WARNがついていても、恐らく動作します
  • FAILがついている場合は、恐らく正しく動作しません

WARNとFAILの解釈は、私の推測です。
確認ツールの動作について、manを確認したり、libvirt.org内を検索したのですが、情報は得られませんでした。
とはいえ、libvirt公式のvalidation tool ですし、ツールを実行するだけで問題解決のヒントを得られるので気軽に実行してみるのが良いと思います。

確認ツールの実行

確認ツールを実行します。
私の環境 (Fedora32) の出力も貼っておきます。
いくつかWARNがあるものの、FAILが一つもないので問題無さそうです。
※実際、KVMの動作確認 (2/2)KVMが動作していることを私の環境で検証済みです

virt-host-validate qemu
  # QEMU: Checking for hardware virtualization             : PASS
  # QEMU: Checking if device /dev/kvm exists               : PASS
  # QEMU: Checking if device /dev/kvm is accessible        : PASS
  # QEMU: Checking if device /dev/vhost-net exists         : PASS
  # QEMU: Checking if device /dev/net/tun exists           : PASS
  # QEMU: Checking for cgroup 'cpu' controller support     : WARN (Enable 'cpu' in kernel Kconfig file or mount/enable cgroup controller in your system)
  # QEMU: Checking for cgroup 'cpuacct' controller support : PASS
  # QEMU: Checking for cgroup 'cpuset' controller support  : WARN (Enable 'cpuset' in kernel Kconfig file or mount/enable cgroup controller in your system)
  # QEMU: Checking for cgroup 'memory' controller support  : PASS
  # QEMU: Checking for cgroup 'devices' controller support : WARN (Enable 'devices' in kernel Kconfig file or mount/enable cgroup controller in your system)
  # QEMU: Checking for cgroup 'blkio' controller support   : WARN (Enable 'blkio' in kernel Kconfig file or mount/enable cgroup controller in your system)
  # QEMU: Checking for device assignment IOMMU support     : PASS
  # QEMU: Checking if IOMMU is enabled by kernel           : PASS

WARNの解消については現在のところ特に調べていませんが、libvirt.orgでcgroupを検索するとcgroupに関するページがヒットしました。
ここを読めば、何かがわかるかもしれません。

CPUが仮想化支援機能をサポートしていること

確認手順

以下のコマンドを実行して文字列が表示されれば、CPUが仮想化支援機能をサポートしているので問題ありません。
VMXはIntel VT-x、SVMAMD-V と紐づく言葉であり、どちらもCPUの仮想化支援機能を表す言葉です。

egrep -o '(vmx|svm)' /proc/cpuinfo
# vmx
# vmx
# vmx
# vmx
# vmx
# vmx
# vmx
# vmx
# vmx
# vmx
# vmx
# vmx
# vmx
# vmx
# vmx
# vmx

対処法

もし上記フラグが出てこなかった場合、以下も併せてご確認ください。

上記を確認してもおかしいと感じた場合は、後述のBIOSが仮想化支援機能を無効化していないことをご確認ください。
または、CPUの型番から仮想化支援機能のサポート有無を改めてご確認ください。

BIOSが仮想化支援機能を無効化していないこと

確認手順

以下のコマンドを実行し、何も表示されなければ問題ありません。
もし、"KVM: disabled by BIOS" というメッセージが出てきた場合は、BIOSによってCPUの仮想化支援機能が無効化されている可能性があります。

dmesg | grep -i kvm

対処法

BIOS設定画面を表示し、仮想化支援機能を有効化する必要があります。

BIOS設定画面の表示方法、そもそも設定変更できるのか否かは、BIOSのマニュアルをご確認ください。

ちなみに、私が使っているNUC10BIOSの場合は設定項目自体ありませんでしたが、特に仮想化支援機能は使えていたので問題なしです。

KVMカーネルモジュールがロードされていること

確認手順

以下のコマンドを実行し、kvmとkvm_intel、またはkvmとkvm_amd が表示されれば正常です。
非常にレアケースだと思いますが、何も表示されなかったり、kvmしか表示されない場合は対処が必要な可能性があります。

lsmod | grep kvm
# kvm_intel             319488  0
# kvm                   823296  1 kvm_intel
# irqbypass              16384  1 kvm

対処法

まず、IntelAMDのCPUを使っていない場合には、kvmしか表示されなくても問題ない可能性があります。

IBM POWER8 か IBM POWER9 の場合はこちらをご確認ください。

IBM Zの場合はこちらをご確認ください。

(無いと信じたいですが) IntelAMDのCPUを使っていても表示が想定外になった場合は、手動でのモジュールロードを試してみると良いかもしれません。

まずは設定ファイルを変更せず、起動時のみに影響を与える方法カーネルモジュールをロードしてみます (OSが起動しなくなったら怖いので)。
Intel製ではなくAMD製CPUを利用している場合は、kvm_intelkvm_amdに読み替えてください

sudo modprobe kvm_intel

もう一度確認してみます。

lsmod | grep kvm

この方法で解決できる場合、OS起動時にモジュールを自動的にロードするよう設定すれば解決できるはずです。
これは未検証なのですが、設定ファイル (/etc/modules-load.d/kvm.confなど) に以下のように記述してOSを再起動すれば、恐らく直ります。 (情報元:man modules-loaded.d)。

kvm_intel

再起動後にもう一度確認し、カーネルモジュールがロードできていれば対処完了です。

蛇足ですが、正常に動作している環境においてもVMを起動していなければsudo modprobe -r kvm_intelkvm_intelカーネルモジュールを除外すれば、不具合の発生している状況を再現できます。

/dev/kvm の権限が正しいこと

確認手順

公式にも切り分け方法として書いてあったので、稀にこの不具合にあたるケースがあるようです。

参考情報として、KVMを問題なく利用できている私の環境における出力を貼ります。
/dev/kvmkvmグループから参照できるようになっており、kvmグループにはqemuユーザーが所属する構成でした (Fedora32の場合)。
/dev/kvmQEMUKVMに連携する時に利用されるKVMのインターフェース部分なので、qemuユーザーがアクセスできれば問題ないと考えています。

ls -l /dev/kvm
# crw-rw-rw-. 1 root kvm 10, 232 Nov 23 19:27 /dev/kvm
#
grep kvm /etc/group
# kvm:x:36:qemu

なお、kvmカーネルモジュールがロードされていない場合は、/dev/kvm がそもそも生成していませんでした。
/dev/kvmが存在しない場合には、KVMカーネルモジュールがロードされていることも改めてご確認ください。

対処法

軽く検索したところ、Ubuntu 18.04 ではこのトラブルが発生するケースがあるようです。
2つの情報ソースを確認したところそれぞれ別の対象法を取っていますが、最終的にqemuユーザーが/dev/kvm にアクセスできるよう構成することで不具合を回避しているようです。

バイスファイルの場合はOS再起動するたびに権限やオーナー設定がリセットされるので、chownやchmodで変更しても一時的にしか対処できないようです。
ちなみにFedoraの場合は、KVM公式ページに書いてあるようにudevで/dev/kvmの権限を変更していました。
以下の出力のうち、1行目が該当します。
記載内容の意味は、man udev を読めば確認できます。

grep -r kvm /etc/udev/rules.d/ /usr/lib/udev/rules.d
# /usr/lib/udev/rules.d/50-udev-default.rules:KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"
# /usr/lib/udev/rules.d/50-udev-default.rules:KERNEL=="udmabuf", GROUP="kvm"

言い換えると、/usr/lib/udev/rules.d/50-udev-default.rulesに以下の行を追記すれば直ると思われます。

KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"
KERNEL=="udmabuf", GROUP="kvm"

(参考) qemu:///system と qemu:///session の違い

libvirtには、connectionというオプションがあります。
libvirtを使う際、connectionURIを指定することで、制御対象の仮想化製品を示す必要があります。

QEMU+KVM (またはQEMU単体) を操作する場合は、以下のいずれかのURIを使用します

  • qemu:///system
  • qemu:///session

本記事ではqemu:///systemを使う前提で手順を紹介しました。
qemu:///systemは公式で推奨されていますし、こちらのほうがトラブルを踏みにくいと感じたためです。

次のセクションで両者の違いを簡単に紹介します。

両者の違いを紹介するにあたり、以下の記事を参考にしました。

qemu:///system

rootユーザによって起動されたlibvirtdデーモンを介してVMを操作します。
libvirtがシステムのリソースにアクセスするために必要な権限を一通り持つため、基本的には何でもできます。

ちなみに、qemu:///systemは、rootユーザーのユーザーセッションでもあります。
すなわち、sudo virsh --connect qemu:///session listと仮に実行したとしても、sudo virsh listと同じ意味になります。
このことからもqemu:///systemは特権と同等であるということがわかります。

qemu:///systemを利用するには、必要な設定が2つあります。

1. libvirtグループへの所属

libvirtはPolkitと連携しています。
Polkitは、非特権のプロセスが特権を持つプロセスにアクセスする仕組みを提供するツールキットです。
Polkitで適切なポリシーを定めて適用することで、セキュリティリスクを最小限に抑えつつ、非特権プロセスから特権プロセスへのアクセス権限を付与できます。
sudo に似たような仕組みと思えば理解しやすいと思います。

普段virshやVirtual Machine ManagerによってVMを作る際、一般ユーザーで作業します。
つまり、上記操作によって発行されるのは非特権プロセスです。
一方で、qemu:///systemというURIでアクセスするのは、rootユーザーによって起動されたlibvirtd (即ち特権プロセス) ですので、Polkitの影響を受けます。
具体的には、virshやVirtual Machine Managerを操作するたびに毎回パスワードを求められるようになります。
これは非常に面倒です。

幸い、こちらのブログに記載されているように回避策はあります。
VMを操作する一般ユーザーから以下のコマンドを発行し、libvirtグループに所属させることでパスワードを求められなくなります。
これに相当するPolkitのルールは、/usr/share/polkit-1/rules.d/50-libvirt.rulesに記載がありました。

sudo usermod --append --groups libvirt $(whoami)

この操作は初回のみ実施すれば、その後意識する必要はなくなります。

2. イメージファイルのパーミッション

2つ目の注意点として、イメージファイルのパーミッションが挙げられます。
VMをインストールする際、ISOファイルが必要となります。
ISOファイルの多くは、インターネットからダウンロードすることで入手します。

例えば、ダウンロードしたISOファイルを$HOME/Downloadsに格納したとします。
このディレクトリは、通常ダウンロードしたユーザーにしかアクセスできません。

一方で、QEMU/KVMVMを作成する際にISOファイルをマウントするよう操作した場合、このISOファイルにqemuユーザーが読み取りアクセスします。
面倒なことに、この時ISOファイルが先ほどの$HOME/Downloadsに置かれていると、パーミッションエラーによってVMの起動に失敗してしまいます。

同じことがVMのディスクイメージファイル (qcow2) についても当てはまります。

対策としては、イメージファイルへのアクセス権限をqemuユーザーに持たせる ことが必要です。
具体的な実装例は、pool作成の事前準備を参照してください。

別の回避策として、FAT32でマウントしたUSBにISOやqcow2ファイルを配置する方法も提案されていました。
FAT32にはパーミッションの概念がないらしいので、ここに配置するだけでパーミッションを意識する必要がなくなるという原理です。

qemu:///session

現在のログインユーザーによって起動されたlibvirtdデーモンを介してVMを操作します。
libvirtdは非特権プロセスですので、Polkit周りの意識は不要です。
また、未検証ですがqemuユーザー周りの権限で悩むこともなくなるようです。

しかしながら、libvirt公式のFAQでは、基本的にqemu:///sessionの利用を推奨していません。
なぜなら、qemu:///sessionを使った場合、特権を必要とする操作ができなくなってしまうためです。

具体的にできなくなることはこちらのブログに譲ります。
必要な設定を入れれば qemu:///system でも問題なく動作するため、基本的にはqemu:///sessionを利用するメリットは少ないと考えます。
しかしながら、セキュリティなどの都合でqemu:///sessionを使う必要がある場合は、本記事の--connect qemu:///system--connect qemu:///sessionに読み替えればそのまま使えます。

(参考) libvirt (virsh) の用語

virshコマンドを使うにあたり、知っておくと便利な用語を紹介します。
libvirt公式のTerminology and goalsを元にしています。

用語 意味
node 物理サーバ
hypervisor ハイパーバイザー役のソフトウェア。本記事の文脈ではQEMU+KVMのこと。
domain 仮想マシンやコンテナ
pool VMのディスク(qcow2)、ISOファイルを格納先を示す設定オブジェクト

特にdomainはvirshのサブコマンドで出てくるので、知っておくと便利です。

また、domainやpoolの状態遷移図もざっくり頭に入れておくとvirshを理解しやすくなります。
公式の図が非常にわかりやすいです。

domain_state
引用元:libvirt.org: States that a guest domain can be in

特に、以下の用語を抑えておくことがvirshを理解する上で重要となります。

用語 意味
define XMLファイルを生成し、libvirt管理下にする
undefine XMLファイルを削除し、libvirt管理から外す
destroy domainの強制終了 (= SIGKILL)、またはpoolの停止
shutdown domainの停止 (VM上でshutdown実行)
start domain/pool の起動

(参考) 仮想NICの設定変更

デフォルトの設定では、defaultという仮想NICが設定されています。
このインターフェースは、VirtualBox でいうNATとホストオンリーに近い性質です。

VMからホスト外部と通信するときは、ホストのIPアドレスにNATされます (≒NAT)。
ただし、ホスト-VM間、VM同士の通信も可能です (≒ホストオンリー)。

仮想NICは、以下のコマンドで一覧表示できます。

virsh net-list
# Name      State    Autostart   Persistent
# --------------------------------------------
 # default   active   yes         yes

仮想NICの設定は、以下のコマンドで表示・編集できます。

virsh net-edit default
# <network>
#   <name>default</name>
#   <uuid>b130cf72-a5eb-4414-9fd8-7d1182f2b50b</uuid>
#   <forward mode='nat'/>
#   <bridge name='virbr0' stp='on' delay='0'/>
#   <mac address='52:54:00:96:e6:67'/>
#   <ip address='192.168.122.1' netmask='255.255.255.0'>
#     <dhcp>
#       <range start='192.168.122.2' end='192.168.122.254'/>
#     </dhcp>
#   </ip>
# </network>

この先はお好みですが、私の環境では上記 virsh net-edit コマンドから、以下の設定のみ変更しました。
これにより、192.168.122.2〜192.168.122.100は静的なIPアドレスアサインできるようになります。

 <range start='192.168.122.101' end='192.168.122.254'/>

変更した場合、設定を反映するためにNICを再起動します。

virsh net-destroy default
virsh net-start default

(参考) おすすめの動画 / 記事

前の記事にも貼りましたが、オススメの動画を紹介させてください。
内容は英語でArch Linuxをベースとした解説ですが、テンポ良く進むので眠くならずに見れると思います。
紹介されている内容は、本記事とほぼ同様です。

(本記事を書き上げて2ヶ月後に以下の動画を見つけました。もっと早く観ていれば私も楽にKVMを理解できたと思うと悔やまれます...。そのぐらい良い動画です)

動画とブログはどちらも同じ作者によるものです。

ブログはこちら:Linux Hypervisor Setup (libvirt/qemu/kvm)

まとめ

本記事では、QEMU+KVMのインストール方法、libvirt CLI (virsh, virt-install) によるVMの作成、KVMの動作確認の手順を紹介しました。

QEMUlibvirtのインストールコマンドはほんの数行です。
ただ、KVMベースのVMが動作するための条件は複数あり、条件を満たすための初期設定やトラブル切り分けは長く、複雑です。

Linux PC 構築関連リンク集

endy-tech.hatenablog.jp

次の記事

libvirtベースのGUIの一つであるCockpitのインストール方法と画面構成について紹介します。
Cockpit は機能拡充中のステータスであるものの、使い勝手がよいのでオススメできます。

endy-tech.hatenablog.jp

デスクトップ環境がある場合は、Virtual Machine Managerも多機能でオススメです。
virshと遜色ない機能性を誇ります。

endy-tech.hatenablog.jp

VM作成/削除、CMROM挿入、起動順序設定などの基本操作のまとめは、以下の記事を参照ください。
CLI/GUIの両方についてまとめてあります。

endy-tech.hatenablog.jp