はじめに
名前や概要を知ってるものの、その仕組みをよくわかっていない技術の1つとしてライブマイグレーションがあります。そのライブマイグレーションについて実践してみたので、今回記事にしようと思いました。
想定読者
- KVMに興味がある方
- ライブマイグレーションに興味がある方
ライブマイグレーションについての事前知識
「ライブマイグレーションとは、あるホストで稼働している仮想マシンを稼働させたまま、別のホストに移動すること」という概要は知っていましたが、それをどのように実現しているのかはこの記事を書く前は知らない状態でした。
この記事で紹介するライブマイグレーションのやり方
ライブマイグレーションを実践するにあたり、いくつかのブログやAIで確認したところ、KVMとNFSを使うことでライブマイグレーションを実現できることが分かりました。
KVMとNFSを使ったライブマイグレーションの大まかなやり方は下記になります。
①移行元と移行先ホスト(以下両ホスト)でQEUMやlibvirtを導入
②両ホストでブリッジ接続の設定
③NFSサーバを構築
④両ホストでストレージプール作成
⑤移行元ホストで仮想マシンを作成
⑥ライブマイグレーションを実行
そして、イメージしやすいように最終的にどのような構成になったのか先に構成図を載せます。

なお文字数の関係により、①-⑤は前編、⑥については後編で紹介いたします。
参考までに各ホストの情報は下記になります。
- HostA
- OS:Ubuntu24.04
- CPU:Intel
- メモリ:8GB
- ストレージ:250GB
- HostB
- OS:Ubuntu24.04
- CPU:AMD
- メモリ:32GB
- ストレージ:1TB
実際の流れ
ここから実際の手順を紹介いたします。一部の手順については、記事が長くなってしまうのを防ぐため省略しています。(省略部分については、参考サイトをご確認ください。)
①移行元と移行先ホスト(以下両ホスト)でQEUMやlibvirtを導入
ここでは主にQEUMやlivbirtに関連するパッケージをインストールします。
# apt install qemu-kvm libvirt-daemon-system libvirt-daemon virtinst bridge-utils libosinfo-bin -y
**KVM(Kernel-based Virtual Machine)**とは、Linuxサーバ上で仮想化機能を提供してくれる技術で、これ自体はLinuxカーネルに標準搭載されており、特に追加パッケージは不要です。
ただ、KVMを使って仮想マシンを作成・稼働させるにあたりQEUMやlivbirtのパッケージが必要になります。
- QEUM:CPUやメモリなどのハードウェアをエミュレートをするオープンソースのエミュレーター
-
libvirt:
virshなどのコマンドを使った仮想マシンの管理機能を提供してくれるもの
②両ホストでブリッジ接続の設定
仮想マシンにおけるブリッジ接続とは、仮想マシンをHostと同じ物理ネットワークに直接接続するための接続方式になります。
Hostと仮想マシン間の通信については、デフォルトだとNATを使って行われておりますが、そのままだとHostAとHostB間(HostAにある仮想マシンとHostBにある仮想マシン間も含む)通信の設定がとてもややこしくなってしまいます。
例えば、HostAとHostBどちらも同じIPアドレス範囲の仮想ネットワークがあるため、HostAからHostBの仮想ネットワークに通信するためにはどのように設定を行うのかなどが複雑になります。
しかしこの設定を行うことで、仮想ネットワークに所属する仮想マシンを物理ネットワークに所属する独立したホストの1台として扱うことができるようになります。
具体的な方法としては下記になります。
# 現在の接続状況を確認
# nmcli connection show
## 以下の作業については、ssh接続中に実施すると、ssh接続が切れることがありますので、コンソール接続など直接ホスト上で実施を推奨します。
# ブリッジインターフェースを追加
# nmcli connection add type bridge ifname br0 con-name br0
# ブリッジインターフェースにIPアドレス、ゲートウェイの設定
# nmcli connection modify br0 ipv4.method manual ipv4.addresses "任意のアドレス" ipv4.gateway "任意のゲートウェイアドレス"
# ブリッジbr0に物理NICを接続タイプbridge-slaveとして追加する
# nmcli connection add type bridge-slave ifname 物理NIC master br0
# br0への設定を反映する
# nmcli connection up br0
# 不要になった有線接続を削除
# nmcli connection delete (有線接続のNAMEorUUID)
# ブリッジ設定後、sshやpingが繋がらない場合
ブリッジ設定後、片方のホストにssh接続しようとしたところ、繋がらない事象が発生。
ip neighでarpテーブルを見たところ、ゲートウェイアドレスに対する通信がFAILEDになっていた。
原因としては、ブリッジ接続設定後にMACアドレスが変わった?ことにより、ルーター側がMACアドレスの変化を拒絶→通信できなくなっていた。
以下の設定(物理NICのMACアドレスと同一にする)を入れることで解決した。
# nmcli con mod br0 ethernet.cloned-mac-address preserve
# nmcli con up br0
③NFSサーバを構築
続いて、NFSサーバを構築します。構築先はホストBになります。NFSサーバは仮想マシンとして構築するので、ゲストOSが必要ですが、今回はrockylinux9というRHEL互換のOSを選択しました。
事前にwgetコマンドを使ってisoファイルをダウンロードしています。
仮想マシンの作成には、virt-installコマンドを使います。以下がNFSサーバを仮想マシンで作成した時のコマンドになります。
# virt-install \
--name "任意の名前" \ #仮想マシンの名前
--memory 8192 \ #メモリサイズ
--vcpus 2 \ #CPU数
--disk "任意のファイルパス",size=100 \ #vmディスクファイルの保存場所とファイル名、サイズ
--os-variant rocky9 \ #作成する仮想マシンがゲストOSに最適化するようにするための設定らしい
--location "任意のisoファイルパス" \ #isoファイルの保存場所
--network bridge=br0 \ #②で作成したブリッジを指定
--graphics none \ #CLIで操作
--console pty,target_type=serial \ #仮想シリアルポートを作成し、`virsh console`で仮想マシンに接続できるようにする
--extra-args 'console=ttyS0,115200n8' #CLIで操作するときに必要なカーネル起動引数
上記実行すると、下記のようにインストーラーが起動します。2を選択します。

2を選択すると、インストール前の設定として、以下の画面が出てきます。(OSによって変わる?)
「!」がついている数字がまだ未設定の部分になるため、その数字を選択しながら、設定を進めていく形になります。

設定後、「b」を選択すると、インストールが始まります。インストールが終了し、仮想マシンが作成されると、仮想マシンのコンソールに接続します。
この状態からホスト側に戻りたい場合は、「Ctrl + ]」で抜けることができます。
NFSの設定としては、/etc/exportsに共有ディレクトリの情報を記載する形になります。
# cat /etc/exports
/exports/migrate *(rw,sync,no_root_squash)
今更ながらですが、 *にしている部分は共有先のホストやネットワークを指定する部分ですが、もう少し絞ることができますし、no_root_squashは共有ディレクトリのファイルをroot権限で操作できてしまいセキュリティ的に良くないので、もう少し改善できたかと思いました。
※ブリッジ作成前に仮想マシンを作成した場合の設定について
②のブリッジ接続設定を行う前に、仮想マシンを作成していた場合、仮想マシン作成時のコマンドで--network bridge=br0が指定できません。
ただ、下記コマンドを実行していくことで、仮想マシン作成後でもブリッジ接続が可能です。
# vm停止
# virsh shutdown "VM名前"
# 現在のNIC設定確認
# virsh domiflist "VM名前"
# default NAT NIC を削除
# virsh detach-interface "VM名前" \
--type network \
--mac <MACアドレス> \ #domiflistで確認したMACアドレス
--persistent
# bridge NIC を追加
# virsh attach-interface "VM名前" \
--type bridge \
--source br0 \
--model virtio \
--config
# VM 起動
# virsh start "VM名前"
# virsh console "VM名前"
# IPアドレス確認
# ip a #IPアドレスが割り振られていればOK
④両ホストでストレージプール作成
続いて、ストレージプールを作成していきます。ストレージプールとは
ストレージプールは、仮想マシンにストレージを提供するために、libvirt が管理するファイル、ディレクトリー、またはストレージデバイスです。https://docs.redhat.com/ja/documentation/red_hat_enterprise_linux/7/html/virtualization_deployment_and_administration_guide/storage_pools#storage_pool_concepts
正直なところ、あまりよく分かっていないのですが、仮想マシンを管理しているlibvirtがvmディスク(仮想マシンの情報がつまったファイル)を安全に操作・管理するために必要な仕組みらしいです。
ストレージプールはネットワーク経由で他のホストと共有することができ、ストレージプールを共有するときに必要となるのがNFSになります。③でNFSサーバを構築したのはそのためになります。
そして、ライブマイグレーションを行うにあたって、ストレージプールを作成する理由は、VMディスクをホスト間で共有するためになります。
VMディスクは、OSなどの情報を保管しておくためのストレージになります。これがないと仮想マシンを作成することができないのですが、このVMディスクをホスト間で共有することにより、ライブマイグレーションを実現することができます。
※予めホスト間で共有することで、サイズが大きく、移行が難しいvmディスクを移行する必要性がなくなる。(ストレージであるvmディスクも移行できなくはないが、時間がかかるなどのデメリットあり)

このストレージプールの作成方法は以下の通りです。この作成は両ホストで実施します。
# 現在のプール一覧を取得
virsh pool-list --all
# 共有用のストレージプールを定義
virsh pool-define-as \
"任意のプール名(ここではnfs_poolとしている)" netfs \ #プール名及びプールタイプを指定
--source-host "NFSサーバのIPアドレス" \ #NFSサーバの情報を指定
--source-path /exports/migrate/ \ #NFSサーバの共有ディレクトリを指定
--target /mnt/images #マウントポイント ここにvmディスクの情報を保存している
# ストレージプールを起動
virsh pool-start "任意のプール名" #内部でmountの処理が走っています。
virsh pool-autostart "任意のプール名"
# プールの状態を確認
virsh pool-list #起動しているか確認
# マウントされているか確認
df
※ストレージプール起動時にうまくいかない場合
ストレージプールの起動(virsh pool-start "任意のプール名")を実施したときに、以下のことが原因でうまくいかないことがございました。
- nfsクライアント機能が不足
# エラー内容
internal error: Child process (/usr/bin/mount -o nodev,nosuid,noexec "NFSサーバのIPアドレス":/exports/migrate /mnt/migrate) unexpected exit status 32: mount: /mnt/migrate: bad option; for several filesystems (e.g. nfs, cifs) you might need a /sbin/mount.<type> helper program.
# 解決方法
nfs-commonをインストール(ubuntu)
- nfsサーバのSELinux及びfirewalld
# エラー内容
no route to host(NFSサーバ)
# 解決方法
SELinuxをdisabled #SELinuxについてはdisabled(完全無効化)までしなくても良いかもしれません。
fireawalldで2049番ポート宛の通信を許可
firewall-cmd --add-port=2049/tcp --zone=public --permanent
なお、NFSサーバ用の仮想マシンのVMディスクは/mnt/images配下に保存しているのですが、pool-start時のマウント処理により見えなくなっているため、起動時は問題ないものの、停止後再度起動するときに起動できないようです…そのため、NFSサーバのVMディスクファイルはまた別の場所にした方がよいです。
⑤移行元ホストで仮想マシンを作成
続いて、移行対象の仮想マシンを作成します。③で大まかな作成方法に触れているため、ここでは、補足的な部分を記載します。
最初に、移行対象の仮想マシンを作成した時のコマンドは下記になります。
# virt-install \
--name migrate-test \
--vcpus 1 \
--memory 2048 \
--disk pool=nfs_pool,vol=nfs_pool/test-vm \
--os-variant rocky9 \
--location "任意のisoファイルパス" \
--network bridge=br0 \
--graphics none \
--console pty,target_type=serial \
--extra-args 'console=ttyS0,115200n8'
③で作成したときと違うのは、--diskオプションの部分になります。ここでは④で作成したpoolを指定しています。またvolと呼ばれるパラメータを指定していますが、これはストレージボリュームと呼ばれるものを指定するものです。ストレージボリュームはvmディスクを保存するための入れ物のようなものらしいです。
このストレージボリュームは予め作成しておく必要があります。コマンドは下記になります。
# virsh vol-create-as --pool nfs_pool --name test-vm --capacity 20G --format qcow2
前編は以上になります。⑥ライブマイグレーションを実行については、後編で記載いたします。

