kvmを使った仮想環境構築(CentOS8.4)

更新日:2021/12/18

KVMを使った仮想化サーバーを作ります
手順については、RHELのマニュアルを参考にやってみました(https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/8/html/configuring_and_managing_virtualization/index)。

これを書くにあたり、用意したPCのマザーボードとCPUは以下の通りです。
・マザーボード → ASUSTeK ROG STRIX B560-I GAMING WIFI (NICもオンボのものを使用。ドライバを用意しなくとも認識します。WIFIは未使用。)
・CPU → Corei5-11400

必要なソフトウェアをインストールする

まずはvirtモジュールをインストールします(仮想化に必要な色々なプログラムがインストールされます)。

[root@localhost /]# dnf module install virt

次に、「virt-install」と「virt-viewer」をインストールします(こっちはmodule指定じゃなくて、単品のソフトウェアインストールなので注意)。

[root@localhost /]# dnf install virt-install virt-viewer

必要なソフトウェアのインストールが終わったら、libvirtdのサービスを開始します。
statusで表示すると、以下の用に出てきます。
また、is-enabledで、OS起動後、自動起動するようになっているのかチェックしてみましたが、自動起動するようになっていました。

[root@localhost /]# systemctl start libvirtd  ←インストール直後は起動していないので、手動で起動させる
[root@localhost /]# systemctl status libvirtd
● libvirtd.service - Virtualization daemon
   Loaded: loaded (/usr/lib/systemd/system/libvirtd.service; enabled; vendor preset: enabled)
   Active: active (running) since Sat 2021-10-09 17:21:56 JST; 2s ago
     Docs: man:libvirtd(8)
           https://libvirt.org
 Main PID: 35834 (libvirtd)
    Tasks: 19 (limit: 32768)
   Memory: 58.3M
   CGroup: /system.slice/libvirtd.service
           tq 2079 /usr/sbin/dnsmasq --conf-file=/var/lib/libvirt/dnsmasq/default.conf --leasefile-ro --dhcp-script=/usr/libexec/libvirt_leaseshelper
           tq 2080 /usr/sbin/dnsmasq --conf-file=/var/lib/libvirt/dnsmasq/default.conf --leasefile-ro --dhcp-script=/usr/libexec/libvirt_leaseshelper
           mq35834 /usr/sbin/libvirtd --timeout 120

10月 09 17:21:56 localhost.localdomain systemd[1]: Starting Virtualization daemon...
10月 09 17:21:56 localhost.localdomain systemd[1]: Started Virtualization daemon.
10月 09 17:21:56 localhost.localdomain dnsmasq[2079]: read /etc/hosts - 2 addresses
10月 09 17:21:56 localhost.localdomain dnsmasq[2079]: read /var/lib/libvirt/dnsmasq/default.addnhosts - 0 addresses
10月 09 17:21:56 localhost.localdomain dnsmasq-dhcp[2079]: read /var/lib/libvirt/dnsmasq/default.hostsfile
[root@localhost /]# systemctl is-enabled libvirtd  ←OS起動時にサービスの自動起動するかを確認。enabledと返ってくるので、自動起動する。
enabled

環境のチェックと、警告の対応

仮想化サーバーとして使えるか、チェックするコマンド「virt-host-validate」を実行します。
以下が、実行してみた結果です。

[root@localhost /]# virt-host-validate
  QEMU: 確認中 for hardware virtualization                                 : 成功
  QEMU: 確認中 if device /dev/kvm exists                                   : 成功
  QEMU: 確認中 if device /dev/kvm is accessible                            : 成功
  QEMU: 確認中 if device /dev/vhost-net exists                             : 成功
  QEMU: 確認中 if device /dev/net/tun exists                               : 成功
  QEMU: 確認中 for cgroup 'cpu' controller support                         : 成功
  QEMU: 確認中 for cgroup 'cpuacct' controller support                     : 成功
  QEMU: 確認中 for cgroup 'cpuset' controller support                      : 成功
  QEMU: 確認中 for cgroup 'memory' controller support                      : 成功
  QEMU: 確認中 for cgroup 'devices' controller support                     : 成功
  QEMU: 確認中 for cgroup 'blkio' controller support                       : 成功
  QEMU: 確認中 for device assignment IOMMU support                         : 成功
  QEMU: 確認中 if IOMMU is enabled by kernel                               : 警告 (IOMMU appears to be disabled in kernel. Add intel_iommu=on to kernel cmdline arguments)
  QEMU: 確認中 for secure guest support                                    : 警告 (Unknown if this platform has Secure Guest support)

「if IOMMU is enabled by kernel」に警告があるので、こちらについては対応します。
「for secure guest support」に表示されている警告は、IntelのCPUを使っているサーバーだと無条件に表示される警告なので無視してOK(virt-host-validateのソースを見てきました。Intel製CPUならチェック処理をしないで、無条件でこの警告がでる実装になっていました)。

「if IOMMU is enabled by kernel」の警告の対応をしていきます。
この警告は、単純に、IOMMUが有効になってないので出ているだけでです。
IntelのCPUの場合「VT-d」という名前の機能で、ハードウェア支援が用意されています(10年ぐらい昔のCPUだと無い気がする)。
これを有効にするには、linux起動時のオプション(grubの設定)を変更します。
「/etc/default/grub」ファイルを開き、赤字部分を追記します。

GRUB_TIMEOUT=5
GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g' /etc/system-release)"
GRUB_DEFAULT=saved
GRUB_DISABLE_SUBMENU=true
GRUB_TERMINAL_OUTPUT="console"
GRUB_CMDLINE_LINUX="crashkernel=auto resume=/dev/mapper/cl-swap rd.lvm.lv=cl/root rd.lvm.lv=cl/swap rhgb quiet intel_iommu=on"
GRUB_DISABLE_RECOVERY="true"
GRUB_ENABLE_BLSCFG=true

その後、実際に、grub用の設定ファイルを生成します(昔は直接手動で編集していましたが、今の時代はこういう手順を踏むらしい・・・)。
以下のコマンドは、UEFIを使って起動させている場合のケースです(今の時代は、特に理由が無い限りUEFIだと思います。BIOSから起動させている場合は、パスの指定が「/boot/grub2/grub.cfg」になるらしい)。
ちなみにgrub.cfgファイルを「/boot/efi/EFI/centos/grub.cfg」に出力させていますが、これはCentOSの場合で、RHELの場合は「/boot/efi/EFI/redhat/grub.cfg」になるので注意。

[root@localhost default]# grub2-mkconfig -o /boot/efi/EFI/centos/grub.cfg
Generating grub configuration file ...
Adding boot menu entry for EFI firmware configuration
done

これでgrubの設定が終わったので、OSを「reboot」コマンドで再起動させます。
その後、改めて「virt-host-validate」を実行すると、以下のように「成功」となっているはずです。

[root@localhost ~]# virt-host-validate
  QEMU: 確認中 for hardware virtualization                                 : 成功
  QEMU: 確認中 if device /dev/kvm exists                                   : 成功
  QEMU: 確認中 if device /dev/kvm is accessible                            : 成功
  QEMU: 確認中 if device /dev/vhost-net exists                             : 成功
  QEMU: 確認中 if device /dev/net/tun exists                               : 成功
  QEMU: 確認中 for cgroup 'cpu' controller support                         : 成功
  QEMU: 確認中 for cgroup 'cpuacct' controller support                     : 成功
  QEMU: 確認中 for cgroup 'cpuset' controller support                      : 成功
  QEMU: 確認中 for cgroup 'memory' controller support                      : 成功
  QEMU: 確認中 for cgroup 'devices' controller support                     : 成功
  QEMU: 確認中 for cgroup 'blkio' controller support                       : 成功
  QEMU: 確認中 for device assignment IOMMU support                         : 成功
  QEMU: 確認中 if IOMMU is enabled by kernel                               : 成功
  QEMU: 確認中 for secure guest support                                    : 警告 (Unknown if this platform has Secure Guest support)

仮想化環境のネットワークについて

ここでは手順ではなく、仮想化のホストとゲストOSの通信ってどうなってるの?という話を、調べてみて分かったことなどを書いていきます。

  1. libvirtのインストール直後の状態
  2. virbr0が作られないようにする
  3. これから作成するネットワーク構成について

libvirtのインストール直後の状態

CentOSに、仮想化パッケージをインストールすると、自動的に「virbr0」というブリッジが作成されます(ipconfigコマンドで確認できる)。
(※libvirtdが起動したタイミングで自動で作成している気がする。少なくとも、「/etc/sysconfig/network-scripts/」の中には、ブリッジの設定ファイルは無い。)
「nmcli device status」で、デバイス一覧を表示させると「virbr0」「virbr0-nic」が勝手に作られている(「virbr0-nic」が何なのかは知らない)。

[root@localhost ~]# nmcli device status
DEVICE      TYPE      STATE            CONNECTION
enp3s0      ethernet  接続済み         System enp3s0
virbr0      bridge    接続済み (外部)  virbr0
lo          loopback  管理無し         --
virbr0-nic  tun       管理無し         --

そして、さらには、iptablesの一覧を見ると、自動でLIBVIRT・・・というのが追加されている。
そもそも、libvirt(仮想環境を作るための基盤ライブラリ)は、iptablesの設定を裏でいじくるので、それを知らずにiptablesの設定を自分で消したり変更したりすると、場合によっては仮想マシンのネットワーク通信ができなくなるので要注意。
なので、iptablesの設定を変更する前に、今ある設定をチェックして、矛盾が無いように設定しないといけない(まぁ、ほとんどの場合、気にしなくても大丈夫でしょうけど)。

[root@localhost ~]# iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination
LIBVIRT_INP  all  --  anywhere             anywhere

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination
LIBVIRT_FWX  all  --  anywhere             anywhere
LIBVIRT_FWI  all  --  anywhere             anywhere
LIBVIRT_FWO  all  --  anywhere             anywhere

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination
LIBVIRT_OUT  all  --  anywhere             anywhere

Chain LIBVIRT_INP (1 references)
target     prot opt source               destination
ACCEPT     udp  --  anywhere             anywhere             udp dpt:domain
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:domain
ACCEPT     udp  --  anywhere             anywhere             udp dpt:bootps
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:bootps

Chain LIBVIRT_OUT (1 references)
target     prot opt source               destination
ACCEPT     udp  --  anywhere             anywhere             udp dpt:domain
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:domain
ACCEPT     udp  --  anywhere             anywhere             udp dpt:bootpc
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:bootpc

Chain LIBVIRT_FWO (1 references)
target     prot opt source               destination
ACCEPT     all  --  192.168.122.0/24     anywhere
REJECT     all  --  anywhere             anywhere             reject-with icmp-port-unreachable

Chain LIBVIRT_FWI (1 references)
target     prot opt source               destination
ACCEPT     all  --  anywhere             192.168.122.0/24     ctstate RELATED,ESTABLISHED
REJECT     all  --  anywhere             anywhere             reject-with icmp-port-unreachable

Chain LIBVIRT_FWX (1 references)
target     prot opt source               destination
ACCEPT     all  --  anywhere             anywhere

virbr0という名前でブリッジが自動的に追加されていて、IPアドレスが192.168.122.0になっている。
そして、このデフォルトのvirbr0を使うと、ゲストOSから外部ネットワークには接続できるけど、外の人がゲストOSにアクセスできない(NATのように外と中のIPアドレスを1:1で変換しないので)。
私がやりたいことは、外のネットワークからゲストOSにアクセスすることなので、このままでは使えない。
そのため、別途ブリッジを新規に作成し、それを介して外からゲストOSにアクセスできるように設定を行います(動作モードがいくつかありますが、ここでは「ブリッジモード」のみを取り扱います)
参照 → 13.5. 仮想マシンのネットワーク接続の種類(https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/8/pdf/configuring_and_managing_virtualization/red_hat_enterprise_linux-8-configuring_and_managing_virtualization-ja-jp.pdf)

ネットワークの定義について、お役立ちコマンドをいくつか・・・。
「virsh net-list --all」 → ネットワークの一覧を表示(デフォルトでは「default」というネットワークが定義されています)。
「virsh net-info default」 → 「default」の情報を表示。
「virsh net-dumpxml default」 → 「default」の定義情報を表示。

以下が各コマンドの実行結果ですが、「default」というネットワークが作成されています。
この設定値は「/etc/libvirt/qemu/networks/default.xml」にかいてあります。

[root@localhost ~]# virsh net-list --all
 名前      状態     自動起動     永続
---------------------------------------------
 default   動作中   はい (yes)   はい (yes)

[root@localhost ~]# virsh net-info default
名前:         default
UUID:           bef530f1-68e1-4752-966f-2834cbdc80e7
起動中:      はい (yes)
永続:         はい (yes)
自動起動:   はい (yes)
ブリッジ:   virbr0

[root@localhost ~]# virsh net-dumpxml default
<network>
  <name>default</name>
  <uuid>bef530f1-68e1-4752-966f-2834cbdc80e7</uuid>
  <forward mode='nat'>
    <nat>
      <port start='1024' end='65535'/>
    </nat>
  </forward>
  <bridge name='virbr0' stp='on' delay='0'/>
  <mac address='52:54:00:42:7b: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>

virbr0が作られないようにする

デフォルトで作成される「virbr0」を消したくなる時があります。
ただ、これは仮想化ホスト場合と、仮想化を使わない普通のOSやゲストOSの場合で対応方法が違ってきます。

まず、仮想化を使わない普通のOSやゲストOSの場合は、単純です。
libvirtが起動するときに、自動的に「virbr0」を作成するので、起動させなければよいだけです。
(libvirtは、OSインストール時に指定するグループの設定次第ではインストールされてしまうみたいです。ミニマムの場合はインストールされないっぽいです)
「systemctl disable libvirtd」でOS起動時のサービス起動を中止し、OS再起動すれば、消えているはず。

仮想化ホストの場合は、以下の方法で、消すます(正確には、非活性化し、OS起動時にも自動起動しないように設定するだけです)。
virbr0を消すとiptablesに設定されていたルールも自動で消えてなくなります。
対応方法としては、デフォルトで作成される仮想ネットワーク「default」を無効します。
その結果「virbr0」もなくなります。
以下のコマンドを実行すると「/etc/libvirt/qemu/networks/autostart/default.xml」が削除されます。
そのため、OS起動後も、virbr0が自動的に作成されることがなくなります。
virbr0の設定ファイル自体は「/etc/libvirt/qemu/networks/default.xml」に残っています。

[root@localhost ~]# virsh net-list --all ←現在の仮想環境のネットワークを一覧表示する
 名前      状態     自動起動     永続
---------------------------------------------
 default   動作中   はい (yes)   はい (yes)

[root@localhost network-scripts]# virsh net-dumpxml default ←defaultの詳細を表示
<network>
  <name>default</name>
  <uuid>bef530f1-68e1-4752-966f-2834cbdc80e7</uuid>
  <forward mode='nat'>
    <nat>
      <port start='1024' end='65535'/>
    </nat>
  </forward>
  <bridge name='virbr0' stp='on' delay='0'/>
  <mac address='52:54:00:42:7b: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>

[root@localhost ~]# virsh net-destroy default ←現在有効になっている「default」という仮想ネットワークを削除
ネットワーク default は強制停止されました

[root@localhost ~]# virsh net-autostart --network default --disable ←「default」という仮想ネットワークをOS起動後、自動起動しないようにする
ネットワーク default の自動起動設定が解除されました

[root@localhost ~]# virsh net-list ←「default」を消したので、何も表示されていない
 名前   状態   自動起動   永続
--------------------------------

[root@localhost network-scripts]#

これから作成するネットワーク構成について


上記のようなイメージの構成を作ろうと思います。
192.168.11.0/24のネットワーク上に、物理サーバーが1台あり、そのサーバーにはNIC(enp3s0)が1つあります。
Linux上にてブリッジを1つ「br0」を作成します。
そのbr0と、各仮想マシンとを接続します。
この構成にしておけば、外部のPCから「192.168.11.42」などで「仮想マシン1」にアクセスできます(デフォルトで作成されるvirbr0は、外から接続しようとしても出来ない設定になっている・・・らしい)。

ゲストOSがが外部ネットワークと通信できるようにブリッジを作成する

こちらに書いたようなイメージのネットワークを作成します。
「br0」というブリッジを作成します。
このサーバーにはデバイス名が「enp3s0」という名のNICがあります。
今までは、このNICを使って通信をしていましたが、これから、ブリッジを介して接続するように設定をおこないます。
なので、ブリッジに「192.168.11.41」というIPアドレスなどのネットワーク設定値をセットし、slaveに「enp3s0」を設定します。

[root@localhost ~]# nmcli con add type bridge con-name br0 ifname br0 ←コネクション名「br0」、インターフェイス名「br0」という名前でブリッジ作成
接続 'br0' (fe7cd7a1-3e00-495c-9598-a433dd222cac) が正常に追加されました。
[root@localhost ~]# nmcli con mod br0 ipv4.method manual ipv4.addresses "192.168.11.41/24" ipv4.gateway "192.168.11.1" ipv4.dns "192.168.11.1" ←「br0」にネットワークの設定を行う
[root@localhost ~]# nmcli con add type bridge-slave ifname enp3s0 master br0 ←「br0」に、物理NIC「enp3s0」を追加する
接続 'bridge-slave-enp3s0' (2a94fc21-7031-40b0-bdcf-dfad7a27db98) が正常に追加されました。
[root@localhost ~]# nmcli con show ←現在のコネクションの定義情報を表示する
NAME                 UUID                                  TYPE      DEVICE
br0                  fe7cd7a1-3e00-495c-9598-a433dd222cac  bridge    br0
System enp3s0        63aa2036-8665-f54d-9a92-c3035bad03f7  ethernet  enp3s0
virbr0               1fda0808-2281-4d9f-8c13-808fbd906328  bridge    virbr0
bridge-slave-enp3s0  2a94fc21-7031-40b0-bdcf-dfad7a27db98  ethernet  --

上記の設定まで終わったら、次に「br0」の接続を有効にします。
その後、「br0」を有効にしたら、今まで使用していたコネクション名「System enp3s0」(デバイス名は「enp3s0」)を削除します。
※SSHで接続して作業している場合、コマンド実行後、SSHの接続が切れるます。もしかしたら、先に「nmcli con del "System enp3s0"」やっておかないと、SSHで接続できないかも?

[root@localhost ~]# nmcli con up br0 ←「br0」を有効にする
接続が正常にアクティベートされました (master waiting for slaves) (D-Bus アクティブパス: /org/freedesktop/NetworkManager/ActiveConnection/7)
[admin@localhost ~]$ nmcli con show ←現在のコネクションの定義情報を表示する
NAME                 UUID                                  TYPE      DEVICE
System enp3s0        63aa2036-8665-f54d-9a92-c3035bad03f7  ethernet  enp3s0
br0                  fe7cd7a1-3e00-495c-9598-a433dd222cac  bridge    br0
virbr0               1fda0808-2281-4d9f-8c13-808fbd906328  bridge    virbr0
bridge-slave-enp3s0  2a94fc21-7031-40b0-bdcf-dfad7a27db98  ethernet  --
[admin@localhost ~]$ nmcli con del "System enp3s0" ←「System enp3s0」のコネクションは不要なので削除する
接続 'System enp3s0' (63aa2036-8665-f54d-9a92-c3035bad03f7) が正常に削除されました。

上記コマンドを実行し終わると「/etc/sysconfig/network-scripts/」の中も変化します。 「ifcfg-br0」「ifcfg-bridge-slave-enp3s0」というファイルだけとなり、さきほど削除したコネクション名「System enp3s0」の設定ファイル「ifcfg-enp3s0」は消えています。
s

ストレージプールの作成

仮想ホストを作れば、自動で作られるらしいですが、よくわからないので、とりあえず手動で作成します。
これは、単純にゲストOSなどを格納するストレージ領域を定義するものです。
ハードディスクのパーティーションや、iSCSIの領域などを、ストレージプールとして設定できます。
指定したディレクトリをストレージプールとしても設定できます。
今回は、指定したディレクトリをストレージプールとして設定します。

ストレージプールの定義を何もしていない状態だと、以下のように、何も表示されません。
これからストレージプールを1個追加してみます。

[root@localhost ~]# virsh pool-list --all
 名前   状態   自動起動
-------------------------

まずは、ディレクトリを用意します。
ディレクトリはどこでもよいのですが、今回は「/virt」というディレクトリを用意しました。

次に、ストレージプールの定義情報を記載したxmlファイルを作成します。
ディレクトリをストレージプールとして指定する場合、以下の設定ファイルを記載します。 これは、コマンドを実行した後には削除してOKなので、どこか適当なところに作ります。

<pool type='dir'>
  <name>pool1</name>
  <target>
    <path>/virt</path>
  </target>
</pool>

上記の内容を「~/storagePool.xml」として作成しました。
以下の操作で「pool1」というストレージプールを作成します。
コマンドを実行し終わったら「storagePool.xml」は削除してしまってOKです。
そして、libvirt起動時に自動的にpool1のストレージプールを有効にする設定を行います。

[root@localhost ~]# virsh pool-define ~/storagePool.xml  ←先ほど作成したxmlの設定でストレージプールを作成
プール pool1 が /root/storagePool.xml から定義されました

[root@localhost ~]# virsh pool-list --all ←作成できたか確認
 名前    状態       自動起動
---------------------------------
 pool1   停止状態   いいえ (no)

[root@localhost ~]# virsh pool-start pool1  ←停止状態なので、起動する
エラー: プール pool1 の起動に失敗しました  ←なぜか起動中なのでエラーと言われる。
エラー: 要求された操作は有効ではありません: ストレージプール 'pool1' はすでに動作中です

[root@localhost ~]# virsh pool-list --all  ←とりあえず動作中となったので、上記エラーは無視する
 名前    状態     自動起動
-------------------------------
 pool1   動作中   いいえ (no)

[root@localhost ~]# virsh pool-autostart pool1  ←libvirt起動時に自動的にpool1も有効になるように設定
プール pool1 が自動起動としてマークされました

[root@localhost ~]# virsh pool-list --all  ←これで、プールとして使える状態&自動起動もONになった
 名前    状態     自動起動
------------------------------
 pool1   動作中   はい (yes)
 [root@localhost /]# virsh pool-info pool1  ←プールの情報を表示してみる
名前:         pool1
UUID:           be2b0301-5a64-446e-8a9f-949ab7ff7684
状態:         実行中
永続:         はい (yes)
自動起動:   はい (yes)
容量:         823.89 GiB
割り当て:   5.78 GiB
利用可能:   818.10 GiB
[root@localhost /]# virsh pool-list --all --details ←このコマンドが一番見やすいかも
 名前    状態     自動起動     永続         容量         割り当て   利用可能
--------------------------------------------------------------------------------
 pool1   実行中   はい (yes)   はい (yes)   823.89 GiB   5.78 GiB   818.11 GiB

おまけとして、ふと、作成済みのストレージプールってどんな設定で作ったのかを知りたくなる時があります。
ストレージプールの設定値は「/etc/libvirt/storage/」ディレクトリの中に保存されます。
先ほど作成したpool1は、「/etc/libvirt/storage/pool1.xml」に作成されており、内容は以下の通りです。

[root@localhost ~]# cat /etc/libvirt/storage/pool1.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 pool-edit pool1
or other application using the libvirt API.
-->

<pool type='dir'>
  <name>pool1</name>
  <uuid>be2b0301-5a64-446e-8a9f-949ab7ff7684</uuid>
  <capacity unit='bytes'>0</capacity>
  <allocation unit='bytes'>0</allocation>
  <available unit='bytes'>0</available>
  <source>
  </source>
  <target>
    <path>/virt</path>
  </target>
</pool>

仮想マシンの作成

まず、インストールしたいOSのisoイメージを用意します。
CentOS8のisoイメージを用意し、「/userdata/iso/CentOS-8.4.2105-x86_64-dvd1.iso」に保存しているとします。

virt-installというコマンドを使うことで、OSのインストールが可能です。
色々とオプションを指定が必要ですが、ひとまず、具体的なコマンドとしては、以下の通りです。

virt-install \
 --name testGuest1\
 --memory 2048\
 --vcpu 2\
 --graphics none\
 --disk pool=pool1,size=10,format=qcow2\
 --network bridge=br0\
 --location /userdata/iso/CentOS-8.4.2105-x86_64-dvd1.iso\
 --os-type=linux\
 --os-variant centos8\
 --extra-args "console=tty0 console=ttyS0,115200n8"

各オプションの説明を以下に記載します。

オプション 説明
name 仮想環境の名前です。管理する際、これが識別子になります。
memory 仮想環境に割り当てるメモリ量(2048MB)。
vcpu 仮想環境に割り当てるCPUの数(2CPU)。
graphics GUIを使うかどうか。使わないのでnoneを指定しています。
disk ストレージの設定です。
こちらで作成済のストレージプール「pool1」の中に、10GBのファイルを作成し、それを仮想環境のストレージとします。
このファイルのフォーマットは、qcow2という形式に指定しています(rawにも設定可能。パフォーマンスはこちらの方が良いらしいけど、qcow2のほうが便利なのでこちらを指定します)。
network こちらで作成したブリッジ「br0」と接続するように指定しています。
os-type OSの種別を指定します。CentOSなのでlinuxを指定。
os-variant 「osinfo-query os」というコマンドを実行すると、OSの一覧が表示されます。
この中からインストールするOSの名前を拾ってきて指定します。
「centos8」をを指定します(今回は、CentOS 8なので、上記コマンドの実行結果からCentOSでgrepをかけると、指定する値がみつかります)。
extra-args 「console=tty0 console=ttyS0,115200n8」のオプション指定をしないと、コマンド実行後、OSのインストール画面がいつまでたっても表示されません。
今表示しているコンソールに、仮想マシンのコンソールを表示させるようにします。

上記で記載したvirt-installコマンドを実行すると、OSのインストールウィザードが始まります。
上記でGUIを使わない設定なので、コンソールから設定していく感じになります。
昔ながらのCUIでのインストールです。
操作にクセがありますが、見れば分かるレベルなので、説明は割愛・。
Windowsの場合、どうするのかやったことないので、不明・・・。

仮想マシンを管理するコマンドたち

基本的に、仮想環境のコントロールは、「virsh」コマンドにオプションを指定することで、制御できるようになっています。
基本的なコマンドを以下にまとめます。
コマンドの中に「XXXXX」という表記が出てきますが、これは仮想マシンの名前です。

ちなみに、teratermでSSH接続して、サーバーの操作を行う際、仮想環境を起動し、その仮想環境のコンソールに接続したい場合があります。
その場合、以下のコマンドを実行することで、コンソールを仮想環境のものに切り替えることができます(以下のコマンドでは「testGurst1」という仮想環境にコンソールを切り替えています)。

virsh console testGuest1

そして、元々のコンソールに戻るときは「Ctrl + ]」を押すことで、戻ります。

コマンド 説明
virsh list --all 仮想環境の一覧を表示する。
virsh start XXXXX 仮想マシンを起動します。
virsh shutdown XXXXX 仮想マシンをシャットダウンします。
virsh destroy XXXXX 仮想マシンを強制的に終了させます。
仮想マシンがハングアップした場合など、どうしようもなくなった時にだけ使用するコマンドです。
virsh undefine XXXXX --remove-all-storage 仮想マシンの環境を削除します。
「--remove-all-storage」オプションをつけることで、仮想マシンが使っていたストレージファイルも一緒に削除されます。
virsh pool-list --all ストレージプールのリストを表示します。
virsh vol-list (プール名) (プール名)で指定した、ストレージプールに登録されているファイルの一覧を表示します。
virsh pool-destroy (プール名) (プール名)で指定した、ストレージプールを停止状態にします。
virsh pool-undefine (プール名) (プール名)で指定した、ストレージプールを削除します。

仮想マシンのテンプレート

環境を1つや2つ作るなら、毎回インストールして1個づつ設定すればよいですが、これが10個とかになると、さすがに大変です・・・。
ということで、1つテンプレートとして作っておいて、これをコピペすることで、環境を素早く構築できるようにします。
テンプレートを使うと、何から何まで自動化できるかというと、残念ながらそうでもありません。
固定IPアドレスの設定などは、手動で行う必要があります(何か別の方法を使えばできるかもしれませんが)。

手順としては
・テンプレートとして使用する仮想マシンを作成
・その仮想マシンで、「dnf update」を実行したり、必要なソフトウェアのインストール
・仮想マシンをシャットダウン。
・環境依存の設定値などの削除をしてくれる「virt-sysprep」というツールを使い、仮想マシンのイメージに対し実行
・テンプレートから、新しい仮想マシンを作成
といった流れです。

仮想マシンテンプレートを作って、そのテンプレートから環境を作ってみたいと思います。
まずは、必要なコマンドを、以下のコマンドでインストールしておきます。

dnf install /usr/bin/virt-sysprep


仮想マシンの作成の手順で、仮想マシンを作成し、その環境へログインします。
「dnf update」など必要なアップデートや、どの環境でも使用するソフトウェアをインストールします。

環境固有の情報をクリアしてくれるコマンド「virt-sysprep」で、いくつか消えてくれないものがあるっぽい?
https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/7/html/virtualization_deployment_and_administration_guide/cloning_virtual_machines
を参考に、手動で消すこととします。
(細かい検証はしていないので、もしかしたら消えてくれるかも?少なくとも、ifcfg-enp1s0の情報は消えてくれなかった)

まず、/etc/udev/rules.d/70-persistent-net.rulesを削除(/etc/sysconfig/network-scripts/ifcfg-ethXの採番ルールの設定値らしい)。

rm -f /etc/udev/rules.d/70-persistent-net.rules

そして「/etc/sysconfig/network-scripts/ifcfg-enp1s0」を、内容を全部消して、以下の2行だけ記載しておきます。

DEVICE=enp1s0
ONBOOT=yes

sshの鍵情報を、以下のコマンドで削除する。

rm -rf /etc/ssh/ssh_host_*


その後、仮想マシンをシャットダウンします。
仮想マシンのディスクが「/virt/centos8Template.qcow2」に作成されているとします。
まずは、検証用としてオリジナルを「/virt/centos8Template_tmp.qcow2」として、コピーして保存しておきます(これは、以下の作業が終わったら消してOK)。

cp /virt/centos8Template.qcow2 /virt/centos8Template_tmp.qcow2

仮想マシンの一覧を表示します。
さきほどテンプレート用に環境を設定した仮想マシンは「centos8Template」という名前です。

[root@miranda ~]# virsh list --all
 Id   名前              状態
--------------------------------------
 -    centos8Template   シャットオフ

テンプレートとして使用する仮想マシンに対し、固有の情報を削除する「virt-sysprep」を実行します。

virt-sysprep -d centos8Template

しばらくすると、処理が終わります。
これで「centos8Template.qcow2」は、固有の情報が削除され、テンプレートとして使用できるようになっている状態です。

以下の作業は不要ですが、「virt-sysprep」を実行する前後で、何が変更されているのかdiffを見ることができます。
(この作業が終わったら、上記作業でコピペして作成した「centos8Template_tmp.qcow2」は不要なので削除してしまってOK)

virt-diff -a /virt/centos8Template.qcow2 -A /virt/centos8Template_tmp.qcow2

これで、テンプレートとなるファイルの作成が完了しました。
次に、テンプレートを使って、仮想マシンを作成してみます。

以下のコマンドを実行します。
「--name」で指定しているのは、新しい仮想マシンの名前です。
「--auto-clone」のオプションを指定することで、テンプレートがあるディレクトリと同じディレクトリに、仮想マシンと同じ名前のファイル名が作成されます。

virt-clone --original centos8Template --name newGuest1 --auto-clone

再度、仮想マシンの一覧を表示するコマンドを実行すると、「newGuest1」が追加されていることが分かります。

[root@miranda ~]# virsh list --all
 Id   名前              状態
--------------------------------------
 -    centos8Template   シャットオフ
 -    newGuest1         シャットオフ

「virsh start newGuest」とコマンドを実行すれば、「newGuest1」が起動します。
テンプレートの作り方がまずいのか、1点修正したいところがあります。
仮想マシンにログインし、コネクション名を表示してみると、「System enp1s0」と頭に「System」とつくようになっちゃってました。

[root@localhost ~]# nmcli connection
NAME           UUID                                  TYPE      DEVICE
System enp1s0  c0ab6b8c-0eac-a1b4-1c47-efe4b2d1191f  ethernet  enp1s0
[root@localhost ~]# nmcli device
DEVICE  TYPE      STATE      CONNECTION
enp1s0  ethernet  connected  System enp1s0

ここままでもよいですが、デバイス名とコネクション名を同じにしておくと、テスト環境などでは便利なので同じにしたいため、以下のコマンドを実行し、コネクション名を「enp1s0」に修正します。
以下のコマンドで修正可能です。

[root@localhost ~]# nmcli connection  ←コネクションの一覧を表示(コネクションのUUIDを表示させる)
NAME           UUID                                  TYPE      DEVICE
System enp1s0  c0ab6b8c-0eac-a1b4-1c47-efe4b2d1191f  ethernet  enp1s0
[root@localhost ~]#nmcli con mod c0ab6b8c-0eac-a1b4-1c47-efe4b2d1191f connection.id enp1s0  ←enp1s0のUUIDを指定し、コネクション名を「enp1s0」に修正する
[root@localhost ~]# nmcli connection  ←コネクション名が修正されたか確認のため、コネクションを一覧表示
NAME    UUID                                  TYPE      DEVICE
enp1s0  c0ab6b8c-0eac-a1b4-1c47-efe4b2d1191f  ethernet  enp1s0

ページの一番上へ