2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

OVS+namespaceで仮想的なネットワークを構築してみる

Last updated at Posted at 2023-04-08

こんにちは。
株式会社クラスアクトインフラストラクチャ事業部の大塚と申します。
この記事では題名の通り、OVSとnamespaceを用いサーバ内部に仮想的なネットワークを構築していきたいと思います。

なぜOVSを触ってみるのか?

①弊社でProxmox VEを触る機会が増え、Proxmox VEはOVSが利用可能で、理解しておくと今後何かと便利かと考えたため
②個人的にopenstackの勉強をしていた時期があるのだが、その中でOVSの話があり、触りたいと思っていたため

OVSとは?

Open vSwicthの略。
ざっくりな理解で恐縮ですが、個人的には
「サーバ内に仮想的なbridgeやveth(Virtual ETHernet)を作成するためのもの」
という認識を持っています。

私はこのOVSという技術をopenstackで初めて知りました。
openstackだけではなく、dockerやkubernetes、KVM等でも使用できることから、今後の仮想化技術をより理解しるためには
避けては通れない道かと考えております。

namespaceとは?

これもざっくりな理解で恐縮ですが、個人的には
「1つのOS空間をいくつかに分断して、分断した空間同士でプロセス等を秘匿化(見えないようにすること)で、あたかも複数のサーバが稼働しているように見える」
という認識です。
dockerやコンテナ技術について1度でも見たり聞いたりしたことがある方は、それをイメージしてもらえればいいのかなと思っています。
※基本的にはnamespaceありきのdockerだと思いますので、本当であれば順序は逆だと思いますが・・・

例えば1つのOSを特に仮想的に分断しないでそのまま使用し、サーバ上に様々なアプリケーションが乱立していることを想像してみます。
この状態だと、プロセスもアプリケーションの数に比例して増えてしまう可能性があり、その結果OS環境がごちゃごちゃしてしまいます。
ovs-ページ9.drawio.png

namespaceを使うことで、例えば各アプリケーションごとに分断した空間を提供することができ、結果ごちゃごちゃが解消され運用保守なども行いやすくなるでしょう。
※図に使用しているイラストはicons8になります
ovs-ページ10.drawio.png

構築

今回はProxmox VE上にubuntu22.04でVMを立ち上げ、そこにプライベートネットワークを構築していきます。
HW構成は以下となります。
image.png

この記事では以下のネットワークをサーバ内に構築し、namespaceAとnamespaceC及びnamespaceBとnamespaceDの疎通確認まで行っていきたいと思います。
ovs-ページ6.drawio.png

また、以下の記事を参考にしています。
図とコマンドが簡潔に表示されており、非常にわかりやすかったです。
この記事は参考記事をほぼ写経しているような形ですが、図を多めに配置し、
よりグラフィカルにイメージできるようにしてみました。主に私のために

まずVM上にovsをインストールしていきます。
インストールができましたら、start,enableも忘れずに行っておきましょう。

root@ovs-test:~# apt install -y openvswitch-switch
root@ovs-test:~# systemctl start openvswitch-switch 
root@ovs-test:~# systemctl status openvswitch-switch 
● openvswitch-switch.service - Open vSwitch 
     Loaded: loaded (/lib/systemd/system/openvswitch-switch.service; enabled; vendor preset: enabled) 
     Active: active (exited) since Mon 2023-03-27 21:38:47 UTC; 44s ago 
    Process: 3886 ExecStart=/bin/true (code=exited, status=0/SUCCESS) 
   Main PID: 3886 (code=exited, status=0/SUCCESS) 
        CPU: 1ms 
Mar 27 21:38:47 ovs-test systemd[1]: Starting Open vSwitch... 
Mar 27 21:38:47 ovs-test systemd[1]: Finished Open vSwitch. 
root@ovs-test:~# systemctl enable openvswitch-switch 
Synchronizing state of openvswitch-switch.service with SysV service script with /lib/systemd/systemd-sysv-install. 
Executing: /lib/systemd/systemd-sysv-install enable openvswitch-switch

このタイミングでipコマンドを打っておき、出力の変化を確認できるようにしておきます。

root@ovs-test:~# ip a 
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 
    inet 127.0.0.1/8 scope host lo 
       valid_lft forever preferred_lft forever 
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever 
2: ens18: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 
    link/ether 52:d8:9a:43:a5:d6 brd ff:ff:ff:ff:ff:ff 
    altname enp0s18 
    inet 192.168.2.186/24 metric 100 brd 192.168.2.255 scope global dynamic ens18 
       valid_lft 348sec preferred_lft 348sec 
    inet6 fe80::50d8:9aff:fe43:a5d6/64 scope link 
       valid_lft forever preferred_lft forever

ブリッジを作成します。
ブリッジの名前は"ovsA"と"ovsB"としました。
ovs-vsctl showコマンドで作成したブリッジが表示されていることを確認します。

root@ovs-test:~# ovs-vsctl add-br ovsA 
root@ovs-test:~# ovs-vsctl add-br ovsB 
root@ovs-test:~# ovs-vsctl show 
d9f37d67-9065-4bed-8741-30a72b02542c 
    Bridge ovsB 
        Port ovsB 
            Interface ovsB 
                type: internal 
    Bridge ovsA 
        Port ovsA 
            Interface ovsA 
                type: internal 
    ovs_version: "2.17.3"

併せてipコマンドもたたいてみます。
出力内容が増えていることが確認できるかと思います。

root@ovs-test:~# ip a 
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 
    inet 127.0.0.1/8 scope host lo 
       valid_lft forever preferred_lft forever 
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever 
2: ens18: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 
    link/ether 52:d8:9a:43:a5:d6 brd ff:ff:ff:ff:ff:ff 
    altname enp0s18 
    inet 192.168.2.186/24 metric 100 brd 192.168.2.255 scope global dynamic ens18 
       valid_lft 357sec preferred_lft 357sec 
    inet6 fe80::50d8:9aff:fe43:a5d6/64 scope link 
       valid_lft forever preferred_lft forever 
3: ovs-system: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000 
    link/ether 06:ec:e2:4c:75:13 brd ff:ff:ff:ff:ff:ff 
4: ovsA: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000 
    link/ether b2:d7:65:fb:45:46 brd ff:ff:ff:ff:ff:ff 
5: ovsB: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000 
    link/ether 76:e9:68:11:0b:4b brd ff:ff:ff:ff:ff:ff

この時の仮想ネットワークのイメージは以下となります。
ovsAとovsBというブリッジが作成されています。
ovs-ページ1.drawio (1).png

次にnamespaceを作成していきます。
今回は"nsA","nsB","nsC","nsD"という名前のnamespaceを作成しています。

root@ovs-test:~# ip netns add nsA 
root@ovs-test:~# ip netns add nsB 
root@ovs-test:~# ip netns add nsC 
root@ovs-test:~# ip netns add nsD

この時のイメージは以下です。
まだ、ethernetなどの設定をまったくやっていないため、存在しているだけの状態となります。
ovs-ページ2.drawio (1).png

実際にvetheを作成していきます。
ここでは作成だけしており、ブリッジやnamespace等に紐づけてはおりません。
また、1つのコマンドで対になるvethを作成しているように見えます。
例えば以下のコマンドですと、"nsAovsA"という名前のvethの対として"ovsAnsA"というvethを併せて
作成しております。

root@ovs-test:~# ip link add name nsAovsA type veth peer name ovsAnsA 
root@ovs-test:~# ip link add name nsBovsA type veth peer name ovsAnsB 
root@ovs-test:~# ip link add name nsCovsB type veth peer name ovsBnsC 
root@ovs-test:~# ip link add name nsDovsB type veth peer name ovsBnsD

ipコマンドをたたいてみますと、4つしかコマンドはたたいておりませんが、
計8つのvethが作成されていることがわかるかと思います。

root@ovs-test:~# ip a 
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 
    inet 127.0.0.1/8 scope host lo 
       valid_lft forever preferred_lft forever 
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever 
2: ens18: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 
    link/ether 52:d8:9a:43:a5:d6 brd ff:ff:ff:ff:ff:ff 
    altname enp0s18 
    inet 192.168.2.186/24 metric 100 brd 192.168.2.255 scope global dynamic ens18 
       valid_lft 341sec preferred_lft 341sec 
    inet6 fe80::50d8:9aff:fe43:a5d6/64 scope link 
       valid_lft forever preferred_lft forever 
3: ovs-system: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000 
    link/ether 06:ec:e2:4c:75:13 brd ff:ff:ff:ff:ff:ff 
4: ovsA: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000 
    link/ether b2:d7:65:fb:45:46 brd ff:ff:ff:ff:ff:ff 
5: ovsB: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000 
    link/ether 76:e9:68:11:0b:4b brd ff:ff:ff:ff:ff:ff 
6: ovsAnsA@nsAovsA: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN group default qlen 1000 
    link/ether 76:2b:cc:69:d6:70 brd ff:ff:ff:ff:ff:ff 
7: nsAovsA@ovsAnsA: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN group default qlen 1000 
    link/ether 1e:05:1c:48:c8:c4 brd ff:ff:ff:ff:ff:ff 
8: ovsAnsB@nsBovsA: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN group default qlen 1000 
    link/ether 86:c6:5b:ae:eb:4b brd ff:ff:ff:ff:ff:ff 
9: nsBovsA@ovsAnsB: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN group default qlen 1000 
    link/ether 62:55:e6:b5:f1:86 brd ff:ff:ff:ff:ff:ff 
10: ovsBnsC@nsCovsB: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN group default qlen 1000 
    link/ether ce:44:1e:be:b9:71 brd ff:ff:ff:ff:ff:ff 
11: nsCovsB@ovsBnsC: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN group default qlen 1000 
    link/ether 1e:54:b0:70:6b:55 brd ff:ff:ff:ff:ff:ff 
12: ovsBnsD@nsDovsB: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN group default qlen 1000 
    link/ether b2:85:57:c4:8b:b4 brd ff:ff:ff:ff:ff:ff 
13: nsDovsB@ovsBnsD: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN group default qlen 1000 
    link/ether de:d5:00:a6:1a:78 brd ff:ff:ff:ff:ff:ff

この時のイメージ図としては以下になるでしょうか。
ovs-ページ3.drawio (2).png

ブリッジに作成したvethを割り当てていきます。
tagというオプションがVLANにあたるみたいです。

root@ovs-test:~# ovs-vsctl add-port ovsA ovsAnsA tag=10 
root@ovs-test:~# ovs-vsctl add-port ovsA ovsAnsB tag=20 
root@ovs-test:~# ovs-vsctl add-port ovsB ovsBnsC tag=10 
root@ovs-test:~# ovs-vsctl add-port ovsB ovsBnsD tag=20

ovs-vsctl showの出力結果を確認します。
紐づいていることが確認できますね。

root@ovs-test:~# ovs-vsctl show 
d9f37d67-9065-4bed-8741-30a72b02542c 
    Bridge ovsB 
        Port ovsBnsC 
            tag: 10 
            Interface ovsBnsC 
        Port ovsB 
            Interface ovsB 
                type: internal 
        Port ovsBnsD 
            tag: 20 
            Interface ovsBnsD 
    Bridge ovsA 
        Port ovsAnsA 
            tag: 10 
            Interface ovsAnsA 
        Port ovsA 
            Interface ovsA 
                type: internal 
        Port ovsAnsB 
            tag: 20 
            Interface ovsAnsB 
    ovs_version: "2.17.3"

ここまでの状態を図にすると以下になります。
ovs-ページ4.drawio (1).png

OVSブリッジ同士を接続していきます。
併せてovs-vsctlコマンドで確認してみます。

root@ovs-test:~# ip link add name ovsAovsB type veth peer name ovsBovsA 
root@ovs-test:~# ovs-vsctl add-port ovsA ovsAovsB 
root@ovs-test:~# ovs-vsctl add-port ovsB ovsBovsA

root@ovs-test:~# ovs-vsctl show 
d9f37d67-9065-4bed-8741-30a72b02542c 
    Bridge ovsB 
        Port ovsBnsC 
            tag: 10 
            Interface ovsBnsC 
        Port ovsBovsA 
            Interface ovsBovsA 
        Port ovsB 
            Interface ovsB 
                type: internal 
        Port ovsBnsD 
            tag: 20 
            Interface ovsBnsD 
    Bridge ovsA 
        Port ovsAnsA 
            tag: 10 
            Interface ovsAnsA 
        Port ovsA 
            Interface ovsA 
                type: internal 
        Port ovsAovsB 
            Interface ovsAovsB 
        Port ovsAnsB 
            tag: 20 
            Interface ovsAnsB 
    ovs_version: "2.17.3"

ここまでのイメージ図となります。
ovs-ページ5.drawio (1).png

nsにvethを接続していきます。

root@ovs-test:~#  ip link set nsAovsA netns nsA
root@ovs-test:~# ip link set nsBovsA netns nsB 
root@ovs-test:~# ip link set nsCovsB netns nsC 
root@ovs-test:~# ip link set nsDovsB netns nsD

ovs-ページ6.drawio (1).png

これだけで接続できればいいのですが、vethやブリッジなどを稼働させなければなりません。
以下のコマンドを実行していきます。

root@ovs-test:~# ip link set ovsA up 
root@ovs-test:~# ip link set ovsB up 
root@ovs-test:~# ip link set ovsAovsB up 
root@ovs-test:~# ip link set ovsBovsA up 
root@ovs-test:~# ip link set ovsAnsA up 
root@ovs-test:~# ip link set ovsAnsB up 
root@ovs-test:~# ip link set ovsBnsC up 
root@ovs-test:~# ip link set ovsBnsD up

root@ovs-test:~# ip netns exec nsA ip link set nsAovsA up 
root@ovs-test:~# ip netns exec nsB ip link set nsBovsA up 
root@ovs-test:~# ip netns exec nsC ip link set nsCovsB up  
root@ovs-test:~# ip netns exec nsD ip link set nsDovsB up

root@ovs-test:~# ip netns exec nsA ip link set lo up 
root@ovs-test:~# ip netns exec nsB ip link set lo up 
root@ovs-test:~# ip netns exec nsC ip link set lo up 
root@ovs-test:~# ip netns exec nsD ip link set lo up

この時のipコマンドの出力結果は以下です
state DOWN状態から変化していることが確認できると思います。

root@ovs-test:~# ip a 
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 
    inet 127.0.0.1/8 scope host lo 
       valid_lft forever preferred_lft forever 
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever 
2: ens18: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 
    link/ether 52:d8:9a:43:a5:d6 brd ff:ff:ff:ff:ff:ff 
    altname enp0s18 
    inet 192.168.2.186/24 metric 100 brd 192.168.2.255 scope global dynamic ens18 
       valid_lft 491sec preferred_lft 491sec 
    inet6 fe80::50d8:9aff:fe43:a5d6/64 scope link 
       valid_lft forever preferred_lft forever 
3: ovs-system: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000 
    link/ether 06:ec:e2:4c:75:13 brd ff:ff:ff:ff:ff:ff 
4: ovsA: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default qlen 1000 
    link/ether b2:d7:65:fb:45:46 brd ff:ff:ff:ff:ff:ff 
    inet6 fe80::b0d7:65ff:fefb:4546/64 scope link 
       valid_lft forever preferred_lft forever 
5: ovsB: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default qlen 1000 
    link/ether 76:e9:68:11:0b:4b brd ff:ff:ff:ff:ff:ff 
    inet6 fe80::74e9:68ff:fe11:b4b/64 scope link 
       valid_lft forever preferred_lft forever 
6: ovsAnsA@if7: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master ovs-system state UP group default qlen 1000 
    link/ether 76:2b:cc:69:d6:70 brd ff:ff:ff:ff:ff:ff link-netns nsA 
    inet6 fe80::742b:ccff:fe69:d670/64 scope link 
       valid_lft forever preferred_lft forever 
8: ovsAnsB@if9: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master ovs-system state UP group default qlen 1000 
    link/ether 86:c6:5b:ae:eb:4b brd ff:ff:ff:ff:ff:ff link-netns nsB 
    inet6 fe80::84c6:5bff:feae:eb4b/64 scope link 
       valid_lft forever preferred_lft forever 
10: ovsBnsC@if11: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master ovs-system state UP group default qlen 1000 
    link/ether ce:44:1e:be:b9:71 brd ff:ff:ff:ff:ff:ff link-netns nsC 
    inet6 fe80::cc44:1eff:febe:b971/64 scope link 
       valid_lft forever preferred_lft forever 
12: ovsBnsD@if13: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master ovs-system state UP group default qlen 1000 
    link/ether b2:85:57:c4:8b:b4 brd ff:ff:ff:ff:ff:ff link-netns nsD 
    inet6 fe80::b085:57ff:fec4:8bb4/64 scope link 
       valid_lft forever preferred_lft forever 
14: ovsBovsA@ovsAovsB: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master ovs-system state UP group default qlen 1000 
    link/ether e6:7e:aa:bb:58:e5 brd ff:ff:ff:ff:ff:ff 
    inet6 fe80::e47e:aaff:febb:58e5/64 scope link 
       valid_lft forever preferred_lft forever 
15: ovsAovsB@ovsBovsA: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master ovs-system state UP group default qlen 1000 
    link/ether b6:80:8c:9c:80:c2 brd ff:ff:ff:ff:ff:ff 
    inet6 fe80::b480:8cff:fe9c:80c2/64 scope link 
       valid_lft forever preferred_lft forever

nsのvethにそれぞれIPアドレスを割り当てていきます。
ネットワークは192.168.2.11~14としました。

root@ovs-test:~# ip netns exec nsA ip addr add 192.168.2.11/24 dev nsAovsA 
root@ovs-test:~# ip netns exec nsB ip addr add 192.168.2.12/24 dev nsBovsA 
root@ovs-test:~# ip netns exec nsC ip addr add 192.168.2.13/24 dev nsCovsB 
root@ovs-test:~# ip netns exec nsD ip addr add 192.168.2.14/24 dev nsDovsB

nsAからnsC、nsBからnsDに対してpingを実行していきます。
双方とも疎通できていることが確認できますね!
今回はここまでです!

root@ovs-test:~# ip netns exec nsA ping 192.168.2.13 
PING 192.168.2.13 (192.168.2.13) 56(84) bytes of data. 
64 bytes from 192.168.2.13: icmp_seq=1 ttl=64 time=1.95 ms 
64 bytes from 192.168.2.13: icmp_seq=2 ttl=64 time=0.158 ms 
64 bytes from 192.168.2.13: icmp_seq=3 ttl=64 time=0.112 ms 
64 bytes from 192.168.2.13: icmp_seq=4 ttl=64 time=0.122 ms 
64 bytes from 192.168.2.13: icmp_seq=5 ttl=64 time=0.105 ms 
^C 
--- 192.168.2.13 ping statistics --- 
5 packets transmitted, 5 received, 0% packet loss, time 4065ms 
rtt min/avg/max/mdev = 0.105/0.489/1.952/0.731 ms 

root@ovs-test:~# ip netns exec nsB ping 192.168.2.14 
PING 192.168.2.14 (192.168.2.14) 56(84) bytes of data. 
64 bytes from 192.168.2.14: icmp_seq=1 ttl=64 time=2.07 ms 
64 bytes from 192.168.2.14: icmp_seq=2 ttl=64 time=0.116 ms 
64 bytes from 192.168.2.14: icmp_seq=3 ttl=64 time=0.134 ms 
64 bytes from 192.168.2.14: icmp_seq=4 ttl=64 time=0.094 ms 
64 bytes from 192.168.2.14: icmp_seq=5 ttl=64 time=0.119 ms 
^C 
--- 192.168.2.14 ping statistics --- 
5 packets transmitted, 5 received, 0% packet loss, time 4056ms 
rtt min/avg/max/mdev = 0.094/0.506/2.070/0.781 ms
2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?