KVMホスト間で仮想マシンをライブマイグレーション（KVM on EC2構成）

# 1.本記事の目標
オンプレミスの環境をなるべく再現することを考えて、KVMホスト(EC2ベアメタルインスタンス)上の仮想マシンを別のKVMホスト(EC2ベアメタルインスタンス)にライブマイグレーションする。

:::note warn

別記事でも紹介されているが、ベアメタルインスタンスは高価インスタンスなので料金には十分注意すること。
EventBridgeを活用して使用しない時間帯は停止するなど工夫したほうがよい。

:::

# 2.構成・スペック
## 2-1.構成図
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576495/a015eb43-b819-a9de-e05b-cecf0860c745.png)

ポイント
- KVMをホストするEC2を2台(以下、KVMホスト01,02)、共有ストレージ（以下、NFSサーバ）となるEC2を1台用意
- KVMホストはベアメタルインスタンス(EC2のインスタンスタイプが*.metalになっているもの)にする
- 共有ストレージにNFSで接続し、各KVMホストにマウントする
    ※　移行元と移行先のホストで同じ仮想マシンのディスクイメージが利用可能でないといけないため、NFSで共有ストレージを組む


## 2-2.EC2スペック
今回の検証におけるEC2の設定値は以下の通り。
|  |KVMホスト01,02  |NFSサーバ  |備考|
|:-:|:-:|:-:|:-:|
|AMI  |RHEL-9.4.0_HVM-20240605-x86_64-82-Hourly2-GP3  |RHEL-9.4.0_HVM-20240605-x86_64-82-Hourly2-GP3  | RHELで試したかったのでRHELにしている |
|インスタンスタイプ  |i3.metal  |t3.large  |KVMホストのインスタンスタイプは*.metalがマスト|
|操作環境  |AWS Session Manager  |AWS Session Manager  |RHELのAMIにはSSM Agentがプリインストールされていないため、EC2作成時にユーザデータでインストール＆起動させておくこと|
|必要なIAMポリシー  |AmazonSSMManagedInstanceCore  |AmazonSSMManagedInstanceCore  |Session Managerで操作するために必要|
|セキュリティグループ(インバウンド)  |NFSサーバとの通信を全許可  |KVMホストとの通信を全許可  |検証なので絞り切らなかった。NFSとSSHの通信ができることはマスト|
|セキュリティグループ(アウトバウンド)  |全許可  |全許可  |検証なので絞り切らなかった。NFSとSSHとSession Managerの通信ができることはマスト|
|ユーザデータ  |以下「install_ssm-agent.sh」を設定  |以下「install_ssm-agent.sh」を設定  |EC2起動時にSSM Agentをインストール|

ユーザデータに指定する、SSM Agentをインストール＆起動させるコマンドは以下の通り。
``` install_ssm-agent.sh
#!/bin/bash
sudo dnf install -y https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/linux_amd64/amazon-ssm-agent.rpm
sudo systemctl start amazon-ssm-agent
sudo systemctl enable amazon-ssm-agent
```

SessionManagerでEC2へ接続できるようになっていればOK。

:::note info

EC2がSystemsManagerのマネージドインスタンスに登録されなくて、SessionManagerで接続できない場合は以下が不足していないかチェックしてみてください。
 - IAMロールの権限が不足している
 - EC2のセキュリティグループ(アウトバウンド)でSystemsManagerとのHTTPS通信を許可していない
 - (EC2がプライベートサブネットにあり、VPCエンドポイントを使ってSystemsManagerと通信する場合)VPCエンドポイントのセキュリティグループ(インバウンド)でHTTPS通信を許可していない
 - (EC2がプライベートサブネットにある場合、NATゲートウェイを使ってSystemsManagerと通信する場合)プライベートサブネットのルーティングテーブルがNATゲートウェイをデフォゲにしていない
 - SSM Agentがインストールできていない
 - SSM Agentが起動していない

:::



# 3.仮想マシン構築

以下のような流れで仮想マシンが作成できる環境を作る。
検証なのでrootユーザで操作する前提のもとコマンドは記載。

1. 仮想マシン作成の前提作業(KVMホスト01,02)
1. 仮想マシン作成の前提作業(NFSサーバ、KVMホスト01,02)
1. 仮想マシン作成(KVMホスト01)

## 3-1.仮想マシン作成の前提作業(KVMホスト01,02)
KVMを起動するための前提条件を満たしているかを確認する。
以下を参考にする。
https://docs.redhat.com/ja/documentation/red_hat_enterprise_linux/9/html/configuring_and_managing_virtualization/assembly_enabling-virtualization-in-rhel-9_configuring-and-managing-virtualization#proc_enabling-virtualization-in-rhel-9_assembly_enabling-virtualization-in-rhel-9

ホスト名を設定する。
``` set_hostname-kvm01.sh
hostnamectl set-hostname kvm01
```

``` set_hostname-kvm02.sh
hostnamectl set-hostname kvm01
```

`/etc/hosts`にも以下を追記し、名前解決できるようにする。
``` /etc/hosts.
<KVMホスト01のIP> kvm01
<KVMホスト02のIP> kvm02
```


KVMで仮想マシンを作成・操作するために必要となるパッケージをインストールする。
今回はCLIで操作するため、virt-viewer等のGUIツールはインストールしない。

``` install_pkgs.sh
dnf install -y qemu-kvm qemu-img libvirt virt-install
```

libvirtdはデフォルトでinactiveになっており、自動起動もdisabledになっているため、起動させる。

``` start_libvirtd.sh
systemctl start libvirtd
systemctl enable libvirtd
```


NFSサーバ上にもqemuユーザを作成するためにKVMホスト上のqemuユーザのIDを確認
``` check_qemu-id.sh
id qemu
```

:::note info

KVMホスト上にあるqemuユーザと同じユーザIDやグループIDをNFSサーバ上に作成しないと、仮想マシンが作成できなくなる。そのためにidコマンドで確かめている。

もう少し説明をすると、
ライブマイグレーションの実施にあたり、共有ストレージ上に仮想マシンのイメージファイルを作成する必要がある。
仮想マシン作成時には、KVMホスト上のqemuユーザが共有ストレージ上のイメージファイルに書き込みを行う。
その際の挙動として、NFSの仕様上、読み込みや書き込みをするクライアント側のユーザIDをNFSサーバのユーザIDにマッピングして書き込む。

このとき、NFSサーバ上にKVMホストのqemuユーザと同じIDを持ったqemuユーザが存在しないと、Permission Deniedとなり、仮想マシン作成が失敗する。

:::

SELinuxを無効化する。`/etc/selinux/config`の`SELINUX=enforcing`を以下に変更する。
```/etc/selinux/config.
SELINUX=disabled
```

SELinux無効化の設定を反映するため、KVMホストを再起動する。

## 3-2.仮想マシン作成の前提作業(NFSサーバ、KVMホスト01,02)
NFSサーバの構築とKVMホストへのマウントを行う。
[こちら](https://qiita.com/instant_baby/items/7513e5551d1521a0d015#server%E5%81%B4%E3%81%AE%E8%A8%AD%E5%AE%9A)を参考にしてください。

今回は説明の便宜上、KVMホストの`/var/lib/libvirt/images/`をNFSサーバにマウントして話を進める。

### 3-2-1.NFSサーバの構築で実施すること
- NFSサーバ上に、qemuユーザを作成する
ユーザID、所属グループはKVMホストで実施した`id qemu`コマンドの出力結果のIDを指定すること



## 3-3.仮想マシン作成(KVMホスト01)
仮想ディスクイメージを共有ストレージ上に作成する。

``` create_virtual-disk-image.sh
qemu-img create -f qcow2 /var/lib/libvirt/images/vm01.img 5G
```

仮想マシンのOSに使うisoファイルを取得する。
今回はRocky Linux9.4を使用する。
※検証のため、isoファイルは`/var/lib/libvirt/images/src/`に配置する。
```get_iso.sh
wget https://download.rockylinux.org/pub/rocky/9/isos/x86_64/Rocky-9.4-x86_64-minimal.iso
```




仮想マシンを作成する。
``` create_vm01.sh
virt-install \
--name vm01 \
--ram 3072 \
--disk path=/var/lib/libvirt/images/vm01.img \
--vcpus 2 \
--network bridge=virbr0 \
--graphics none \
--console pty,target_type=serial \
--location=/var/lib/libvirt/images/src/Rocky-9.4-x86_64-minimal.iso \
--extra-args 'console=ttyS0,115200n8 serial'
```

必須パラメータは以下の通り。
| 必須パラメータ | 説明 |
|:-:|:-:|
| --name  | 新しいマシンの名前  |   |
| --memory  | 割り当てるメモリーの量  |   |
| --vcpus  | 割り当てる仮想 CPU の数  |   |
| --disk  | 割り当てるストレージのタイプとサイズ  |   |
| --cdrom または --location  | OS インストールソースのタイプと場所  |   |

そのほかのオプションについてはCLIで操作する前提のものを指定している。

- オプションの参考情報
https://docs.redhat.com/ja/documentation/red_hat_enterprise_linux/9/html/configuring_and_managing_virtualization/assembly_creating-virtual-machines_configuring-and-managing-virtualization#creating-virtual-machines-using-the-command-line-interface_assembly_creating-virtual-machines

:::note warn

virt-installコマンドで失敗した際に以下のようになっているか確認すること
- libvirtdが起動している
- SELinuxが無効になっている
- NFSサーバ上にqemuユーザが作成されている、かつKVMホスト上のqemuと同じIDになっている
- 必須パラメータを指定している

上記を満たしていなければ、設定してみてください

:::


仮想マシン作成画面上で設定をすすめる（設定内容は省略）と仮想マシンのコンソールへ自動接続する。
`ctrl+]`でコンソール接続からログアウトできる。

KVMホスト01上で`virsh list --all`コマンドを実行すると、仮想マシンがrunning状態であることを確認できる。

``` check_status-vm01.sh
virsh list --all
```
＜出力結果＞
```
 Id   Name   State
-----------------------
 1    vm01    running
```


仮想マシンができた・・！

# 4.仮想マシンのライブマイグレーション
仮想マシンを作成している前提のもと、以下の流れで仮想マシンを別のKVMへライブマイグレーションさせる。

- ライブマイグレーション準備(KVMホスト01,02)
- ライブマイグレーション実施(KVMホスト01,02)

## 4-1.ライブマイグレーション準備(KVMホスト01,02)
KVMホスト間でライブマイグレーションするには、KVMホスト間で公開鍵認証を用いてSSHできる必要がある。

各KVMホストでSSHに必要な秘密鍵と公開鍵を作る。
``` create_rsa-key.sh
ssh-keygen -t rsa
```

各KVMホストで公開鍵の中身を確認し、出力結果をコピーする。
``` cat_pub-key.sh
cat ~/.ssh/id_rsa.pub
```

KVMホスト01の公開鍵をKVMホスト02の`~/.ssh/authorized_keys`に追記する。
KVMホスト02の公開鍵をKVMホスト01の`~/.ssh/authorized_keys`に追記する。

各KVMホストでsshdを再起動する。

``` restart_sshd.sh
systemctl restart sshd
```

KVMホスト間でssh接続できることを確認する。
``` ssh_from-kvm01-to-kvm02.sh
ssh root@kvm02
```

``` ssh_from-kvm02-to-kvm01.sh
ssh root@kvm01
```

## 4-2.ライブマイグレーション検証(KVMホスト01,02)

KVMホスト01,02で仮想マシンのステータスをチェックする。

``` check_status-vm01.sh
virsh list --all
<出力結果>
 Id   Name   State
-----------------------
 1    vm01    running
```

KVMホスト01ではvm01がrunning状態
KVMホスト02では何も表示されない

KVMホスト01でライブマイグレーションのコマンドを実行する
``` migrate_vm01_from-kvm01-to-kvm02.sh
virsh migrate --persistent --live vm01 qemu+ssh://kvm02/system
```


KVMホスト01,02で仮想マシンのステータスをチェックする。

``` check_status-vm01.sh
virsh list --all
```

KVMホスト01では何も表示されないが、
KVMホスト02では以下のようにvm01がrunning状態となる。

＜KVMホスト02での出力結果＞
```
 Id   Name   State
-----------------------
 1    vm01    running
```

ライブマイグレーションできた・・！






# 5.参考
- 仮想マシンの作成
    - https://qiita.com/OPySPGcLYpJE0Tc/items/e3958c79df8ee795d52e
    - https://docs.redhat.com/ja/documentation/red_hat_enterprise_linux/9/html/configuring_and_managing_virtualization/assembly_creating-virtual-machines_configuring-and-managing-virtualization#creating-virtual-machines-using-the-command-line-interface_assembly_creating-virtual-machines


- NFSサーバの構築
    - https://qiita.com/instant_baby/items/7513e5551d1521a0d015

- ライブマイグレーション
    - https://qiita.com/ohtsuka-shota/items/78afa122e07ecaa3ad24