容器如何使用虚拟化网络

SuKai June 25, 2022

前面文章介绍了Kube-OVN基于OVS/OVN将网络虚拟化带入云原生领域。下面我们通过下面的实验场景来看一下容器如何使用虚拟化网络的,从而了解Kube-OVN的基本工作原理。

实验环境

实验使用的是两台虚拟机:ovn-1为控制节点和计算节点,IP地址为:192.168.0.115。ovn-2为计算节点,IP地址为:192.168.0.114。

实验场景

1,两个主机上进入网络命名空间,配置不同网段进行通信

2,Docker运行容器,通过OVS internal port进行通信

3,Docker运行容器,通过veth pair进行通信

安装部署

#控制节点和计算节点
sudo apt install net-tools
sudo apt-get install python-six openssl -y
sudo apt-get install openvswitch-switch openvswitch-common -y
sudo systemctl disable apparmor
#控制节点
sudo apt-get install ovn-central ovn-common ovn-host -y
#计算节点
sudo apt-get install ovn-host ovn-common -y

配置ovn

设置ovn数据库允许tcp进行连接,默认只允许socket本地访问。

#控制节点
sudo ovn-nbctl set-connection ptcp:6641:0.0.0.0 -- set connection . inactivity_probe=60000
sudo ovn-sbctl set-connection ptcp:6642:0.0.0.0 -- set connection . inactivity_probe=60000
sudo ovs-appctl -t ovsdb-server ovsdb-server/add-remote ptcp:6640:192.168.0.115

配置ovs

设置ovs连接远程控制节点的数据库,配置节点间大二层网络封装协议类型。

#控制和计算节点
sudo ovs-vsctl set open . external-ids:ovn-remote=tcp:192.168.0.115:6642
sudo ovs-vsctl set open . external-ids:ovn-encap-type=geneve
sudo ovs-vsctl set open . external-ids:ovn-encap-ip=192.168.0.115 #本机IP

查看安装后状态

看到监听6641/6642端口,Chassis可以看到两个节点。

sukai@ovn-1:~$ ss -tlnp
State                   Recv-Q                  Send-Q                                   Local Address:Port                                   Peer Address:Port                 Process
LISTEN                  0                       10                                             0.0.0.0:6641                                        0.0.0.0:*
LISTEN                  0                       10                                             0.0.0.0:6642                                        0.0.0.0:*
LISTEN                  0                       4096                                     127.0.0.53%lo:53                                          0.0.0.0:*
LISTEN                  0                       128                                            0.0.0.0:22                                          0.0.0.0:*
LISTEN                  0                       128                                          127.0.0.1:6010                                        0.0.0.0:*
LISTEN                  0                       128                                               [::]:22                                             [::]:*
LISTEN                  0                       128                                              [::1]:6010                                           [::]:*
sukai@ovn-1:~$ sudo ovn-nbctl show
sukai@ovn-1:~$ sudo ovn-sbctl show
Chassis "6fa2da75-1393-4efe-984d-0c0310b95ad3"
    hostname: ovn-1
    Encap geneve
        ip: "192.168.0.115"
        options: {csum="true"}
Chassis "28a87e04-b738-4db0-a767-380091e1a752"
    hostname: ovn-2
    Encap geneve
        ip: "192.168.0.114"
        options: {csum="true"}
sukai@ovn-1:~$ 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: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 00:0c:29:d4:b7:e1 brd ff:ff:ff:ff:ff:ff
    inet 192.168.0.115/24 brd 192.168.0.255 scope global dynamic ens33
       valid_lft 85932sec preferred_lft 85932sec
    inet6 fe80::20c:29ff:fed4:b7e1/64 scope link
       valid_lft forever preferred_lft forever
3: ens34: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 00:0c:29:d4:b7:eb brd ff:ff:ff:ff:ff:ff
    inet 192.168.100.10/24 brd 192.168.100.255 scope global ens34
       valid_lft forever preferred_lft forever
    inet6 fe80::20c:29ff:fed4:b7eb/64 scope link
       valid_lft forever preferred_lft forever
4: ovs-system: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether b2:3d:a2:f9:17:b4 brd ff:ff:ff:ff:ff:ff
5: br-int: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether b6:32:20:a4:db:46 brd ff:ff:ff:ff:ff:ff
6: genev_sys_6081: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 65000 qdisc noqueue master ovs-system state UNKNOWN group default qlen 1000
    link/ether 5a:b1:c8:22:ac:7a brd ff:ff:ff:ff:ff:ff
    inet6 fe80::58b1:c8ff:fe22:ac7a/64 scope link
       valid_lft forever preferred_lft forever

场景一

创建路由器和两台交换机

chassis指定路由所在的主机为ovn-1

sudo ovn-nbctl create Logical_Router name=router options:chassis=6fa2da75-1393-4efe-984d-0c0310b95ad3
sudo ovn-nbctl ls-add lswitch1
sudo ovn-nbctl ls-add lswitch2

路由器添加两个端口

sudo ovn-nbctl lrp-add router lr-ls1 52:54:00:c1:68:50 10.0.0.1/24
sudo ovn-nbctl lrp-add router lr-ls2 52:54:00:c1:68:60 10.1.0.1/24

交换机1上添加连接路由器接口

sudo ovn-nbctl lsp-add lswitch1 ls1-lr1
sudo ovn-nbctl lsp-set-type ls1-lr1 router
sudo ovn-nbctl lsp-set-addresses ls1-lr1 52:54:00:c1:68:50
sudo ovn-nbctl lsp-set-options ls1-lr1 router-port=lr-ls1

交换机1上配置DHCP

dhcp_sw1=`sudo ovn-nbctl create DHCP_Options cidr=10.0.0.0/24 options="\"server_id\"=\"10.0.0.1\" \"server_mac\"=\"52:54:00:c1:68:50\" \"lease_time\"=\"3600\" \"router\"=\"10.0.0.1\""`
sudo ovn-nbctl lsp-set-dhcpv4-options ls1-vm1 $dhcp_sw1

交换机2上配置DHCP

dhcp_sw2=`sudo ovn-nbctl create DHCP_Options cidr=10.1.0.0/24 options="\"server_id\"=\"10.1.0.1\" \"server_mac\"=\"52:54:00:c1:68:60\" \"lease_time\"=\"3600\" \"router\"=\"10.1.0.1\""`
sudo ovn-nbctl lsp-set-dhcpv4-options ls2-vm2 $dhcp_sw2

交换机1上添加vm1接口

sudo ovn-nbctl lsp-add lswitch1 ls1-vm1
sudo ovn-nbctl lsp-set-addresses ls1-vm1 "02:ac:10:ff:01:30 10.0.0.10"
sudo ovn-nbctl lsp-set-port-security ls1-vm1 "02:ac:10:ff:01:30 10.0.0.10"

在ovn-1虚拟机上创建vm1网络命名空间,配置网卡

sudo ifconfig br-int up
sudo ip netns add vm1
sudo ovs-vsctl add-port br-int vm1 -- set interface vm1 type=internal
sudo ip link set vm1 address 02:ac:10:ff:01:30
sudo ip link set vm1 netns vm1
sudo ovs-vsctl set Interface vm1 external_ids:iface-id=ls1-vm1
sudo pkill dhclient
sudo ip netns exec vm1 dhclient vm1

在ovn-2虚拟机上创建vm2网络命名空间,配置网卡

sudo ifconfig br-int up
sudo ip netns add vm2
sudo ovs-vsctl add-port br-int vm2 -- set interface vm2 type=internal
sudo ip link set vm2 address 02:ac:10:ff:01:31
sudo ip link set vm2 netns vm2
sudo ovs-vsctl set Interface vm2 external_ids:iface-id=ls2-vm2
sudo pkill dhclient
sudo ip netns exec vm2 dhclient vm2

验证网络

sukai@ovn-1:~$ sudo ip netns exec vm1 /bin/bash
root@ovn-1:/home/sukai# ip a
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
7: vm1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default qlen 1000
    link/ether 02:ac:10:ff:01:30 brd ff:ff:ff:ff:ff:ff
    inet 10.0.0.10/24 brd 10.0.0.255 scope global dynamic vm1
       valid_lft 3541sec preferred_lft 3541sec
    inet6 fe80::ac:10ff:feff:130/64 scope link
       valid_lft forever preferred_lft forever
root@ovn-1:/home/sukai# ping 10.0.0.1
PING 10.0.0.1 (10.0.0.1) 56(84) bytes of data.
64 bytes from 10.0.0.1: icmp_seq=1 ttl=254 time=0.967 ms
64 bytes from 10.0.0.1: icmp_seq=2 ttl=254 time=0.858 ms
^C
--- 10.0.0.1 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 0.858/0.912/0.967/0.054 ms
root@ovn-1:/home/sukai# ping 10.10.0.1
PING 10.10.0.1 (10.10.0.1) 56(84) bytes of data.
^C
--- 10.10.0.1 ping statistics ---
2 packets transmitted, 0 received, 100% packet loss, time 1018ms

root@ovn-1:/home/sukai# ping 10.1.0.20
PING 10.1.0.20 (10.1.0.20) 56(84) bytes of data.
64 bytes from 10.1.0.20: icmp_seq=1 ttl=63 time=2.41 ms
64 bytes from 10.1.0.20: icmp_seq=2 ttl=63 time=1.41 ms
^C
--- 10.1.0.20 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1003ms
rtt min/avg/max/mdev = 1.410/1.909/2.409/0.499 ms

查看ovn信息

sukai@ovn-1:~$ sudo ovn-nbctl show
switch 75a787a4-9e55-4542-acaa-e969bebfaf16 (lswitch1)
    port ls1-vm1
        addresses: ["02:ac:10:ff:01:30 10.0.0.10"]
    port ls1-lr1
        type: router
        addresses: ["52:54:00:c1:68:50"]
        router-port: lr-ls1
switch d85756bc-e7d3-42fb-ace1-15168e017736 (lswitch2)
    port ls2-lr1
        type: router
        addresses: ["52:54:00:c1:68:60"]
        router-port: lr-ls2
    port ls2-vm2
        addresses: ["02:ac:10:ff:01:31 10.1.0.20"]
router 3bccdebe-38de-450c-8e02-208eaff33398 (router)
    port lr-ls2
        mac: "52:54:00:c1:68:60"
        networks: ["10.1.0.1/24"]
    port lr-ls1
        mac: "52:54:00:c1:68:50"
        networks: ["10.0.0.1/24"]
sukai@ovn-1:~$ sudo ovn-sbctl show
Chassis "6fa2da75-1393-4efe-984d-0c0310b95ad3"
    hostname: ovn-1
    Encap geneve
        ip: "192.168.0.115"
        options: {csum="true"}
    Port_Binding lr-ls2
    Port_Binding ls1-vm1
    Port_Binding ls2-lr1
    Port_Binding ls1-lr1
    Port_Binding lr-ls1
Chassis "28a87e04-b738-4db0-a767-380091e1a752"
    hostname: ovn-2
    Encap geneve
        ip: "192.168.0.114"
        options: {csum="true"}
    Port_Binding ls2-vm2

场景二

在交换机1上添加接口

sudo ovn-nbctl lsp-add lswitch1 ls1-ctn1
sudo ovn-nbctl lsp-set-addresses ls1-ctn1 "02:ac:10:ff:01:33 10.0.0.30"

创建容器

创建一个无网络容器

sudo docker run -itd --net=none --name ctn-1 library/alpine /bin/sh
sukai@ovn-1:~$ sudo docker ps
CONTAINER ID   IMAGE     COMMAND         CREATED         STATUS         PORTS     NAMES
ffb0b4da4866   alpine    "sleep 3600d"   3 minutes ago   Up 3 minutes             cont-1
34670a048857   alpine    "/bin/sh"       7 minutes ago   Up 7 minutes             ctn-1
sukai@ovn-1:~$ echo $NETNS
8608
sukai@ovn-1:~$ sudo docker exec -it ctn-1 /bin/sh
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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
/ #

配置容器使用ovs internal port

NETNS=`sudo docker inspect -f '{{.State.Pid}}' ctn-1`
sudo ln -s /proc/$NETNS/ns/net /var/run/netns/$NETNS
sudo ovs-vsctl add-port br-int ctn1 -- set Interface ctn1 type=internal
sudo ip link set ctn1 netns $NETNS
sudo ovs-vsctl set Interface ctn1 external_ids:iface-id=ls1-ctn1
sudo ip netns exec $NETNS ip link set ctn1 address 02:ac:10:ff:01:33
sudo ip netns exec $NETNS ip link set dev ctn1 up
sudo ip netns exec $NETNS ip addr add 10.0.0.30/24 dev ctn1
sudo ip netns exec $NETNS ip route add default via 10.0.0.1

查看ovs信息

sukai@ovn-1:~$ sudo ovs-vsctl show
93fd4842-e0e9-4413-a99a-2c11e4180a0a
    Bridge br-int
        fail_mode: secure
        Port ctn1
            Interface ctn1
                type: internal
        Port vm1
            Interface vm1
                type: internal
        Port br-int
            Interface br-int
                type: internal
        Port ovn-28a87e-0
            Interface ovn-28a87e-0
                type: geneve
                options: {csum="true", key=flow, remote_ip="192.168.0.114"}
    ovs_version: "2.13.5"
sukai@ovn-1:~$

验证网络

# 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
11: ctn1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default qlen 1000
    link/ether 02:ac:10:ff:01:33 brd ff:ff:ff:ff:ff:ff
    inet 10.0.0.30/24 scope global ctn1
       valid_lft forever preferred_lft forever
# ip route
default via 10.0.0.1 dev ctn1
10.0.0.0/24 dev ctn1 proto kernel scope link src 10.0.0.30

# ping -c 1 10.0.0.10
PING 10.0.0.10 (10.0.0.10) 56(84) bytes of data.
64 bytes from 10.0.0.10: icmp_seq=1 ttl=64 time=1.79 ms

--- 10.0.0.10 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 1.787/1.787/1.787/0.000 ms
# ping -c 1 10.0.0.1
PING 10.0.0.1 (10.0.0.1) 56(84) bytes of data.
64 bytes from 10.0.0.1: icmp_seq=1 ttl=254 time=1.47 ms

--- 10.0.0.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 1.472/1.472/1.472/0.000 ms
# ping -c 1 10.1.0.20
PING 10.1.0.20 (10.1.0.20) 56(84) bytes of data.
64 bytes from 10.1.0.20: icmp_seq=1 ttl=63 time=12.7 ms

--- 10.1.0.20 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 12.714/12.714/12.714/0.000 ms
#

场景三

在交换机2上添加容器接口

sudo ovn-nbctl lsp-add lswitch2 ls2-ctn2
sudo ovn-nbctl lsp-set-addresses ls2-ctn2 "02:ac:10:ff:01:34 10.1.0.40"

创建容器,通过veth pair方式使用ovs

创建一个veth对,一端接入br-int,一端接入容器veth2

sudo docker run -itd --net=none --name ctn-2 library/alpine /bin/sh

NETNS=`sudo docker inspect -f '{{.State.Pid}}' ctn-2`
sudo ln -s /proc/$NETNS/ns/net /var/run/netns/$NETNS
sudo ip link add veth8d5915b type veth peer name veth2
sudo ifconfig veth8d5915b up
sudo ovs-vsctl add-port br-int veth8d5915b
sudo ip link set veth2 netns $NETNS
sudo ovs-vsctl set Interface veth8d5915b external_ids:iface-id=ls2-ctn2
sudo ip netns exec $NETNS ip link set veth2 address 02:ac:10:ff:01:34
sudo ip netns exec $NETNS ip link set dev veth2 up
sudo ip netns exec $NETNS ip address add 10.1.0.40/24 dev veth2
sudo ip netns exec $NETNS ip route add default via 10.1.0.1

查看ovs/ovn信息

sukai@ovn-2:~$ sudo ovs-vsctl show
1ab53615-2604-4edf-ac6a-7a244803a25e
    Bridge br-int
        fail_mode: secure
        Port ovn-6fa2da-0
            Interface ovn-6fa2da-0
                type: geneve
                options: {csum="true", key=flow, remote_ip="192.168.0.115"}
        Port vm2
            Interface vm2
                type: internal
        Port veth8d5915b
            Interface veth8d5915b
        Port br-int
            Interface br-int
                type: internal
    ovs_version: "2.13.5"

sukai@ovn-1:~$ sudo ovn-nbctl show
switch 75a787a4-9e55-4542-acaa-e969bebfaf16 (lswitch1)
    port ls1-vm1
        addresses: ["02:ac:10:ff:01:30 10.0.0.10"]
    port ls1-ctn1
        addresses: ["02:ac:10:ff:01:33 10.0.0.30"]
    port ls1-lr1
        type: router
        addresses: ["52:54:00:c1:68:50"]
        router-port: lr-ls1
switch d85756bc-e7d3-42fb-ace1-15168e017736 (lswitch2)
    port ls2-ctn2
        addresses: ["02:ac:10:ff:01:34 10.1.0.40"]
    port ls2-lr1
        type: router
        addresses: ["52:54:00:c1:68:60"]
        router-port: lr-ls2
    port ls2-vm2
        addresses: ["02:ac:10:ff:01:31 10.1.0.20"]
router 3bccdebe-38de-450c-8e02-208eaff33398 (router)
    port lr-ls2
        mac: "52:54:00:c1:68:60"
        networks: ["10.1.0.1/24"]
    port lr-ls1
        mac: "52:54:00:c1:68:50"
        networks: ["10.0.0.1/24"]

sukai@ovn-1:~$ sudo ovn-sbctl show
Chassis "6fa2da75-1393-4efe-984d-0c0310b95ad3"
    hostname: ovn-1
    Encap geneve
        ip: "192.168.0.115"
        options: {csum="true"}
    Port_Binding ls1-vm1
    Port_Binding ls1-ctn1
    Port_Binding lr-ls2
    Port_Binding lr-ls1
    Port_Binding ls1-lr1
    Port_Binding ls2-lr1
Chassis "28a87e04-b738-4db0-a767-380091e1a752"
    hostname: ovn-2
    Encap geneve
        ip: "192.168.0.114"
        options: {csum="true"}
    Port_Binding ls2-ctn2
    Port_Binding ls2-vm2

验证网络

sukai@ovn-2:~$ sudo ifconfig veth8d5915b up
sukai@ovn-2:~$ sudo ip netns exec $NETNS /bin/sh
# 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
9: veth2@if10: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 02:ac:10:ff:01:34 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 10.1.0.40/24 scope global veth2
       valid_lft forever preferred_lft forever

# ip route
default via 10.1.0.1 dev veth2
10.1.0.0/24 dev veth2 proto kernel scope link src 10.1.0.40

# ping -c 1 10.1.0.1
PING 10.1.0.1 (10.1.0.1) 56(84) bytes of data.
64 bytes from 10.1.0.1: icmp_seq=1 ttl=254 time=4.97 ms

--- 10.1.0.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 4.965/4.965/4.965/0.000 ms
# ping -c 1 10.0.0.30
PING 10.0.0.30 (10.0.0.30) 56(84) bytes of data.
64 bytes from 10.0.0.30: icmp_seq=1 ttl=63 time=8.49 ms

--- 10.0.0.30 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 8.488/8.488/8.488/0.000 ms

总结

OVN让容器结合了虚拟化网络,容器运行平台具备了SDN能力。容器可以通过OVS Internal Port和Veth对两种方式接入网络。