ovs+ovnのoverlayネットワークを構築し、KVMの仮想マシンとDockerコンテナのトラフィックをBridgeで外部ネットワークに流して使用する場合の設定方法を記載したいと思います。
これにより、仮想マシンとコンテナと外部ネットワーク機器が同一VLANで通信可能になります。
ただ、実用性の観点で冗長化できないため、あまり使えないかもしれませんが、ovnの仕組みを理解する上では活用できるかと思います。
1.環境
1-1.VMWare
筐体 : 自作PC(Win10pro) CPU : Intel(R) Core(TM) i9-9900K CPU @ 3.60GHz VMWare : VMware(R) Workstation 15 Pro 15.1.0 build-13591040 OS : CentOS7.6(1810) Kernel : 3.10.0-957.el7.x86_64 Installed Environment Groups : Server with GUI Add-Ons for Selected Environment : Virtualization Client, Virtualization Hypervisor, Virtualization Tools ovs&ovn : 2.11.1
ベアメタル環境でも同様に設定可能です。
1-2.全体構成その1:Underlay
1-3.全体構成その2:Overlay
補足
「'」が付いている箇所は、主に「'」が付いていない箇所を設定すると自動設定されます。*1
1-4 .全体の流れ ~概要~
- ovs+ovnのビルドとインストール
- ovs+ovnの設定
- docker+consulのクラスタ設定
- (1)~(7)の設定
1-5 .全体の流れ ~コマンドのみ~
以下のコマンドを投入していきます。
やりたいことが既に決まっている方は、構成図とコマンドの内容を見るだけでもよいと思います。
しかし、ovs+ovnやdocker+consulの設定もそこそこボリュームがあるため、(1)~(7)の辿り着くまでが少々しんどいかもしれません。。
(1) docker network create -d openvswitch --subnet=192.168.31.0/24 ovs (2) vi /etc/sysconfig/network-scripts/ifcfg-br-ext DEVICE=br-ext DEVICETYPE=ovs TYPE=OVSBridge BOOTPROTO=static NM_CONTROLLED=no ONBOOT=yes HOTPLUG=no vi /etc/sysconfig/network-scripts/ifcfg-ens36 DEVICE=ens36 ONBOOT=yes DEVICETYPE=ovs TYPE=OVSPort OVS_BRIDGE=br-ext BOOTPROTO=none NM_CONTROLLED=no OVS_OPTIONS="vlan_mode=trunk trunks=300-301" HOTPLUG=no (3) ovn-sbctl --db=tcp:192.168.30.101:6642 show ovs-vsctl set Open_vSwitch . external-ids:ovn-bridge-mappings=physnet301:br-ext export SW_NAME=$(ovn-nbctl --db=tcp:192.168.30.101:6641 ls-list | awk '{print $2}' | sed s/\(//g | sed s/\)//g) ovn-nbctl --db=tcp:192.168.30.101:6641 lsp-add $SW_NAME l2gwport "" 301 ovn-nbctl --db=tcp:192.168.30.101:6641 lsp-set-addresses l2gwport unknown ovn-nbctl --db=tcp:192.168.30.101:6641 lsp-set-type l2gwport l2gateway ovn-nbctl --db=tcp:192.168.30.101:6641 lsp-set-options l2gwport network_name=physnet301 l2gateway-chassis=28928b40-900b-4f48-b4ed-8d9d2f1082fd (4) export SW_NAME=$(ovn-nbctl --db=tcp:192.168.30.101:6641 ls-list | awk '{print $2}' | sed s/\(//g | sed s/\)//g) export IFACE_ID=$(ovs-vsctl get interface vnet1 external_ids:iface-id | sed s/\"//g) export MAC_ADDR=$(ovs-vsctl get interface vnet1 external_ids:attached-mac | sed s/\"//g) ovn-nbctl --db=tcp:192.168.30.101:6641 lsp-add $SW_NAME $IFACE_ID ovn-nbctl --db=tcp:192.168.30.101:6641 lsp-set-addresses $IFACE_ID $MAC_ADDR ovn-nbctl --db=tcp:192.168.30.101:6641 show (5) export SW_NAME=$(ovn-nbctl --db=tcp:192.168.30.101:6641 ls-list | awk '{print $2}' | sed s/\(//g | sed s/\)//g) export IFACE_ID=$(ovs-vsctl get interface vnet1 external_ids:iface-id | sed s/\"//g) export MAC_ADDR=$(ovs-vsctl get interface vnet1 external_ids:attached-mac | sed s/\"//g) ovn-nbctl --db=tcp:192.168.30.101:6641 lsp-add $SW_NAME $IFACE_ID ovn-nbctl --db=tcp:192.168.30.101:6641 lsp-set-addresses $IFACE_ID $MAC_ADDR ovn-nbctl --db=tcp:192.168.30.101:6641 show (6) docker run -itd \ --privileged \ --network ovs \ --name c2 \ c76 \ /sbin/init (7) docker run -itd \ --privileged \ --network ovs \ --name c3 \ c76 \ /sbin/init
2.ovs+ovnのビルドとインストール
ControllerNode(c76ovn01)にてビルドとインストールを実施します。またDockerもインストールしてしまいます。
2-1.ControllerNode
yum -y install @'Development Tools' rpm-build yum-utils wget libpcap-devel numactl-devel mkdir -p /root/rpmbuild/SOURCES cd /root/rpmbuild/SOURCES wget https://www.openvswitch.org/releases/openvswitch-2.11.1.tar.gz tar zxvf openvswitch-2.11.1.tar.gz sed -e 's/@VERSION@/0.0.1/' openvswitch-2.11.1/rhel/openvswitch-fedora.spec.in > ovs.spec yum-builddep -y ovs.spec && \ cd openvswitch-2.11.1 && \ ./boot.sh && \ ./configure && \ make rpm-fedora RPMBUILD_OPT="--without check" && \ make rpm-fedora-ovn RPMBUILD_OPT="--without check" cd /root/rpmbuild/SOURCES/openvswitch-2.11.1/rpm/rpmbuild/RPMS/noarch yum -y localinstall python-openvswitch-2.11.1-1.el7.noarch.rpm cd /root/rpmbuild/SOURCES/openvswitch-2.11.1/rpm/rpmbuild/RPMS/x86_64 yum -y localinstall \ openvswitch-2.11.1-1.el7.x86_64.rpm \ ovn-2.11.1-1.el7.x86_64.rpm \ ovn-common-2.11.1-1.el7.x86_64.rpm \ ovn-central-2.11.1-1.el7.x86_64.rpm \ ovn-host-2.11.1-1.el7.x86_64.rpm \ ovn-docker-2.11.1-1.el7.x86_64.rpm curl -sSL https://get.docker.com/ | sh systemctl start openvswitch systemctl enable openvswitch systemctl start ovn-northd systemctl enable ovn-northd systemctl start docker systemctl enable docker
2-2.ComputeNode
ComputeNode(c76ovn02&c76ovn03)にてビルドとインストールを実施します。違いは、ovn-central-2.11.1-1.el7.x86_64.rpmが無いだけです。
yum -y install @'Development Tools' rpm-build yum-utils wget libpcap-devel numactl-devel mkdir -p /root/rpmbuild/SOURCES cd /root/rpmbuild/SOURCES wget https://www.openvswitch.org/releases/openvswitch-2.11.1.tar.gz tar zxvf openvswitch-2.11.1.tar.gz sed -e 's/@VERSION@/0.0.1/' openvswitch-2.11.1/rhel/openvswitch-fedora.spec.in > ovs.spec yum-builddep -y ovs.spec && \ cd openvswitch-2.11.1 && \ ./boot.sh && \ ./configure && \ make rpm-fedora RPMBUILD_OPT="--without check" && \ make rpm-fedora-ovn RPMBUILD_OPT="--without check" cd /root/rpmbuild/SOURCES/openvswitch-2.11.1/rpm/rpmbuild/RPMS/noarch yum -y localinstall python-openvswitch-2.11.1-1.el7.noarch.rpm cd /root/rpmbuild/SOURCES/openvswitch-2.11.1/rpm/rpmbuild/RPMS/x86_64 yum -y localinstall \ openvswitch-2.11.1-1.el7.x86_64.rpm \ ovn-2.11.1-1.el7.x86_64.rpm \ ovn-common-2.11.1-1.el7.x86_64.rpm \ ovn-host-2.11.1-1.el7.x86_64.rpm \ ovn-docker-2.11.1-1.el7.x86_64.rpm curl -sSL https://get.docker.com/ | sh systemctl start openvswitch systemctl enable openvswitch systemctl start ovn-controller systemctl enable ovn-controller systemctl start docker systemctl enable docker
3.ovs+ovnの設定
3-1.Overlay用のInteface設定
c76ovn01 nmcli con add type ethernet autoconnect yes con-name ens37 ifname ens37 nmcli con mod ens37 ipv4.method manual ipv4.addresses 192.168.30.101/24 nmcli con up ens37 c76ovn02 nmcli con add type ethernet autoconnect yes con-name ens37 ifname ens37 nmcli con mod ens37 ipv4.method manual ipv4.addresses 192.168.30.102/24 nmcli con up ens37 c76ovn03 nmcli con add type ethernet autoconnect yes con-name ens37 ifname ens37 nmcli con mod ens37 ipv4.method manual ipv4.addresses 192.168.30.103/24 nmcli con up ens37
3-2.ovnの設定
c76ovn01 ovn-nbctl set-connection ptcp:6641 ovn-sbctl set-connection ptcp:6642 ovs-appctl -t ovsdb-server ovsdb-server/add-remote ptcp:6640
3-3.ovsの設定
c76ovn02 export CENTRAL_IP=192.168.30.101 export ENCAP_TYPE=geneve export LOCAL_IP=192.168.30.102 ovs-vsctl set Open_vSwitch . external_ids:ovn-remote="tcp:${CENTRAL_IP}:6642" ovs-vsctl set Open_vSwitch . external_ids:ovn-nb="tcp:${CENTRAL_IP}:6641" ovs-vsctl set Open_vSwitch . external_ids:ovn-encap-ip=${LOCAL_IP} ovs-vsctl set Open_vSwitch . external_ids:ovn-encap-type="${ENCAP_TYPE}" systemctl restart ovn-controller c76ovn03 export CENTRAL_IP=192.168.30.101 export ENCAP_TYPE=geneve export LOCAL_IP=192.168.30.103 ovs-vsctl set Open_vSwitch . external_ids:ovn-remote="tcp:${CENTRAL_IP}:6642" ovs-vsctl set Open_vSwitch . external_ids:ovn-nb="tcp:${CENTRAL_IP}:6641" ovs-vsctl set Open_vSwitch . external_ids:ovn-encap-ip=${LOCAL_IP} ovs-vsctl set Open_vSwitch . external_ids:ovn-encap-type="${ENCAP_TYPE}" systemctl restart ovn-controller
3-4.設定確認
102と103が101とESTABとなっていればOKです。
c76ovn01 ss -ant |grep 6642 出力例 [root@c76ovn01 ~]# ss -ant |grep 6642 LISTEN 0 10 *:6642 *:* ESTAB 0 0 192.168.30.101:6642 192.168.30.102:44102 ESTAB 0 0 192.168.30.101:6642 192.168.30.103:34252
上記がOKな場合、br-intが自動生成され、GeneveによるOverlayのトンネル設定も自動で実施されます。また、ovs上では以下のようなステータスとなっていればOKです。
c76ovn02&03 ovs-vsctl show 出力例 [root@c76ovn02 ~]# ovs-vsctl show e2d97138-977a-4579-bc6a-dfb43d8769cb Bridge br-int fail_mode: secure Port br-int Interface br-int type: internal Port "ovn-925250-0" Interface "ovn-925250-0" type: geneve options: {csum="true", key=flow, remote_ip="192.168.30.103"} ovs_version: "2.11.0"
3-5.virshによるovsの設定
c76ovn02&03にてovsのPortGroup設定を実施しておきます。*2
c76ovn02&03 vi /tmp/ovsnw.xml <network> <name>ovsnw</name> <forward mode='bridge'/> <bridge name='br-int'/> <virtualport type='openvswitch'/> <portgroup name='untag' default='yes'> </portgroup> <portgroup name='vlan300'> <vlan> <tag id='300'/> </vlan> </portgroup> <portgroup name='vlan301'> <vlan> <tag id='301'/> </vlan> </portgroup> </network> virsh net-list virsh net-define /tmp/ovsnw.xml virsh net-start ovsnw virsh net-autostart ovsnw virsh net-list
4.docker+consulのクラスタ設定
4-1.Dockerの設定その1
Option設定を読込みできるようにします。
c76ovn01&02&03 vi /usr/lib/systemd/system/docker.service EnvironmentFile=-/etc/sysconfig/docker EnvironmentFile=-/etc/sysconfig/docker-storage EnvironmentFile=-/etc/sysconfig/docker-network ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock \ $OPTIONS \ $DOCKER_STORAGE_OPTIONS \ $DOCKER_NETWORK_OPTIONS \ $ADD_REGISTRY \ $BLOCK_REGISTRY \ $INSECURE_REGISTRY 出力例 青文字はコメントアウトしてください。 [Service] Type=notify # the default is not to use systemd for cgroups because the delegate issues still # exists and systemd currently does not support the cgroup feature set required # for containers run by docker #ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock EnvironmentFile=-/etc/sysconfig/docker EnvironmentFile=-/etc/sysconfig/docker-storage EnvironmentFile=-/etc/sysconfig/docker-network ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock \ $OPTIONS \ $DOCKER_STORAGE_OPTIONS \ $DOCKER_NETWORK_OPTIONS \ $ADD_REGISTRY \ $BLOCK_REGISTRY \ $INSECURE_REGISTRY ExecReload=/bin/kill -s HUP $MAINPID TimeoutSec=0 RestartSec=2 Restart=always
4-2.Dockerの設定その2
c76ovn01 vi /etc/sysconfig/docker OPTIONS="--cluster-store=consul://127.0.0.1:8500 --cluster-advertise=192.168.30.101:0" systemctl daemon-reload systemctl restart docker c76ovn02 vi /etc/sysconfig/docker OPTIONS="--cluster-store=consul://127.0.0.1:8500 --cluster-advertise=192.168.30.102:0" systemctl daemon-reload systemctl restart docker c76ovn03 vi /etc/sysconfig/docker OPTIONS="--cluster-store=consul://127.0.0.1:8500 --cluster-advertise=192.168.30.103:0" systemctl daemon-reload systemctl restart docker
4-3.consulのインストール
consulでクラスタを構成します。
一度設定をミスると色々やっかいだった*3ので、VMWareなどで各Nodeを動作させている方は、この手順を進める前にスナップショットなりクローンを作成しておいた方が良いと思います。
c76ovn01&ovn02&ovn03 yum -y install epel-release && \ yum -y install python-pip && \ pip install pip --upgrade && \ pip install flask wget https://releases.hashicorp.com/consul/1.5.2/consul_1.5.2_linux_amd64.zip unzip consul_1.5.2_linux_amd64.zip mv consul /usr/local/bin
4-4.consulの設定
最初に暗号キーを生成しておきます。生成した暗号キーは全Nodeで共通にしますので、任意の1台で生成すればOKです。ここでは例としてc76ovn01にて生成します。
c76ovn01 consul keygen 出力例 [root@c76ovn01 ~]# consul keygen az3EW5ykRod6hBS1FiSFAA==
各Nodeごとに設定ファイルを作成します。赤文字の箇所のみ異なっています。
c76ovn01 sudo mkdir -p /etc/consul.d/scripts sudo mkdir /var/consul vi /etc/consul.d/config.json { "bootstrap_expect": 3, "client_addr": "0.0.0.0", "datacenter": "dc1", "data_dir": "/var/consul", "domain": "consul", "enable_script_checks": true, "dns_config": { "enable_truncate": true, "only_passing": true }, "enable_syslog": true, "encrypt": "az3EW5ykRod6hBS1FiSFAA==", "leave_on_terminate": true, "log_level": "INFO", "rejoin_after_leave": true, "bind_addr": "192.168.30.101", "server": true, "start_join": [ "192.168.30.101", "192.168.30.102", "192.168.30.103" ], "ui": false } c76ovn02 sudo mkdir -p /etc/consul.d/scripts sudo mkdir /var/consul vi /etc/consul.d/config.json { "bootstrap_expect": 3, "client_addr": "0.0.0.0", "datacenter": "dc1", "data_dir": "/var/consul", "domain": "consul", "enable_script_checks": true, "dns_config": { "enable_truncate": true, "only_passing": true }, "enable_syslog": true, "encrypt": "az3EW5ykRod6hBS1FiSFAA==", "leave_on_terminate": true, "log_level": "INFO", "rejoin_after_leave": true, "bind_addr": "192.168.30.102", "server": true, "start_join": [ "192.168.30.101", "192.168.30.102", "192.168.30.103" ], "ui": false } c76ovn03 sudo mkdir -p /etc/consul.d/scripts sudo mkdir /var/consul vi /etc/consul.d/config.json { "bootstrap_expect": 3, "client_addr": "0.0.0.0", "datacenter": "dc1", "data_dir": "/var/consul", "domain": "consul", "enable_script_checks": true, "dns_config": { "enable_truncate": true, "only_passing": true }, "enable_syslog": true, "encrypt": "az3EW5ykRod6hBS1FiSFAA==", "leave_on_terminate": true, "log_level": "INFO", "rejoin_after_leave": true, "bind_addr": "192.168.30.103", "server": true, "start_join": [ "192.168.30.101", "192.168.30.102", "192.168.30.103" ], "ui": false }
4-5.consulのサービス化設定
consulをサービス化し、自動起動するように設定します。
c76ovn01&02&03 vi /etc/systemd/system/consul.service [Unit] Description=Consul Startup process After=network.target [Service] Type=simple ExecStart=/bin/bash -c '/usr/local/bin/consul agent -config-dir /etc/consul.d/' TimeoutStartSec=0 [Install] WantedBy=default.target systemctl daemon-reload systemctl start consul systemctl enable consul consul members 出力例 全Nodeで同様の出力となります。 [root@c76ovn03 ~]# consul members Node Address Status Type Build Protocol DC Segment c76ovn01.md.jp 192.168.30.101:8301 alive server 1.5.2 2 dc1c76ovn02.md.jp 192.168.30.102:8301 alive server 1.5.2 2 dc1 c76ovn03.md.jp 192.168.30.103:8301 alive server 1.5.2 2 dc1 [root@c76ovn03 ~]# systemctl status consul ● consul.service - Consul Startup process Loaded: loaded (/etc/systemd/system/consul.service; enabled; vendor preset: disabled) Active: active (running) since Sun 2019-07-21 16:27:32 JST; 1s ago Main PID: 28182 (consul) Tasks: 14 Memory: 18.2M CGroup: /system.slice/consul.service mq28182 /usr/local/bin/consul agent -config-dir /etc/consul.d/ Jul 21 16:27:32 c76ovn03.md.jp consul[28182]: consul: Adding LAN server c76ovn01.md.jp (Addr: tcp/192.168.30.101:8300) (DC: dc1) Jul 21 16:27:32 c76ovn03.md.jp consul[28182]: consul: Adding LAN server c76ovn02.md.jp (Addr: tcp/192.168.30.102:8300) (DC: dc1) Jul 21 16:27:32 c76ovn03.md.jp consul[28182]: serf: EventMemberJoin: c76ovn02.md.jp.dc1 192.168.30.102 Jul 21 16:27:32 c76ovn03.md.jp consul[28182]: serf: Re-joined to previously known node: c76ovn01.md.jp.dc1: 192.168.30.101:8302 Jul 21 16:27:32 c76ovn03.md.jp consul[28182]: agent: Started HTTP server on [::]:8500 (tcp) Jul 21 16:27:32 c76ovn03.md.jp consul[28182]: consul: Handled member-join event for server "c76ovn01.md.jp.dc1" in area "wan" Jul 21 16:27:32 c76ovn03.md.jp consul[28182]: consul: Handled member-join event for server "c76ovn02.md.jp.dc1" in area "wan" Jul 21 16:27:32 c76ovn03.md.jp consul[28182]: agent: (LAN) joining: [192.168.30.101 192.168.30.102 192.168.30.103] Jul 21 16:27:32 c76ovn03.md.jp consul[28182]: agent: (LAN) joined: 3 Jul 21 16:27:32 c76ovn03.md.jp consul[28182]: agent: started state syncer
ここまで完了したら、一度全Nodeを再起動しておいてください。
再起動完了後、以下のコマンドでDockerとconsulが正常に起動していることを確認してください。
systemctl status docker systemctl status consul
5.(1)~(7)の設定
5-1.事前準備
ovnのdocker-overlayドライバを各ComputeNodeで起動しておきます。
c76ovn02&03 ovn-docker-overlay-driver --detach
5-2.(1)の設定:DockerOverlaySwitchの作成
(1’)は自動生成されていますが、Overlay上では認識されていません。
以下のコマンドにより、ovnのNorthboundDBにDockerOverlaySwitchが生成されます。それと同時にDocker上のNWとしても認識されます。
c76ovn02もしくはc76ovn03のどちらか一方で設定すればOKです。
c76ovn02 or 03 docker network create -d openvswitch --subnet=192.168.31.0/24 ovs 出力例 [root@c76ovn02 ~]# docker network ls NETWORK ID NAME DRIVER SCOPE 7a78f73ce06d bridge bridge local 368be43f05a1 host host local efee695f0f0c none null local b5fb702e9489 ovs openvswitch global [root@c76ovn02 ~]# ovn-nbctl --db=tcp:192.168.30.101:6641 show switch b70b9243-80b3-4ad6-8940-55bff06251fc (b5fb702e948902881b1b933191b9ee83f8dad4eb434a9d27d408d7a2d5fe2aa2)
5-3.(2)の設定:br-extの作成
br-intに無理やりインターフェースをアタッチしても外部とのBridge接続による疎通はできません。この辺りはNeutronのアーキテクチャに近い感じです。br-intとbr-extをPatch接続させて、外部ネットワークとブリッジ接続します。
c76ovn02 3-5に合わせて300-301をTrunkしていますが、今回の構成であれば301のみでOKです。 vi /etc/sysconfig/network-scripts/ifcfg-br-ext DEVICE=br-ext DEVICETYPE=ovs TYPE=OVSBridge BOOTPROTO=static NM_CONTROLLED=no ONBOOT=yes HOTPLUG=no vi /etc/sysconfig/network-scripts/ifcfg-ens36 DEVICE=ens36 ONBOOT=yes DEVICETYPE=ovs TYPE=OVSPort OVS_BRIDGE=br-ext BOOTPROTO=none NM_CONTROLLED=no OVS_OPTIONS="vlan_mode=trunk trunks=300-301" HOTPLUG=no systemctl restart network
5-4.(3)の設定:br-intとbr-extのPatch接続
先にovn-sbctlコマンドでシャーシIDを取得した後に設定を入れます。
c76ovn02
(3)
ovn-sbctl --db=tcp:192.168.30.101:6642 show
ovs-vsctl set Open_vSwitch . external-ids:ovn-bridge-mappings=physnet301:br-ext
export SW_NAME=$(ovn-nbctl --db=tcp:192.168.30.101:6641 ls-list | awk '{print $2}' | sed s/\(//g | sed s/\)//g)
ovn-nbctl --db=tcp:192.168.30.101:6641 lsp-add $SW_NAME l2gwport "" 301
ovn-nbctl --db=tcp:192.168.30.101:6641 lsp-set-addresses l2gwport unknown
ovn-nbctl --db=tcp:192.168.30.101:6641 lsp-set-type l2gwport l2gateway
ovn-nbctl --db=tcp:192.168.30.101:6641 lsp-set-options l2gwport network_name=physnet301 l2gateway-chassis=28928b40-900b-4f48-b4ed-8d9d2f1082fd
補足その1
ovn-sbctl --db=tcp:192.168.30.101:6642 showの出力例を以下に記載します。
赤文字の箇所をl2gateway-chassis=の後に加えます。
出力例
[root@c76ovn02 ~]# ovn-sbctl --db=tcp:192.168.30.101:6642 show
Chassis "1fdd4703-9c73-4afd-adf3-e0e90b7afb63"
hostname: "c76ovn03.md.jp"
Encap geneve
ip: "192.168.30.103"
options: {csum="true"}
Port_Binding "35d89c2d-0505-41aa-b0c6-6aff6f483899"
Port_Binding "b7131d7ecd548dcc4b6eb38bef0179b1bc75645e5683b69e6131da69d0aed1be"
Chassis "28928b40-900b-4f48-b4ed-8d9d2f1082fd"
hostname: "c76ovn02.md.jp"
Encap geneve
ip: "192.168.30.102"
options: {csum="true"}
Port_Binding "16b258df72cb52ddb2527be69578c1f953c9275e154d4107743b0ee3ac13f095"
Port_Binding "2c5a0afd-b12a-419e-b6f5-718c5d0e6446"
Port_Binding "l2gwport"
[root@c76ovn02 ~]#
補足その2 設定後、以下のようになっていればOKです。 出力例 [root@c76ovn02 ~]# ovn-nbctl --db=tcp:192.168.30.101:6641 show switch b70b9243-80b3-4ad6-8940-55bff06251fc (b5fb702e948902881b1b933191b9ee83f8dad4eb434a9d27d408d7a2d5fe2aa2) port l2gwport type: l2gateway parent: tag: 301 addresses: ["unknown"] [root@c76ovn02 ~]# [root@c76ovn02 ~]# ovs-vsctl show 090be24a-f730-4d28-a4a0-dcf6d97fe618 Bridge br-int fail_mode: secure Port "patch-br-int-to-l2gwport" Interface "patch-br-int-to-l2gwport" type: patch options: {peer="patch-l2gwport-to-br-int"} Port "ovn-1fdd47-0" Interface "ovn-1fdd47-0" type: geneve options: {csum="true", key=flow, remote_ip="192.168.30.103"} Port br-int Interface br-int type: internal Bridge br-ext Port "patch-l2gwport-to-br-int" Interface "patch-l2gwport-to-br-int" type: patch options: {peer="patch-br-int-to-l2gwport"} Port br-ext Interface br-ext type: internal Port "ens36" trunks: [300, 301] Interface "ens36" ovs_version: "2.11.1" [root@c76ovn02 ~]#
ここまででアップリンクに相当する部分が構築できました。
あとは、仮想マシンやコンテナをアタッチしていきます。
コンテナは以下のコマンドで作成したDockerネットワークのovsにアタッチさせるだけで自動設定してくれます。
docker network create -d openvswitch --subnet=192.168.31.0/24 ovs
一方、KVMの仮想マシンについては、もう一工夫必要になります。
5-5.(4)と(5)の設定:KVM仮想マシンのアタッチ
先にvirt-installコマンドなどで仮想マシンを起動しておいてください。
その際、仮想マシンに使用するインターフェースは3-5で設定したPortGroupのうちvlan301を使用するようにしてください。
virt-installはこんな感じです。ポイントは赤文字の箇所です。
virt-install --connect=qemu:///system \
--name=c7623 \
--disk /var/lib/libvirt/images/c7623.qcow2,format=qcow2,bus=virtio \
--network bridge=virbr0,model=virtio \
--network network=ovsnw,portgroup=vlan301,model=virtio \
--initrd-inject=./c76min.ks \
--extra-args='ks=file:/c76min.ks biosdevname=0 net.ifnames=0 console=tty0 console=ttyS0,115200n8' \
--vcpus=1 \
--ram=1024 \
--accelerate \
--hvm \
--location='/var/lib/libvirt/images/CentOS-7-x86_64-DVD-1810.iso' \
--nographics \
--os-type=linux \
--os-variant=centos7.0 \
--arch=x86_64
これにより、以下のような設定になります。ポイントはvnet1とovsnw, vlan301がBridgeしている点です。
vnet0 | virbr0 | eth0 | libvirtでDefault定義 |
vnet1 | ovsnw, vlan301 | eth1 | 3-5で定義 |
仮想マシンが起動したら以下のコマンドにて、ovn上に登録していきます。
SW_NAME、IFACE_ID、MAC_ADDRを取得し、それをNorthboundDBに登録する形となります。*4
c76ovn02
(4)
export SW_NAME=$(ovn-nbctl --db=tcp:192.168.30.101:6641 ls-list | awk '{print $2}' | sed s/\(//g | sed s/\)//g)
export IFACE_ID=$(ovs-vsctl get interface vnet1 external_ids:iface-id | sed s/\"//g)
export MAC_ADDR=$(ovs-vsctl get interface vnet1 external_ids:attached-mac | sed s/\"//g)
ovn-nbctl --db=tcp:192.168.30.101:6641 lsp-add $SW_NAME $IFACE_ID
ovn-nbctl --db=tcp:192.168.30.101:6641 lsp-set-addresses $IFACE_ID $MAC_ADDR
ovn-nbctl --db=tcp:192.168.30.101:6641 show
c76ovn03
(5)
export SW_NAME=$(ovn-nbctl --db=tcp:192.168.30.101:6641 ls-list | awk '{print $2}' | sed s/\(//g | sed s/\)//g)
export IFACE_ID=$(ovs-vsctl get interface vnet1 external_ids:iface-id | sed s/\"//g)
export MAC_ADDR=$(ovs-vsctl get interface vnet1 external_ids:attached-mac | sed s/\"//g)
ovn-nbctl --db=tcp:192.168.30.101:6641 lsp-add $SW_NAME $IFACE_ID
ovn-nbctl --db=tcp:192.168.30.101:6641 lsp-set-addresses $IFACE_ID $MAC_ADDR
ovn-nbctl --db=tcp:192.168.30.101:6641 show
出力例
[root@c76ovn02 ~]# ovn-nbctl --db=tcp:192.168.30.101:6641 show
switch b70b9243-80b3-4ad6-8940-55bff06251fc (b5fb702e948902881b1b933191b9ee83f8dad4eb434a9d27d408d7a2d5fe2aa2)
port l2gwport
type: l2gateway
parent:
tag: 301
addresses: ["unknown"]
port 35d89c2d-0505-41aa-b0c6-6aff6f483899
addresses: ["52:54:00:f6:45:c2"]
port 2c5a0afd-b12a-419e-b6f5-718c5d0e6446
addresses: ["52:54:00:d7:a6:96"]
[root@c76ovn02 ~]#
5-6.(6)と(7)の設定:Dockerコンテナのアタッチ
DockerコンテナのアタッチはPlug-Inで自動的にovs&ovnに登録されるため、「--network ovs」だけ忘れずに設定すれば問題ありません。
c76ovn02
(6)
docker run -itd \
--privileged \
--network ovs \
--name c2 \
centos \
/sbin/init
c76ovn03
(7)
docker run -itd \
--privileged \
--network ovs \
--name c3 \
centos \
/sbin/init
構成を確認してみます。
確認コマンド docker network ls ovn-nbctl --db=tcp:192.168.30.101:6641 show ovn-sbctl --db=tcp:192.168.30.101:6642 show ovs-vsctl show 出力例 ここでは例としてc76ovn03にて実施します。 ovs-vsctl showだけは02&03の両方で出力させます。 [root@c76ovn03 ~]# docker network ls NETWORK ID NAME DRIVER SCOPE 116424d7f10a bridge bridge local db62b02926e4 docker_gwbridge bridge local dcdbfcc3e390 host host local da1e0883a8ed none null local b5fb702e9489 ovs openvswitch global [root@c76ovn03 ~]# ovn-nbctl --db=tcp:192.168.30.101:6641 show switch b70b9243-80b3-4ad6-8940-55bff06251fc (b5fb702e948902881b1b933191b9ee83f8dad4eb434a9d27d408d7a2d5fe2aa2) port b7131d7ecd548dcc4b6eb38bef0179b1bc75645e5683b69e6131da69d0aed1be addresses: ["02:dc:06:e4:de:3c 192.168.31.2"] port 16b258df72cb52ddb2527be69578c1f953c9275e154d4107743b0ee3ac13f095 addresses: ["02:26:b3:e1:ab:5c 192.168.31.3"] port l2gwport type: l2gateway parent: tag: 301 addresses: ["unknown"] port 35d89c2d-0505-41aa-b0c6-6aff6f483899 addresses: ["52:54:00:f6:45:c2"] port 2c5a0afd-b12a-419e-b6f5-718c5d0e6446 addresses: ["52:54:00:d7:a6:96"] [root@c76ovn03 ~]# ovn-sbctl --db=tcp:192.168.30.101:6642 show Chassis "1fdd4703-9c73-4afd-adf3-e0e90b7afb63" hostname: "c76ovn03.md.jp" Encap geneve ip: "192.168.30.103" options: {csum="true"} Port_Binding "35d89c2d-0505-41aa-b0c6-6aff6f483899" Port_Binding "b7131d7ecd548dcc4b6eb38bef0179b1bc75645e5683b69e6131da69d0aed1be" Chassis "28928b40-900b-4f48-b4ed-8d9d2f1082fd" hostname: "c76ovn02.md.jp" Encap geneve ip: "192.168.30.102" options: {csum="true"} Port_Binding "16b258df72cb52ddb2527be69578c1f953c9275e154d4107743b0ee3ac13f095" Port_Binding "2c5a0afd-b12a-419e-b6f5-718c5d0e6446" Port_Binding "l2gwport" [root@c76ovn02 ~]# ovs-vsctl show 090be24a-f730-4d28-a4a0-dcf6d97fe618 Bridge br-int fail_mode: secure Port "16b258df72cb52d" Interface "16b258df72cb52d" Port "vnet1" tag: 301 Interface "vnet1" Port "patch-br-int-to-l2gwport" Interface "patch-br-int-to-l2gwport" type: patch options: {peer="patch-l2gwport-to-br-int"} Port "ovn-1fdd47-0" Interface "ovn-1fdd47-0" type: geneve options: {csum="true", key=flow, remote_ip="192.168.30.103"} Port br-int Interface br-int type: internal Bridge br-ext Port "patch-l2gwport-to-br-int" Interface "patch-l2gwport-to-br-int" type: patch options: {peer="patch-br-int-to-l2gwport"} Port br-ext Interface br-ext type: internal Port "ens36" trunks: [30, 300, 301] Interface "ens36" ovs_version: "2.11.1" [root@c76ovn03 ~]# ovs-vsctl show 2cbade66-e4e8-48e1-83e7-2ff460c1d665 Bridge br-ext Port "ens36" trunks: [300, 301] Interface "ens36" Port br-ext Interface br-ext type: internal Bridge br-int fail_mode: secure Port "ovn-28928b-0" Interface "ovn-28928b-0" type: geneve options: {csum="true", key=flow, remote_ip="192.168.30.102"} Port br-int Interface br-int type: internal Port "b7131d7ecd548dc" Interface "b7131d7ecd548dc" Port "vnet1" tag: 301 Interface "vnet1" ovs_version: "2.11.1" [root@c76ovn03 ~]# docker container exec c3 ping 192.168.31.2 PING 192.168.31.2 (192.168.31.2) 56(84) bytes of data. 64 bytes from 192.168.31.2: icmp_seq=1 ttl=64 time=0.029 ms 64 bytes from 192.168.31.2: icmp_seq=2 ttl=64 time=0.070 ms ^C [root@c76ovn03 ~]# docker container exec c3 ping 192.168.31.203 PING 192.168.31.203 (192.168.31.203) 56(84) bytes of data. 64 bytes from 192.168.31.203: icmp_seq=1 ttl=64 time=0.946 ms 64 bytes from 192.168.31.203: icmp_seq=2 ttl=64 time=0.697 ms ^C [root@c76ovn03 ~]# docker container exec c3 ping 192.168.31.2 PING 192.168.31.2 (192.168.31.2) 56(84) bytes of data. 64 bytes from 192.168.31.2: icmp_seq=1 ttl=64 time=0.028 ms 64 bytes from 192.168.31.2: icmp_seq=2 ttl=64 time=0.073 ms 64 bytes from 192.168.31.2: icmp_seq=3 ttl=64 time=0.027 ms ^C [root@c76ovn03 ~]# docker container exec c3 ping 192.168.31.202 PING 192.168.31.202 (192.168.31.202) 56(84) bytes of data. 64 bytes from 192.168.31.202: icmp_seq=1 ttl=64 time=2.34 ms 64 bytes from 192.168.31.202: icmp_seq=2 ttl=64 time=2.28 ms 64 bytes from 192.168.31.202: icmp_seq=3 ttl=64 time=2.98 ms ^C [root@c76ovn03 ~]# docker container exec c3 ping 192.168.31.203 PING 192.168.31.203 (192.168.31.203) 56(84) bytes of data. 64 bytes from 192.168.31.203: icmp_seq=1 ttl=64 time=0.256 ms 64 bytes from 192.168.31.203: icmp_seq=2 ttl=64 time=0.984 ms 64 bytes from 192.168.31.203: icmp_seq=3 ttl=64 time=0.262 ms ^C [root@c76ovn03 ~]# docker container exec c3 ping 192.168.31.254 PING 192.168.31.254 (192.168.31.254) 56(84) bytes of data. 64 bytes from 192.168.31.254: icmp_seq=1 ttl=64 time=9.48 ms 64 bytes from 192.168.31.254: icmp_seq=2 ttl=64 time=3.94 ms 64 bytes from 192.168.31.254: icmp_seq=3 ttl=64 time=3.91 ms
NorthboundDBとSouthboundDBの状態を確認する以下のコマンドですが
ovn-nbctl --db=tcp:192.168.30.101:6641 show ovn-sbctl --db=tcp:192.168.30.101:6642 show
図に起こすとこんな感じになります。
最初に載せた2つの図と合わせて観ると、より明確になってくるかと思います。
6.補足
ComputeNodeを再起動やShutdownしたいときは、以下のようなコマンドで必ずコンテナを終了させた後に、再起動やShutdownしてください。
docker container stop c2
というのも、Dockerコンテナのアタッチ時はほぼほぼ自動で設定してくれていましたが、デタッチ時は上記コマンドのように正常にコンテナを終了させないと、NorthboundDB上にゴミが残ります。場合によっては消せなくなるので、何度も繰り返し試したい方は必ずコンテナを終了させるようにしましょう。
以上です。
7.最後に
以下のサイトを参考にさせて頂きました。
OVN 設定サンプル | OVN config example 2015/12/27
Using OVN with KVM and Libvirt - Scott's Weblog - The weblog of an IT pro focusing on cloud computing, Kubernetes, Linux, containers, and networking
OVN - L2 Breakout Options | Blog @ Weiti.ORG
Dustin Spinhirne: The OVN Gateway Router
ovnは正直取っつきにくいかもしれません。
しかし、openstack stein以降では、ovnが実装されるようなので、今のうちから、しっかり理解しておくことは大切かなと思います。
また、今回はKVMとDockerでしたが、LXC/LXDでも試してみました。
しかし、FakeBridgeを使用する点が障壁となり疎通できませんでした。
さらに、アップリンク側にDPDKも動作させてみたのですが、設定方法は解ったものの、これまた疎通できずで断念しました。
Bridgeではなく、PAT+Routingだったら上手くいくような気がしていますが、取り急ぎ、一旦まとめてみようと思い今回の記事を書いた次第です。
なお、今回はl2gatewayという方法でBridgeさせましたが、localnetという方法もあります。こちらは、全ComputeNodeにてbr-extを作成した後、以下のコマンドでNorthboundDBに登録すれば設定可能です。
export SW_NAME=$(ovn-nbctl --db=tcp:192.168.30.101:6641 ls-list | awk '{print $2}' | sed s/\(//g | sed s/\)//g) ovn-nbctl --db=tcp:192.168.30.101:6641 lsp-add $SW_NAME lcntport "" 301 ovn-nbctl --db=tcp:192.168.30.101:6641 lsp-set-addresses lcntport unknown ovn-nbctl --db=tcp:192.168.30.101:6641 lsp-set-type lcntport localnet ovn-nbctl --db=tcp:192.168.30.101:6641 lsp-set-options lcntport network_name=physnet301
localnetの場合、冗長化できそうな雰囲気はありますが、L2ループの懸念があるため、あまり推奨されていないようです。
ただ、いずれにせよ、ovn単体で使うのはあまり現実的ではないと感じたので、やはりopenstackやovirtなどと一緒に使用するのが良いと思います。
*1:例外はあります。例えば、(1')は自動で設定されますが、その後(1)を手動設定した際に初めて利用可能となる、といったケースがあります。また、(2)を手動設定した後、(3)を設定しないと、(2’)や(3’)がNorthboundDB上で認識されない、など。
*2:ここではUntagやvlan300も作成されていますが、vlan301のみでOKです。他は削除して構いません。
*3:私の環境では、正しい設定に直してもエラーが解消されなかったりしました。本編とあまり関係の無いところで時間を取られるのは、しんどいのでスナップショットやクローン化をおススメします。
*4:上記(4)と(5)のコマンドは同じですが、それぞれのComputeNodeにて実行するため取得するIDが異なります。