犬でも分かるKVM(2): 外部ネットワークとブリッジ接続する

IT

仮想マシンを物理サーバの代わりとしていろいろなテストに使いたいのに、仮想マシンがNAT経由でしか外部ネットワーク(ここで言う「外部ネットワーク」はインターネットという意味ではなく、物理サーバが接続している物理ネットワークのことを指します)に接続できないことはとても不満でした。外部のネットワークから見たときに、物理サーバも仮想マシンも同じに見える、すなわち、外部ネットワークと同じセグメントのIPアドレスで直接アクセスできるようにしたいと思っています。今回は、ホストコンピュータのほうに仮想ブリッジを追加して、仮想マシンが外部のネットワークに直接接続するための方法を解説します。

(注記) 内容が長くなってしまっていますが、最も簡単で正しい方法は、最後の「(3) virt-install で仮想マシンを作成するときに、接続するブリッジの数分だけ –network bridge=ブリッジ名 を指定する」で書いた方法ですので、先にこっちを読んじゃってください(スミマセン)。

目指すゴール

今回目指す接続形態のゴールを以下に図示します。

我が家のホームネットワーク(青色)は、192.168.1.0/24 です。作成する仮想マシンにも、このホームネットワークのIPアドレスを付与して、ホームネットワークから直接アクセスできようにしたいと思っています。
そして、もうひとつ赤色で示したネットワーク「管理ネットワーク」(まあ名前はなんでも良いです)があります。これは、オイラがPXEブートのテストをするために作ったネットワークで、ホームネットワークとは別のネットワークスイッチに接続しています。PXEブートではDHCPサーバを運用するので、ホームネットワークとは別のセグメントにしておく必要があります。
お仕事で使うサーバは、1台で複数のLANポートを持っている場合も多く、LANポートを2つ持つMINIFORUM GK41は、お仕事の事前テストをするのにとても便利で安価なミニPCです。ちなみに、GMKtec NucBox3は、PXEブートでOSをインストールするテストに使う物理サーバ(ミニPC)なので、今回のKVMの話題とは直接関係はありません。

PXEブートに興味のある方は、「犬でも分かるPXEブートシリーズ」をご覧ください。PXEブートに必要な機能は、今回の手順で作成した仮想マシン上に整備しています。

初期状態

以下は、KVMをインストールした後、仮想マシン test0 を作成した直後のネットワークの状態です(初期状態)。LANポートを2つ有するホストコンピュータ base0 は、LAN1、LAN2に対してそれぞれ、IPアドレス 192.168.1.200と192.168.2.200 が割り当てられています。
仮想マシンはKVMが作成した仮想ブリッジvirbr0でホストコンピュータと接続しており、ホストコンピュータを経由して外部のネットワークとNATで接続しています。

KVMをインストールして、仮想マシンを作成する手順は「犬でも分かるKVM(1): KVMとは?」で解説しています。

ホストコンピュータで仮想ブリッジを作成する

仮想マシンが直接、外部のネットワーク(今回は、上図のホームネットワークと管理ネットワーク)に、同一のセグメントで接続するためには、ホストコンピュータ上に仮想ブリッジを作成する必要があります。外部のネットワークに接続しているデバイス(IPアドレスが割り当てられている)は enp2s0とenp3s0です。

初期のコネクションの状態

nmcli コマンドでコネクションの状態を確認してみましょう。

# nmcli c s
NAME    UUID                                  TYPE      DEVICE
enp2s0  34e0ca70-a3df-312c-a577-668de4714926  ethernet  enp2s0
enp3s0  f228f23f-1e05-4f91-9f96-8f502d69a762  ethernet  enp3s0
virbr0 d7f94fb4-6d70-4647-9c47-42db746366d0 bridge virbr0
vnet0  b7682c93-6498-4527-ae78-773ca9ce6e7d  tun       vnet
0

TYPEは接続の種類を表します。ethernetとなっているのは、通常のイーサネットデバイスです。bridgeとなっているのは仮想ブリッジです。そして、tunとなっているのはネットワークトンネルまたはTAPデバイスです。イーサネットデバイスがハードウェアのネットワークアダプタに対応するネットワークデバイスであるのに対して、ネットワークトンネルまたはTAPデバイスはソフトウェアによりサポートされるネットワークデバイスです。ネットワークトンネルはL3で動作するのに対して、TAPはL2で動作します。ネットワークトンネルまたはTAPデバイスは、仮想マシンのネットワークアダプタとして機能しますが、作成されるのはホストコンピュータ上であることに注意して下さい。そして、ネットワークトンネルまたはTAPデバイスは、仮想マシン内のイーサネットデバイスと1:1に対応します。

vnet0は仮想マシン test0 を作成したときに、仮想ブリッジvirbr0に接続するためのTAPデバイスです。vnet0に接続している仮想マシン内のイーサネットデバイスは enp1s です。

仮想ブリッジを作成する

ホストコンピュータ上で仮想ブリッジを作成します。今回の場合は、ホームネットワーク用と管理ネットワーク用に、2つの仮想ブリッジを作成します。以下は管理ネットワーク用の仮想ブリッジを作成する手順です。

仮想ブリッジを作成します。名前は br3 としています。

# nmcli c add type bridge ifname br3
Connection 'bridge-br3' (c458bf04-155c-4335-bbbd-1cf011f629f0) successfully added.

作成後に、デバイスとコネクションを確認すると、デバイス br3 に対応した bridge-br3 というコネクションが作成されたことが分かります。

# nmcli d s
DEVICE  TYPE      STATE                                  CONNECTION

br3     bridge    connecting (getting IP configuration)  bridge-br3

# nmcli c s
NAME        UUID                                  TYPE      DEVICE

bridge-br3  422b512f-7739-49cf-85a9-fcf5fe768042  bridge    br3

ブリッジを作成するとデフォルトでスパニングツリーが有効になっています。単独のブリッジとして動かすのでスパニングツリーは不要で、余計なパケットを流すので以下のコマンドで無効化します。

# nmcli c m bridge-br3 bridge.stp no

作成した仮想ブリッジ br3 のコネクション bridge-br3 に対して、元のコネクション enp3s0 で使用していたIPアドレスを割り当てます(この場合は 192.168.2.200/24)。

# nmcli c m bridge-br3 ipv4.method manual ipv4.addresses "192.168.2.200/24"

作成した仮想ブリッジ br3 (コネクション bridge-br3) をマスターとして に、元の ネットワークデバイス enp3s0 を bridge-slave として接続します。

# nmcli c add type bridge-slave ifname enp3s0 master bridge-br3
Connection 'bridge-slave-enp3s0' (b88d0057-e8e1-4738-9d65-dd0a225ac488) successfully added.

接続後に、コネクションを確認すると、仮想ブリッジ(ブリッジマスター) bridge-br3 、ブリッジスレーブ bridge-slave-enp3s0 というコネクションが存在することが分かります。

# nmcli c s
NAME                 UUID                                  TYPE      DEVICE

bridge-br3           422b512f-7739-49cf-85a9-fcf5fe768042  bridge    br3
enp3s0               f228f23f-1e05-4f91-9f96-8f502d69a762  ethernet  enp3s0
bridge-slave-enp3s0  b88d0057-e8e1-4738-9d65-dd0a225ac488  ethernet  --

ネットワークデバイス enp3s0 に対応するコネクションをブリッジスレーブとして作成したので、もともとネットワークデバイス enp3s0に対応していたコネクション enp3s0 は不要なので削除します。

# nmcli c delete enp3s0
Connection 'enp3s0' (f228f23f-1e05-4f91-9f96-8f502d69a762) successfully deleted.

その後、ホストコンピュータをリブートして、デバイスとコネクションを再度確認します。
(ホストコンピュータをリブートする前に、仮想マシンは全て停止しておいて下さい)

# nmcli d s
DEVICE  TYPE      STATE      CONNECTION

br3     bridge    connected  bridge-br3
enp3s0  ethernet  connected  bridge-slave-enp3s0

管理ネットワーク用の仮想ブリッジの作成に成功したら、同じ方法でホームネットワーク用の仮想ブリッジ(ブリッジマスター)を、
デバイス名 br2
コネクション名 bridge-br2
として作成し、仮想ブリッジ br2 に接続するブリッジスレーブ を、
デバイス名 enp2s0
コネクション名 bridge-slave-enp2s0
として作成します(再生したら、同様にホストコンピュータをリブートします)。

※ちなみに、ホームネットワーク経由でホストコンピュータにsshログインしている場合、ネットワーク設定の変更によって接続が切断されるので、その点に注意して下さい。コンソールディスプレイ等から操作するのが良いかと思います。

ここまで設定を終えた状態のホストコンピュータのネットワークを図示すると以下のようになっています(仮想マシンを起動していない状態)。

また、仮想マシン test0 を起動すると接続状態は、以下の図のようになります。

ホストコンピュータにおけるデバイスとコネクションの状態を表示すると、以下の通りになっています。

# nmcli d s
DEVICE  TYPE      STATE                   CONNECTION
br2     bridge    connected               bridge-br2
br3     bridge    connected               bridge-br3
virbr0  bridge    connected (externally)  virbr0
vnet0   tun       connected (externally)  vnet0
enp2s0  ethernet  connected               bridge-slave-enp2s0
enp3s0  ethernet  connected               bridge-slave-enp3s0

# nmcli c s
NAME                 UUID                                  TYPE      DEVICE
bridge-br2           5cfbc2a3-cbb0-4c2e-b8b1-93e8fe48ff16  bridge    br2
bridge-br3           422b512f-7739-49cf-85a9-fcf5fe768042  bridge    br3
virbr0               aef79783-501d-4a4c-ba3e-bdf551a6dd64  bridge    virbr0
vnet0                b7682c93-6498-4527-ae78-773ca9ce6e7d  tun       vnet0
bridge-slave-enp2s0  ac7b68cf-c64d-4a27-ab62-92db5b6c53e7  ethernet  enp2s0
bridge-slave-enp3s0  b88d0057-e8e1-4738-9d65-dd0a225ac488  ethernet  enp3s0

(注記) ホストコンピュータ上で仮想ブリッジを作成する方法は、犬でも分かるLinuxネットワーク設定(3): 仮想ブリッジでも解説しています。

TAPデバイスを追加する

ホストコンピュータ上で仮想ブリッジを作成しただけでは、仮想マシンは仮想ブリッジに接続できません。前述の通り、ホストコンピュータ上で、TAPデバイスを作成してあげる必要があります。
仮想マシン test0 が起動している状態で、仮想マシン test0 が仮想ブリッジ br2, br3 に接続するためのTAPデバイスを作成するコマンドは以下の通りです。

# virsh attach-interface --type bridge --source br2 --model virtio test0
# virsh attach-interface --type bridge --source br3 --model virtio test0

この状態で、ホストコンピュータのデバイスとコネクションの状態の確認をすると、以下の通りになっています。TABデバイス、vnet1, vnet2 が追加されていることが分かります。

# nmcli d s
DEVICE  TYPE      STATE                   CONNECTION
br2     bridge    connected               bridge-br2
br3     bridge    connected               bridge-br3
virbr0  bridge    connected (externally)  virbr0
vnet0   tun       connected (externally)  vnet0
vnet1   tun       connected (externally)  vnet1
vnet2   tun       connected (externally)  vnet2
enp2s0  ethernet  connected               bridge-slave-enp2s0
enp3s0  ethernet  connected               bridge-slave-enp3s0

# nmcli c s
NAME                 UUID                                  TYPE      DEVICE
bridge-br2           5cfbc2a3-cbb0-4c2e-b8b1-93e8fe48ff16  bridge    br2
bridge-br3           422b512f-7739-49cf-85a9-fcf5fe768042  bridge    br3
virbr0               aef79783-501d-4a4c-ba3e-bdf551a6dd64  bridge    virbr0
vnet0                b7682c93-6498-4527-ae78-773ca9ce6e7d  tun       vnet0
vnet1                89f787b9-35c4-485c-8179-92d65c8daec2  tun       vnet1
vnet2                8d3faedb-388e-4c5a-b911-fc626b30896a  tun       vnet2
bridge-slave-enp2s0  ac7b68cf-c64d-4a27-ab62-92db5b6c53e7  ethernet  enp2s0
bridge-slave-enp3s0  b88d0057-e8e1-4738-9d65-dd0a225ac488  ethernet  enp3s0

この状態で、仮想マシン test0 にログインして、デバイスを確認すると、あら不思議。ネットワークデバイス enp7s0, enp8s0 が追加されています。TAPデバイスの作成順序を考慮すると、enp7s0のほうが 仮想ブリッジbr2に接続可能なネットワークデバイスですね。

# nmcli d s
DEVICE TYPE STATE CONNECTION
enp1s0 ethernet connected enp1s0
enp7s0 ethernet connected --
enp8s0 ethernet connected --

ネットワークデバイスが見える状態になったので、物理サーバと同様の手順でコネクションを作成して、固定のIPアドレスを割り当てます。
以下は、enp8s0に対応したコネクション enp8s0 を作成して、192.168.2.2 を割り当てる手順です。

# nmcli c add type ethernet con-name enp8s0 ifname enp8s0
Connection 'enp8s0' (f228f23f-1e05-4f91-9f96-8f502d69a762) successfully added.
# nmcli c m enp8s0 ipv4.addresses 192.168.2.2/24
# nmcli c m enp8s0 ipv4.method manual
# nmcli c m enp8s0 connection.autoconnect yes
# nmcli c m enp8s0 ipv6.method ignore
# nmcli c up enp8s0
Connection successfully activated (D-Bus active path: /org/freedesktop/NetworkManager/ActiveConnection/5)

同様に、以下はenp7s0に対応したコネクション enp7s0 を作成して、192.168.1.2 を割り当てる手順です。enp7s0はホームネットワークに接続するインターフェースですので、デフォルトゲートウェイの指定とDNSサーバの指定をenp7s0に対して設定するようにしましょう。

# nmcli c add type ethernet con-name enp7s0 ifname enp7s0
Connection 'enp7s0' (4fde4e47-c0d7-322d-9ecb-31e0652f515a) successfully added.

# nmcli c m enp7s0 ipv4.addresses 192.168.1.2/24
# nmcli c m enp7s0 ipv4.gateway "192.168.1.1"
# nmcli c m enp7s0 ipv4.dns  "192.168.1.1"
# nmcli c m enp7s0 ipv4.method manual

# nmcli c m enp7s0 connection.autoconnect yes
# nmcli c m enp7s0 ipv6.method ignore
# nmcli c up enp7s0

Connection successfully activated (D-Bus active path: /org/freedesktop/NetworkManager/ActiveConnection/4)

同時に、enp1s0のほうに設定していた、デフォルトゲートウェイの指定とDNSサーバの指定を削除しましょう。また、このタイミングでネットワーク設定もdynamic(DHCP)からstatic(固定)に変えてしまいましょう。

# nmcli c m enp1s0 ipv4.addresses 192.168.122.2/24
# nmcli c m enp1s0 ipv4.method manual
# nmcli c m enp1s0 ipv6.method ignore

# nmcli c m enp1s0 connection.autoconnect yes
# nmcli c up enp1s0

この状態におけるホストコンピュータと仮想マシンの接続状態は以下の図の通りです。

仮想マシンを停止するとTAPデバイスは消えてしまう..

ところで、このようにせっかく TAPデバイスを作成しても、仮想マシンを停止するとTAPデバイスは消失してしまいます。これに対応する方法は3つあります。
(3つ目の方法は 2024/9/8に追記しました… 実はこの3番目が一番一般的な方法です… ゴメンなさい)

(1)仮想マシンを起動した後で再度TAPデバイスを作成する

まー、そりゃそうだよな(笑)。以下のようにして、仮想マシン test0 を起動した後に、前述の方法でTAPデバイスをもう一度作成すれば良いのです。

# virsh start test0
# virsh attach-interface --type bridge --source br2 --model virtio test0
# virsh attach-interface --type bridge --source br3 --model virtio test0

仮想マシン test0 のOSのほうでは、対応するコネクションは作成済なので、改めて作成する必要はありません。

(2)仮想マシンのXML設定ファイルにブリッジとの接続を追加する

こちらのほうがよりスマートな方法です。
仮想マシンのXMLファイルに、仮想ブリッジとの接続を定義しておけば、仮想マシンを起動したときに自動的に仮想ブリッジに接続する(すなわちTAPデバイスも自動的に作成される)ことができます。
仮想マシン test0 のXML定義ファイルは、以下のパスに存在します。

/etc/libvirt/qemu/ldap0.xml

これを修正するのはハードルが高いですよね。でも良い方法があります。
仮想マシン test0 が仮想ブリッジに接続している状態で、以下のようにしてXML設定ファイルをダンプしてあげるのです。

# virsh dumpxml test0 > /tmp/test0.xml

オリジナルの /etc/libvirt/qemu/test0.xml と比較(diff)すると、仮想ブリッジ br2 と br3 に接続するための定義が追加されていることが分かります。
このようにダンプ出力したXML定義ファイルを、オリジナルの /etc/libvirt/qemu/test0.xml に反映してあげれば良いのですが、以下の手順で行って下さい。

・オリジナルの XML設定ファイル /etc/libvirt/qemu/test0.xml をバックアップ (起動できなくなったときのため)
・仮想マシン test0 を停止
・以下のように、ダンプ出力したXML定義ファイル /tmp/test0.xml を /etc/libvirt/qemu/test0.xml に反映

# cat /tmp/test0.xml > /etc/libvirt/qemu/test0.xml
# virsh define /etc/libvirt/qemu/test0.xml

・仮想マシン test0 を起動

このようにXML設定ファイルを更新しておけば、次回以降は test0を起動するだけで、ブリッジ br2, br3 に接続できます。

(3) virt-install で仮想マシンを作成するときに、接続するブリッジの数分だけ –network bridge=ブリッジ名 を指定する

仮想マシンを作成する前に、ホストコンピュータ上で必要な個数の仮想ブリッジが準備されているのであれば、仮想マシンをこれらの仮想ブリッジに接続するように作成するのはとても簡単です。

virt-install の「 --network オプション」では、仮想マシンが接続するネットワークを指定することができます。KVMをインストールした直後から、virbr0という仮想ブリッジが作成されていますので、最初に仮想マシン test0 を作成したときは、以下の例のようにvirt-installコマンドを実行して、virbr0に接続するようにしていました。

virt-install \
--name test0 \
--ram 4096 \
--disk path=/var/lib/libvirt/images/test0.qcow2,size=20 \
--vcpus 1 \
--os-variant rocky9 \
--network bridge=virbr0 \
--graphics none \
--console pty,target_type=serial \
--location /export/data/IMAGES/ISO/Rocky-9.4-x86_64-dvd.iso \
--extra-args 'console=ttyS0,115200n8'

もし、仮想マシンを作成する前に、今回の例のように仮想ブリッジbr2,br3 が作成されているのであれば、virt-installを実行するときに、全ての仮想ブリッジに接続するように「 --network オプション」を追加しちゃって下さい。具体的には、以下の例のように実行すればOKです。

virt-install \
--name test0 \
--ram 4096 \
--disk path=/var/lib/libvirt/images/test0.qcow2,size=20 \
--vcpus 1 \
--os-variant rocky9 \
--network bridge=virbr0 \
--network bridge=br2 \
--network bridge=br3 \

--graphics none \
--console pty,target_type=serial \
--location /export/data/IMAGES/ISO/Rocky-9.4-x86_64-dvd.iso \
--extra-args 'console=ttyS0,115200n8'

このように作成すれば、仮想マシンが作成(起動)した直後からTAPデバイスは自動的に作成され、仮想マシンのOS内では、virbr0,br2,br3 のそれぞれに接続可能なネットワークデバイスも作成されています。
仮想マシンのXML設定ファイルにも、br2,br3に接続するための設定が定義されていますので、2回目以降の起動でも自動的に仮想ブリッジに接続されます。

また今回のように、仮想マシン test0 をvirbr0だけに接続するようにvirt-installを実行して作成した場合では、前述の(1)(2)に示す方法で、br2,br3に接続させ、XML設定ファイルも更新するということをやりましたが、もっと簡単な方法を以下に示します。

virt-installの「--import オプション」で、既存の仮想マシンのイメージを使用しつつ、新しい仮想マシンとして再登録する(XML設定ファイルも再作成される)のです。このとき、仮想マシンの名前には新しい名前を付けます。

virt-install \
--import \
--name test01 \
--ram 4096 \
--disk path=/var/lib/libvirt/images/test0.qcow2,size=20 \
--vcpus 1 \
--os-variant rocky9 \
--network bridge=virbr0 \
--network bridge=br2 \
--network bridge=br3 \

--graphics none \
--console pty,target_type=serial \
--extra-args 'console=ttyS0,115200n8'

最初からこの方法を紹介しなくてゴメンなさい(まさか、--network オプションを何個も追加できるとは思わなかった)。でも、私はこの方法を知らなかったおかげで、TAPデバイスのような存在を勉強することができました。

広告主へのリンク




ミニPCのお勧め

おウチでLinuxを勉強するのに、ミニPCはどうですか。
仮想環境(KVM)使えば、仮想マシンを複数起動できますし、とても安価にシステム構築の練習ができます。ミニPCはとっても静かで消費電力も小さいので部屋で常時起動させています。

このブログにおける関連リンク

犬でも分かるKVMシリーズ
犬でも分かるPXEブートシリーズ

コメント

タイトルとURLをコピーしました