KVMでsystemd-networkdを用いてブリッジ構築をする方法
これはKMC Advent Calendar 2022 - Adventar の9日目の記事です。
昨日はcrashRTさんの「After Effects おすすめチュートリアル」でした。
はじめに
こんにちはこんにちは。KMC2回生のsegreです。昨日まで第45代の副会長をしていました。今年からは副代表としてもう1年仕事をします(何をするのか全くわかっていませんが...)。最近は趣味の釣りもオフシーズンに入り、サーバーの環境構築をしたりLinuCの勉強をしたりとLinuxに浸かった生活をしています。
さて、この記事ではLinuxでKVMの仮想マシンをsystemd-networkd環境でブリッジを構築し外部と接続する方法についてお話します。
KVMについて
KVM (Kernel-based Virtual Machine) とはLinuxに組み込まれたオープンソースの仮想化ソフトウェアと一般的に説明されます。KVMはLinuxカーネルをハイパーバイザーに変換させ、仮想ネットワークカード、グラフィックアダプター、CPU、メモリー、ディスクなどを備えています。
ただし、KVMは仮想化ソフトウェアではなくカーネルモジュールとしてLinuxに組み込まれているものであり、QEMUによるエミュレーションを支援するという説明がより正確なものとなります。この部分の説明は本記事の趣旨とは外れるため詳しくは
QEMU、KVM、libvirtの基礎知識まとめ - えんでぃの技術ブログ などを参照してください。
KVMで仮想マシンを作成
今回はこちらのコマンドでUbuntu Server 22.04.1 仮想マシンtest_vmを作成しました。
# virt-install \ --connect=qemu:///system \ -n test_vm \ -r 2048 \ --disk path=/var/lib/libvirt/images/test_vm/root.img,size=20 \ --check path_in_use=off \ --vcpus=2 \ --os-variant=ubuntu22.04 \ --network network=default \ --location /home/segre/Documents/iso/ubuntu-22.04.1-live-server-amd64.iso,kernel=casper/vmlinuz,initrd=casper/initrd \ --console pty,target_type=serial\ --nographics \ --extra-args 'console=ttyS0 115200n8 serial'
ここでnetwork network=default
と指定していることに注意して下さい。
networkにdefaultを指定するとどうなるか
network network=default
と指定すると、仮想マシンが外部ネットワークと通信する際にiptablesのNAT(IPマスカレード)機能が用いられます。
IPマスカレード機能を用いると、仮想ブリッジvirbr0を作成し、virbr0に到達したパケットは、送信元IPアドレスを物理NICのIPアドレスに変換して外部ネットワークに送信します。
ここでNIC、eth、vnet、brについて説明します。
- NIC : ネットワークインターフェースカードの略でネットワーク通信に必要なカード型の機器であり、イーサネットを挿すためのコネクタなどが付いています。
- eth : イーサネットの略でネットワークインターフェースを指します。IPアドレスが割り当てられ、NIC内でのネットワーク通信を担っています。仮想ネットワークインターフェースの場合はveth0/veth1などと表されることが多いです。
- vnet : タップデバイスを表しています。KVMにおいてホストマシンが仮想マシンに接続するために用いられるデバイスです。
- br : 仮想ブリッジを表しています。virbrは仮想環境でIP変換を行うためのスイッチ、brは仮想ブリッジを接続するためのスイッチです(後述)。
図からも分かる通り、仮想マシンから外部へ通信することはできますが、外部から仮想マシンに通信することはできません。そのため、外部から通信したい場合はbr0を作成し、仮想ブリッジを構築する必要があります。続いての章ではその方法を説明します。
物理NICを仮想スイッチに接続する
物理NICを仮想スイッチに接続する仮想ブリッジを作成することにより外部と通信することができるようになります。ここではsystemd-networkdによって仮想ブリッジbr0を作成します。なおLinuxでは他にNetworkManagerによって管理する方法もあり、NetworkManagerの場合は設定方法が違うことに注意してください。
ネットワーク設定の確認をする
まずはネットワークがどのような構成になっているか確認します。
$ brctl show
コマンドによりブリッジとそのブリッジに取り付けられたインターフェースを表示することができます。
$ brctl show bridge name bridge id STP enabled interfaces virbr0 XXXX.YYYYYYYYYYYY yes vnet3
systemd-networkdによって管理されている場合はvirbr0という仮想ブリッジが表示されていると思います。ここではvnet3というタップデバイスが接続されていることがわかります。インターフェースの詳細を確認するには$ ip link show master virbr0
から確認することができます。
続いて仮想マシンのvethがどのタップデバイスに接続されているか確認するためには$ virsh dumpxml VM名
を実行して仮想マシンの設定xmlファイルのinterfaceタグを確認します。今回はVMを1つしか作成していないのでtest_vmのveth0がvnet3に接続されているかがわかりますが、VMが複数ある場合はこのコマンドによって確認する必要があります。test_vmのxmlを見てみると
<interface type='bridge'> <mac address='XX:XX:XX:XX:XX:XX'/> <source bridge='virbr0'/> <target dev='vnet0'/> <model type='virtio'/> <alias name='vnet3'/> </interface>
となっていることからvnet3に接続されていることがわかります。
ブリッジを定義する
続いてnetworkファイルを編集していきます。なお、brctl
コマンドを用いてブリッジを構築することもできますが、brctlによって作られたブリッジは再起動すると消えてしまうため、今回はnetworkファイルを編集する方法を紹介します。
systemd-networkdではネットワークファイルは/etc/systemd/network/
以下に保存されています。
$ ls /etc/systemd/network -l total 8 -rw-r--r-- 1 root root 223 Aug 23 13:39 eth0.network
eth0の設定ファイルがあることからIPマスカレードが用いられていることがわかります。このファイルの中身を見てみると
$ cat eth0.network [Match] Name=eth0 [Network] Address=XXX.YYY.ZZZ.AA/24 Gateway=XXX.YYY.ZZZ.1
となっています。
ファイル内容を説明します。[Match]セクションにはどのインターフェースを用いているか記述します。Name=
とするとデバイス名のリストにマッチします。
[Network]セクションにはDHCHの設定等のネットワークの設定を記述します。Adress=
とするとIPアドレスをNICに割り当てることができます。また、Gateway=
とするとデフォルトゲートウェイを設定できます。
なお、Adress=
とGateway=
はそれぞれ[Adress]セクションと[Gateway]セクションに入れるのが適切ですが、[Address] が Address キーだけを含み [Route] セクションが Gateway キーだけを含む場合、略式表記として [Network] セクションに Address=
と Gateway=
を記述することができます。
ここからはブリッジbr0を定義していきます。新しいブリッジを定義するためにはnetworkファイルとnetdevファイルを作成する必要があります。ここではbr0.network
とbr0.netdev
を作成します。
br0.netdev
ファイルは
$ cat br0.netdev [NetDev] Name=br0 Kind=bridge
とするとブリッジbr0を定義できます。
続いてbr0.network
はこれまでeth0.network
に記述されていた内容を書きます。そのため
$ cat br0.network [Match] Name=eth0 [Network] Address=XXX.YYY.ZZZ.AA/24 Gateway=XXX.YYY.ZZZ.1
とするのが適切です。
eth0.networkはブリッジbr0に接続しているため
$ cat eth0.network [Match] Name=eth0 [Network] Bridge=br0
とします。
以上を記述して# sysmctl restart sysytemd-networkd
とすると仮想ブリッジを作成することができます。
タップデバイスとブリッジを接続する
最後に先程定義したbr0とタップデバイスvnet0を接続すると通信することができます。VMの設定を変更するためにはxmlファイルを編集します。
# virsh edit test_vm
とするとxmlファイルを編集できます。# virsh shutdown test_vm
でVMをshutdownしてから、ファイル中のinterfaceセクションの
<interface type='bridge'> <mac address='XX:YY:XX:YY:XX:YY'/> <source bridge='br0'/> <model type='virtio'/> </interface>
以上でブリッジを構築することができます。brctl
を確認してみてください。
$ brctl show bridge name bridge id STP enabled interfaces br0 XXXX.YYYYYYY no eth0 vnet0 virbr0 XXXX.YYYYYYY yes
# virsh start test_vm
すると、br0がeth0とvnet0をつなぎ、外部から通信できるようになっていると思います。
まとめ
今回はsystemd-networkd環境でKVMで新しくブリッジを作成し外部から通信する方法を紹介しました。
まとめると
NetworkManager/Systemd-Networkd/Netplanかを確認
brctl show
やip link show master virbr0
、virsh xmldump [VM]
などからネットワーク図作成 systemd-networkd/etc/systemd/network/
以下にブリッジ定義 → networkd restart
となります。
今後はitamaeを用いたサーバー管理等を勉強していきたいです。 ありとうございました。
明日はtenさんの「『実装意図』を語るために」です。
参考にさせていただいた記事
・ KVM とは - Linux 仮想化の仕組み | Red Hat