共计 11966 个字符,预计需要花费 30 分钟才能阅读完成。
sdn (software defines network)
看了些相关的资料,这里记录一下自己对 sdn 的理解,能力有限,如有错误欢迎指正。
sdn 软件定义网络,目的是想要利用软件来模拟网络设备,如交换机,路由器之类的。
为什么需要这么做? 一个主要原因是云计算的高速发展,给传统的数据中心带来了更加灵活和复杂的组网需求。
传统网络设备完成数据中心服务器的组网,在此之上,通过 sdn 来完成虚机和容器之间的连通
ovs (openvSwitch)
官方的说法:Open vSwitch 是一款高质量的多层虚拟交换机,以开源 Apache 2 许可证授权,非常适合在虚拟机环境中充当 2 层交换机。支持多种基于 Linux 的虚拟化技术,包括 Xen / XenServer、KVM 和 VirtualBox。
支持 Open Flow 协议,所以可以很方便的通过编程实现大规模网络的自动化,被大量运用于 SDN 网络中。
架构和原理之类的文章很多,这里就不在一一阐述,本文以实践为主。
安装
# 安装 docker
yum install -y docker-1.13.1
# 预安装
yum -y install wget openssl-devel gcc make python-devel openssl-devel kernel-devel graphviz kernel-debug-devel autoconf automake rpm-build redhat-rpm-config libtool python-twisted-core python-zope-interface PyQt4 desktop-file-utils libcap-ng-devel groff checkpolicy selinux-policy-devel
# 安装 open vswitch:
yum install -y openvswitch-2.8.2-1.el7.x86_64 # 此版本包含 ovs-docker
systemctl start openvswitch.service
systemctl is-active openvswitch
systemctl enable openvswitch
ovs 单机连通性
创建容器, 设置 net=none 可以防止 docker0 默认网桥影响连通性测试
docker run -itd --name con6 --net=none ubuntu:14.04 /bin/bash
docker run -itd --name con7 --net=none ubuntu:14.04 /bin/bash
docker run -itd --name con8 --net=none ubuntu:14.04 /bin/bash
创建网桥
ovs-vsctl add-br ovs0
使用 ovs-docker 给容器添加网卡,并挂到 ovs0 网桥上
ovs-docker add-port ovs0 eth0 con6 --ipaddress=192.168.1.2/24
ovs-docker add-port ovs0 eth0 con7 --ipaddress=192.168.1.3/24
ovs-docker add-port ovs0 eth0 con8 --ipaddress=192.168.1.4/24
查看网桥
[root@controller /]# ovs-vsctl show
21e4d4c5-cadd-4dac-b025-c20b8108ad09
Bridge "ovs0"
Port "b167e3dcf8db4_l"
Interface "b167e3dcf8db4_l"
Port "f1c0a9d0994d4_l"
Interface "f1c0a9d0994d4_l"
Port "121c6b2f221c4_l"
Interface "121c6b2f221c4_l"
Port "ovs0"
Interface "ovs0"
type: internal
ovs_version: "2.8.2"
测试连通性
[root@controller /]# docker exec -it con8 sh
# ping 192.168.1.2
PING 192.168.1.2 (192.168.1.2) 56(84) bytes of data.
64 bytes from 192.168.1.2: icmp_seq=1 ttl=64 time=0.886 ms
^C
--- 192.168.1.2 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.886/0.886/0.886/0.000 ms
#
# ping 192.168.1.3
PING 192.168.1.3 (192.168.1.3) 56(84) bytes of data.
64 bytes from 192.168.1.3: icmp_seq=1 ttl=64 time=0.712 ms
^C
--- 192.168.1.3 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.712/0.712/0.712/0.000 ms
#
设置 VLAN tag
查看网桥
[root@controller /]# ovs-vsctl show
21e4d4c5-cadd-4dac-b025-c20b8108ad09
Bridge "ovs0"
Port "b167e3dcf8db4_l"
Interface "b167e3dcf8db4_l"
Port "f1c0a9d0994d4_l"
Interface "f1c0a9d0994d4_l"
Port "121c6b2f221c4_l"
Interface "121c6b2f221c4_l"
Port "ovs0"
Interface "ovs0"
type: internal
ovs_version: "2.8.2"
查看 interface
[root@controller /]# ovs-vsctl list interface f1c0a9d0994d4_l
_uuid : cf400e7c-d2d6-4e0a-ad02-663dd63d1751
admin_state : up
duplex : full
error : []
external_ids : {container_id="con6", container_iface="eth0"}
ifindex : 239
ingress_policing_burst: 0
ingress_policing_rate: 0
lacp_current : []
link_resets : 1
link_speed : 10000000000
link_state : up
mac_in_use : "96:91:0a:c9:02:d6"
mtu : 1500
mtu_request : []
name : "f1c0a9d0994d4_l"
ofport : 3
other_config : {}
statistics : {collisions=0, rx_bytes=1328, rx_crc_err=0, rx_dropped=0, rx_errors=0, rx_frame_err=0, rx_over_err=0, rx_packets=18, tx_bytes=3032, tx_dropped=0, tx_errors=0, tx_packets=40}
status : {driver_name=veth, driver_version="1.0", firmware_version=""}
type : ""
设置 vlan tag
ovs-vsctl set port f1c0a9d0994d4_l tag=100 //con6
ovs-vsctl set port b167e3dcf8db4_l tag=100 //con8
ovs-vsctl set port 121c6b2f221c4_l tag=200 //con7
测试连通性
[root@controller /]# docker exec -it con8 sh
#
# ping 192.168.1.2 -c 3
PING 192.168.1.2 (192.168.1.2) 56(84) bytes of data.
64 bytes from 192.168.1.2: icmp_seq=1 ttl=64 time=0.413 ms
64 bytes from 192.168.1.2: icmp_seq=2 ttl=64 time=0.061 ms
64 bytes from 192.168.1.2: icmp_seq=3 ttl=64 time=0.057 ms
--- 192.168.1.2 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2044ms
rtt min/avg/max/mdev = 0.057/0.177/0.413/0.166 ms
#
# ping 192.168.1.3 -c 3
PING 192.168.1.3 (192.168.1.3) 56(84) bytes of data.
From 192.168.1.4 icmp_seq=1 Destination Host Unreachable
From 192.168.1.4 icmp_seq=2 Destination Host Unreachable
--- 192.168.1.3 ping statistics ---
3 packets transmitted, 0 received, +3 errors, 100% packet loss, time 2068ms
pipe 3
#
跨主机连通性
环境
host1 172.29.101.123
网桥: ovs0
容器:
con6 192.168.1.2
con7 192.168.1.3
con8 192.168.1.4
创建方式依上
host2 172.29.101.82
网桥: ovs1
容器: con11
准备环境
创建网桥
ovs-vsctl add-br ovs1
创建容器
docker run -itd --name con11 --net=none ubuntu:14.04 /bin/bash
挂到 ovs0 网桥
ovs-docker add-port ovs1 eth0 con11 --ipaddress=192.168.1.6/24
查看网桥 ovs1
[root@compute82 /]# ovs-vsctl show
380ce027-8edf-4844-8e89-a6b9c1adaff3
Bridge "ovs1"
Port "0384251973e64_l"
Interface "0384251973e64_l"
Port "ovs1"
Interface "ovs1"
type: internal
ovs_version: "2.8.2"
设置 vxlan
在 host1 上
[root@controller /]# ovs-vsctl add-port ovs0 vxlan1 -- set interface vxlan1 type=vxlan options:remote_ip=172.29.101.82 options:key=flow
[root@controller /]#
[root@controller /]# ovs-vsctl show
21e4d4c5-cadd-4dac-b025-c20b8108ad09
Bridge "ovs0"
Port "b167e3dcf8db4_l"
tag: 100
Interface "b167e3dcf8db4_l"
Port "f1c0a9d0994d4_l"
tag: 100
Interface "f1c0a9d0994d4_l"
Port "121c6b2f221c4_l"
tag: 200
Interface "121c6b2f221c4_l"
Port "ovs0"
Interface "ovs0"
type: internal
Port "vxlan1"
Interface "vxlan1"
type: vxlan
options: {key=flow, remote_ip="172.29.101.82"}
ovs_version: "2.8.2"
在 host2 上
[root@compute82 /]# ovs-vsctl add-port ovs1 vxlan1 -- set interface vxlan1 type=vxlan options:remote_ip=172.29.101.123 options:key=flow
[root@compute82 /]#
[root@compute82 /]# ovs-vsctl show
380ce027-8edf-4844-8e89-a6b9c1adaff3
Bridge "ovs1"
Port "0384251973e64_l"
Interface "0384251973e64_l"
Port "vxlan1"
Interface "vxlan1"
type: vxlan
options: {key=flow, remote_ip="172.29.101.123"}
Port "ovs1"
Interface "ovs1"
type: internal
ovs_version: "2.8.2"
设置 vlan tag
ovs-vsctl set port 0384251973e64_l tag=100
连通性测试
[root@compute82 /]# docker exec -ti con11 bash
root@c82da61bf925:/# ping 192.168.1.2
PING 192.168.1.2 (192.168.1.2) 56(84) bytes of data.
64 bytes from 192.168.1.2: icmp_seq=1 ttl=64 time=0.161 ms
64 bytes from 192.168.1.2: icmp_seq=2 ttl=64 time=0.206 ms
^C
--- 192.168.1.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1000ms
root@c82da61bf925:/#
root@c82da61bf925:/# ping 192.168.1.3
PING 192.168.1.3 (192.168.1.3) 56(84) bytes of data.
^C
--- 192.168.1.3 ping statistics ---
3 packets transmitted, 0 received, 100% packet loss, time 2027ms
root@c82da61bf925:/#
root@c82da61bf925:/# exit
结论
vxlan 只能连通两台机器的 ovs 上同一个网段的容器,无法连通 ovs 上不同网段的容器。如果需要连通不同网段的容器,接下来我们尝试通过 ovs 的流表来解决这个问题。
OpenFlow
flow table
支持 openflow 的交换机中可能包含多个 flow table。每个 flow table 包含多条规则,每条规则包含匹配条件和执行动作。flow table 中的每条规则有优先级,优先级高的优先匹配,匹配到规则以后,执行 action,如果匹配失败,按优先级高低,继续匹配下一条。如果都不匹配,每张表会有默认的动作,一般为 drop 或者转给下一张流表。
实践
环境
host1 172.29.101.123
网桥: ovs0
容器:
con6 192.168.1.2 tag=100
con7 192.168.1.3 tag=100
host2 172.29.101.82
网桥: ovs1
容器:
con9: 192.168.2.2 tag=100
con10:192.168.2.3 tag=100
con11: 192.168.1.5 tag=100
查看默认流表
在 host1 上查看默认流表
[root@controller msxu]# ovs-ofctl dump-flows ovs0
cookie=0x0, duration=27858.050s, table=0, n_packets=5253660876, n_bytes=371729202788, priority=0 actions=NORMAL
在容器 con6 中 ping con7,网络连通
[root@controller /]# docker exec -ti con6 bash
root@9ccc5c5664f9:/#
root@9ccc5c5664f9:/# ping 192.168.1.3
PING 192.168.1.3 (192.168.1.3) 56(84) bytes of data.
64 bytes from 192.168.1.3: icmp_seq=1 ttl=64 time=0.613 ms
64 bytes from 192.168.1.3: icmp_seq=2 ttl=64 time=0.066 ms
--- 192.168.1.3 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1058ms
rtt min/avg/max/mdev = 0.066/0.339/0.613/0.274 ms
root@9ccc5c5664f9:/#
删除默认流表
[root@controller /]# ovs-ofctl del-flows ovs0
[root@controller /]#
[root@controller /]# ovs-ofctl dump-flows ovs0
[root@controller /]#
测试网络连通性,发现网络已经不通
[root@controller /]# docker exec -ti con6 bash
root@9ccc5c5664f9:/#
root@9ccc5c5664f9:/# ping 192.168.1.3
PING 192.168.1.3 (192.168.1.3) 56(84) bytes of data.
^C
--- 192.168.1.3 ping statistics ---
2 packets transmitted, 0 received, 100% packet loss, time 1025ms
root@9ccc5c5664f9:/#
添加流表
如果要 con6 和 con7 能够通信,需要建立规则,让 ovs 转发对应的数据
查看 con6 和 con7 在 ovs 上的网络端口
[root@controller /]# ovs-vsctl show
21e4d4c5-cadd-4dac-b025-c20b8108ad09
Bridge "ovs0"
Port "f1c0a9d0994d4_l"
tag: 100
Interface "f1c0a9d0994d4_l"
Port "121c6b2f221c4_l"
tag: 100
Interface "121c6b2f221c4_l"
Port "ovs0"
Interface "ovs0"
type: internal
Port "vxlan1"
Interface "vxlan1"
type: vxlan
options: {key=flow, remote_ip="172.29.101.82"}
ovs_version: "2.8.2"
[root@controller /]# ovs-vsctl list interface f1c0a9d0994d4_l |grep ofport
ofport : 3
ofport_request : []
[root@controller /]#
[root@controller /]# ovs-vsctl list interface 121c6b2f221c4_l |grep ofport
ofport : 4
ofport_request : []
添加规则:
[root@controller /]#ovs-ofctl add-flow ovs0 "priority=1,in_port=3,actions=output:4"
[root@controller /]#ovs-ofctl add-flow ovs0 "priority=2,in_port=4,actions=output:3"
[root@controller /]# ovs-ofctl dump-flows ovs0
cookie=0x0, duration=60.440s, table=0, n_packets=0, n_bytes=0, priority=1,in_port="f1c0a9d0994d4_l" actions=output:"121c6b2f221c4_l"
cookie=0x0, duration=50.791s, table=0, n_packets=0, n_bytes=0, priority=1,in_port="121c6b2f221c4_l" actions=output:"f1c0a9d0994d4_l"
[root@controller /]#
测试连通性:con6 和 con7 已通
[root@controller msxu]# docker exec -ti con6 bash
root@9ccc5c5664f9:/# ping 192.168.1.3
PING 192.168.1.3 (192.168.1.3) 56(84) bytes of data.
64 bytes from 192.168.1.3: icmp_seq=1 ttl=64 time=0.924 ms
64 bytes from 192.168.1.3: icmp_seq=2 ttl=64 time=0.058 ms
^C
--- 192.168.1.3 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1057ms
rtt min/avg/max/mdev = 0.058/0.491/0.924/0.433 ms
root@9ccc5c5664f9:/#
设置一条优先级高的规则:
[root@controller /]# ovs-ofctl add-flow ovs0 "priority=2,in_port=4,actions=drop"
[root@controller /]#
[root@controller /]# docker exec -ti con6 bash
root@9ccc5c5664f9:/#
root@9ccc5c5664f9:/# ping 192.168.1.3
PING 192.168.1.3 (192.168.1.3) 56(84) bytes of data.
^C
--- 192.168.1.3 ping statistics ---
3 packets transmitted, 0 received, 100% packet loss, time 2087ms
root@9ccc5c5664f9:/#
root@9ccc5c5664f9:/#
流表中的规则是有优先级的,priority 数值越大,优先级越高。流表中,优先级高的优先匹配,并执行匹配规则的 actions。如果不匹配,继续匹配优先级低的下一条。
跨网段连通
在上一个 vxlan 的实践中,通过设置 vxlan 可以打通两个机器上的 ovs,但我们提到两个机器 ovs 上的容器得在同一个网段上才能通信。
在 ip 为 192.168.2.2 的 con9 上 ping 另一台机上的 con6 192.168.1.2
[root@compute82 /]# docker exec -ti con9 bash
root@b55602aad0ac:/#
root@b55602aad0ac:/# ping 192.168.1.2
connect: Network is unreachable
root@b55602aad0ac:/#
添加流表规则:
在 host1 上:
[root@controller /]# ovs-ofctl add-flow ovs0 "priority=4,in_port=6,actions=output:3"
[root@controller /]#
[root@controller /]# ovs-ofctl add-flow ovs0 "priority=4,in_port=3,actions=output:6"
[root@controller /]# ovs-ofctl dump-flows ovs0
cookie=0x0, duration=3228.737s, table=0, n_packets=7, n_bytes=490, priority=1,in_port="f1c0a9d0994d4_l" actions=output:"121c6b2f221c4_l"
cookie=0x0, duration=3215.544s, table=0, n_packets=0, n_bytes=0, priority=1,in_port="121c6b2f221c4_l" actions=output:"f1c0a9d0994d4_l"
cookie=0x0, duration=3168.297s, table=0, n_packets=9, n_bytes=546, priority=2,in_port="121c6b2f221c4_l" actions=drop
cookie=0x0, duration=12.024s, table=0, n_packets=0, n_bytes=0, priority=4,in_port=vxlan1 actions=output:"f1c0a9d0994d4_l"
cookie=0x0, duration=3.168s, table=0, n_packets=0, n_bytes=0, priority=4,in_port="f1c0a9d0994d4_l" actions=output:vxlan1
在 host2 上
[root@compute82 /]# ovs-ofctl add-flow ovs1 "priority=1,in_port=1,actions=output:6"
[root@compute82 /]#
[root@compute82 /]# ovs-ofctl add-flow ovs1 "priority=1,in_port=6,actions=output:1"
[root@compute82 /]# ovs-ofctl dump-flows ovs1
cookie=0x0, duration=1076.522s, table=0, n_packets=27, n_bytes=1134, priority=1,in_port="0384251973e64_l" actions=output:vxlan1
cookie=0x0, duration=936.403s, table=0, n_packets=0, n_bytes=0, priority=1,in_port=vxlan1 actions=output:"0384251973e64_l"
cookie=0x0, duration=70205.443s, table=0, n_packets=7325, n_bytes=740137, priority=0 actions=NORMAL
测试连通性
在 host2 con9 上 ping 192.168.1.2
[root@compute82 /]# docker exec -ti con9 bash
root@b55602aad0ac:/#
root@b55602aad0ac:/# ping 192.168.1.2
connect: Network is unreachable
root@b55602aad0ac:/#
发现网络并不通,查看发现路由规则有问题,添加默认路由规则,注意这里需要已 privileged 权限进入容器
[root@compute82 /]# docker exec --privileged -ti con9 bash
root@b55602aad0ac:/#
root@b55602aad0ac:/# route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
192.168.2.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0
root@b55602aad0ac:/# route add default dev eth0
root@b55602aad0ac:/#
root@b55602aad0ac:/# route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 0.0.0.0 0.0.0.0 U 0 0 0 eth0
192.168.2.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0
root@b55602aad0ac:/#
在 host1 和 host2 的容器中都添加好路由规则后,测试连通性
[root@compute82 /]# docker exec --privileged -ti con9 bash
root@b55602aad0ac:/#
root@b55602aad0ac:/# ping 192.168.1.2
PING 192.168.1.2 (192.168.1.2) 56(84) bytes of data.
64 bytes from 192.168.1.2: icmp_seq=1 ttl=64 time=1.16 ms
64 bytes from 192.168.1.2: icmp_seq=2 ttl=64 time=0.314 ms
^C
--- 192.168.1.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 0.314/0.739/1.165/0.426 ms
已成功通过 ovs,vxlan 打通两台机器上不同网段容器