Nested KVMでCockpitを試してみる
homelabでKVMとCockpitを利用するケースを見かけるようになったため、ESXi上にNestedでKVMを構築し、Cockpitで仮想マシンの構築ができるか試してみました。
構成
KVMとは
KVM (Kernel-based Virtual Machine) は、Linuxカーネルに組み込まれた仮想化技術です。KVM を使用すると、Linux をハイパーバイザーとして機能させることができます。
Cockpitとは
Cockpitは、Webベースのサーバー管理インターフェイスで、コマンドラインを使わなくてもサーバーの状態を確認したり、設定変更を行うことができます。また、KVMの仮想マシンも管理することができます。
Nested KVMのセットアップ
Nested KVMを用意するために、Ubuntuをインストールした仮想マシンを用意します。
KVM用のUbuntu VMの仮想マシンの設定の編集を開き、CPUのハードウェア仮想化にチェックを入れておきます。
ネットワークはまずはVLANを指定したポートグループを接続しておきます。
インストール
以下で必要なパッケージをインストールしておきます。
$ sudo apt install -y qemu-kvm virt-manager libvirt-daemon-system \ virtinst libvirt-clients bridge-utils
libvirtdのサービスを有効化しておきます。
$ sudo systemctl enable --now libvirtd $ sudo systemctl start libvirtd $ sudo systemctl status libvirtd
kvmグループにユーザを追加します。
$ sudo usermod -aG kvm $USER $ sudo usermod -aG libvirt $USER
Cockpitをインストールします。
$ sudo apt install cockpit $ sudo systemctl start cockpit $ sudo systemctl status cockpit
http://<IPアドレス>:9090 でCockpitのWeb UIにアクセスできることを確認します。

Cockpitはネットワーク管理にNetworkManagerを使っており、Cockpit上でネットワーク設定をするために、ネットワーク管理をNetworkManagerに変更します。
$ sudo vi /etc/netplan/01-custom-config.yaml network: renderer: NetworkManager version: 2 $ sudo netplan apply
systemd-networkd-wait-onlineのサービスがfailedになるため、サービスを停止させておきます。
$ systemctl status systemd-networkd-wait-online
× systemd-networkd-wait-online.service - Wait for Network to be Configured
Loaded: loaded (/lib/systemd/system/systemd-networkd-wait-online.service; enabled; vendor preset: disabled)
Active: failed (Result: exit-code)
Docs: man:systemd-networkd-wait-online.service(8)
Process: 885 ExecStart=/lib/systemd/systemd-networkd-wait-online (code=exited, status=1/FAILURE)
Main PID: 885 (code=exited, status=1/FAILURE)
CPU: 6ms
$ sudo systemctl stop systemd-networkd-wait-online.service
$ sudo systemctl disable systemd-networkd-wait-online.service
$ sudo systemctl mask systemd-networkd-wait-online.service
こちらの状態で、ログインし、ネットワークはこのように表示されます。

初期状態では、 virbr0 というブリッジが作成されており、libvirt が自動的に仮想ネットワークを用意してくれています。
$ brctl show bridge name bridge id STP enabled interfaces virbr0 8000.5254001f7a81 yes
$ nmcli device show virbr0 GENERAL.DEVICE: virbr0 GENERAL.TYPE: bridge GENERAL.HWADDR: 52:54:00:1F:7A:81 GENERAL.MTU: 1500 GENERAL.STATE: 100 (connected (externally)) GENERAL.CONNECTION: virbr0 GENERAL.CON-PATH: /org/freedesktop/NetworkManager/ActiveConnection/1 IP4.ADDRESS[1]: 192.168.122.1/24 IP4.GATEWAY: -- IP4.ROUTE[1]: dst = 192.168.122.0/24, nh = 0.0.0.0, mt = 0 IP6.GATEWAY: --
外部ネットワークへの通信は iptables によってNAT、DHCPはdnsmasqが行ってそうです。
$ sudo iptables -t nat -nvL
Chain LIBVIRT_PRT (1 references)
pkts bytes target prot opt in out source destination
1 40 RETURN all -- * * 192.168.122.0/24 224.0.0.0/24
0 0 RETURN all -- * * 192.168.122.0/24 255.255.255.255
0 0 MASQUERADE tcp -- * * 192.168.122.0/24 !192.168.122.0/24 masq ports: 1024-65535
0 0 MASQUERADE udp -- * * 192.168.122.0/24 !192.168.122.0/24 masq ports: 1024-65535
0 0 MASQUERADE all -- * * 192.168.122.0/24 !192.168.122.0/24
$ ps aux | grep dnsmasq libvirt+ 107607 0.0 0.0 10084 388 ? S 21:11 0:00 /usr/sbin/dnsmasq --conf-file=/var/lib/libvirt/dnsmasq/default.conf --leasefile-ro --dhcp-script=/usr/lib/libvirt/libvirt_leaseshelper
仮想マシンを管理するために、以下のインストールを行います。
$ sudo apt install cockpit-machines
こちらの状態で、仮想マシンを作成してみます。

デフォルトで、ネットワークはdefaultのvirbr0に接続するような設定になっています。

ネットワークの構成を図にすると以下のようになります。
┌─────────────────────┌──────────────┐───────────────────────┐ │ KVM Host │ ens192 │ │ │ └───────┬──────┘ │ │ │ NAT(iptables) │ │ ┌───────┴──────┐ │ │ │ virbr0 │ 192.168.122.1/24 │ │ └───────┬──────┘ │ │ │ interface member │ │ ┌───────┴──────┐ │ │ │ vnet0 │ 192.168.122.2/24 │ │ └───────┬──────┘ │ │ ┌───────┴──────┐ │ │ │ VM │ │ │ └──────────────┘ │ └────────────────────────────────────────────────────────────┘
VLANトランクへの変更
外部からのアクセスや、ネットワークをNested ESXiライクに変更するために、Nested KVMのポートグループをVLANトランクに変更します。
Cockpitのネットワークの設定で、bridge50 という名前でブリッジを追加します。
VLANの追加で、親に bridge50 を指定し、VLAN IDに50、名前を vlan.50 を入れ追加します。

仮想マシンのネットワークの設定を、インターフェイス形式を Bridge to LAN 、ソースを bridge50 に変更します。

この状態で、同じVLANからsshで接続できることを確認します。
ネットワークの構成を図にすると以下のようになります。
┌──────────────┐
│ Trunk VLAN │
└───────┬──────┘
┌─────────────────────┌───────┴──────┐───────────────────────┐
│ KVM Host │ ens192 │ │
│ └───────┬──────┘ │
│ │ │
│ ┌───────┴──────┐ │
│ │ vlan.50 │ VLANID 50 │
│ └───────┬──────┘ │
│ │ interface member │
│ ┌───────┴──────┐ │
│ │ brige50 │ │
│ └───────┬──────┘ │
│ │ interface member │
│ ┌───────┴──────┐ │
│ │ vnet0 │ │
│ └───────┬──────┘ │
│ ┌───────┴──────┐ │
│ │ VM │ │
│ └──────────────┘ │
└────────────────────────────────────────────────────────────┘
現在の構成だと、KVMホストごとにネットワークの設定を行っているため、KVMホスト1台や数台に管理にはCockpitが向いていそうに見えます。