使用ovs构建docker网络,实现跨主机通信与网络隔离
一、Open VSwitch简介
OVS简介
OpenvSwitch,简称OVS是一个虚拟交换软件,主要用于虚拟机VM环境,作为一个虚拟交换机,支持Xen/XenServer, KVM, and VirtualBox多种虚拟化技术。虽然是虚拟交换机,但是其工作原理与物理交换机类似。在虚拟交换机的实现中,其两端分别连接着物理网卡和多块虚拟网卡,同时虚拟交换机内部会维护一张映射表,根据MAC地址寻找对应的虚拟机链路进而完成数据转发。
OpenvSwitch是实现虚拟化网络的重要基础组件,在OpenStack中利用OpenvSwitch作为底层部件来完成虚拟网络提供和租户网络管理。OpenvSwitch可以实现访问控制功能,通过转发规则,可以实现简单的安全行为,包括通过、禁止等。
OVS组件
ovsdb-sever: OVS的数据库服务器,用来存储虚拟交换机的配置信息。它于manager和ovs-vswitchd交换信息使用了OVSDB(JSON-RPC)的方式。
ovs-vswitchd: OVS的核心部件,实现switch的daemon,包括一个支持流交换的Linux内核模块;和上层controller通信遵从OPENFLOW协议,与ovsdb-server通信使用OVSDB协议,和内核模块通过netlink通信,支持多个独立的datapath(网桥)。
ovs kernel module: OVS的内核模块,处理包交换和隧道,缓存flow,如果在内核的缓存中找到转发规则则转发,否则发向用户空间去处理。
ovs-vsctl: 查询和更新ovs-vswitchd的配置(通过对ovsdb进行配置)。
ovs-ofctl: 查询和控制OpenFlow交换机。
ovs-appctl: 发送命令消息,对daemon进行控制、查询ovs-dpctl 用来配置switch内核模块,一些Scripts and specs 辅助OVS安装在Citrix XenServer上,作为默认switch;
ovs-brcompatd 让ovs-vswitch替换Linuxbridge,包括获取bridge ioctls的Linux内核模块。
ovsdbmonitor GUI工具: 可以远程获取OVS数据库和OpenFlow的流表。
此外,OVS也提供了支持OpenFlow的特性实现,包括
ovs-openflowd:一个简单的OpenFlow交换机。
ovs-controller:一个简单的OpenFlow控制器。
ovs-pki:OpenFlow交换机创建和管理公钥框架。
ovs-tcpundump:tcpdump的补丁,解析OpenFlow的消息。
工作流程
支持OpenFlow的OVS核心架构主要包括OpenFlow协议支持和数据转发通路等两个部分。OVS的数据转发通路(datapath)主要用于执行数据交换工作,即负责从设备入端口接收数据包并依据流表信息对其进行管理,例如将其转发至出端口、丢弃或者进行数据包修改。而OVS的OpenFlow协议支持则用于实现交换策略,即通过增加、删除、修改流表项的方式告诉数据转发通路针对不同的数据流采用不同的动作。
报文从端口上来(1),在datapatch中转发,查询Flow Table(6),如果查到了直接转出去(7)。
如果未查询到,送到用户态(2),在vswitchd中查询软表,生成精确的flow table下发到kernel(4),然后报文被送回kernel继续转发(5),此时会再查询flow table(6),然后转发出去(7)。
·Datapath是在kernel mode。
·Datapath里是精确匹配,计算报文头的hash与流表进行匹配,匹配到了进行转发。
·Datapath里未匹配时,送到userspace进行软件查找转发,并在datapath里添加精确匹配流表。
·Datapath里的流会老化。
二、初始化环境
systemctl stop firewalld.service && systemctl disable firewalld.service
sed -i "s/SELINUX=enforcing/SELINUX=disabled/" /etc/selinux/config
升级内核:
rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org
rpm -Uvh http://www.elrepo.org/elrepo-release-7.0-2.el7.elrepo.noarch.rpm
yum --enablerepo=elrepo-kernel install kernel-ml-devel kernel-ml
awk -F\' '$1=="menuentry " {print $2}' /etc/grub2.cfg
grub2-set-default 0
reboot
uname -a
安装docker:
yum -y install docker-io
yum list installed | grep docker
鉴于国内网络问题,后续拉取 Docker 镜像十分缓慢,我们可以需要配置加速器来解决,我使用的是阿里的镜像地址:
在/etc/docker/daemon.json文件中添加如下内容.
{
"registry-mirrors": ["https://wghlmi3i.mirror.aliyuncs.com"]
}
或者使用如下地址
{
"registry-mirrors": ["https://registry.docker-cn.com"]
}
systemctl start docker.service
安装open vswitch:
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
wget ftp://ftp.muug.mb.ca/mirror/centos/7.2.1511/virt/x86_64/ovirt-3.6/openvswitch-2.4.0-1.el7.x86_64.rpm
yum localinstall openvswitch-2.4.0-1.el7.x86_64.rpm -y
systemctl start openvswitch && systemctl is-active openvswitch
ovs-vsctl -V
systemctl enable openvswitch
安装pipework:
yum install git
git clone https://github.com/jpetazzo/pipework
cp pipework/pipework /bin
一些工具安装:
yum install bridge-utils # 如果brctl不能用
yum install net-tools # 如果route命令不能用
三、单节点上使用ovs vlan划分网络
启动四个容器:
docker run -itd --name con1 ubuntu:14.04 /bin/bash
docker run -itd --name con2 ubuntu:14.04 /bin/bash
docker run -itd --name con3 ubuntu:14.04 /bin/bash
docker run -itd --name con4 ubuntu:14.04 /bin/bash
创建ovs网桥并绑定端口
pipework ovs0 con1 192.168.0.1/24 @100
pipework ovs0 con2 192.168.0.2/24 @100
pipework ovs0 con3 192.168.0.3/24 @200
pipework ovs0 con4 192.168.0.4/24 @200
这样con1 和 con2是通的,con3和con4是通的,这个比较简单。pipework干的具体的事是:
验证:
[root@zabbix-node1 ~]# docker exec -it con1 /bin/bash
root@c7b302585796:/# ping -c 2 192.168.0.1
PING 192.168.0.1 (192.168.0.1) 56(84) bytes of data.
64 bytes from 192.168.0.1: icmp_seq=1 ttl=64 time=0.035 ms
64 bytes from 192.168.0.1: icmp_seq=2 ttl=64 time=0.103 ms
root@c7b302585796:/# ping -c 2 192.168.0.2
PING 192.168.0.2 (192.168.0.2) 56(84) bytes of data.
64 bytes from 192.168.0.2: icmp_seq=1 ttl=64 time=0.908 ms
64 bytes from 192.168.0.2: icmp_seq=2 ttl=64 time=0.441 ms
root@c7b302585796:/# ping -c 2 192.168.0.3
PING 192.168.0.3 (192.168.0.3) 56(84) bytes of data.
From 192.168.0.1 icmp_seq=1 Destination Host Unreachable
From 192.168.0.1 icmp_seq=2 Destination Host Unreachable
root@c7b302585796:/# ping -c 2 192.168.0.4
PING 192.168.0.4 (192.168.0.4) 56(84) bytes of data.
From 192.168.0.1 icmp_seq=1 Destination Host Unreachable
From 192.168.0.1 icmp_seq=2 Destination Host Unreachable
ovs-vsctl add-port ovs0 [容器的虚拟网卡设备] tag=100
ovs划分vlan处理的原理也非常简单,包进入到switch时打上tag,发出去时去掉tag,发出去的端口与包的tag不匹配时不处理,这便实现了二层隔离。
access端口与trunk端口的区别是,trunk端口可接受多个tag。
四、Vxlan实现跨主机通信
host1:192.169.91.133
ovs0
|
|-veth1 <-------> eth1 192.168.0.9 con9
|
|-vxlan1-------------+
| |
|
host2:192.169.91.134 |
ovs0 |
| |
|-vxlan1------------+
|
|-veth1 <--------> eth1 192.168.0.10 con10
|
可以看到con9和con10在搭建vxlan之前是无法通信的。
在192.168.91.133主机上:
[root@zabbix-node1 ~]# docker run --name con9 -itd ubuntu:14.04 /bin/bash
[root@zabbix-node1 ~]# ovs-vsctl add-br ovs0 #如果有ovs就不需要再创建了
[root@zabbix-node1 ~]# pipework ovs0 con9 192.168.0.9/24 # 给容器分配地址并挂到ovs0上
[root@zabbix-node1 ~]# ovs-vsctl add-port ovs0 vxlan1 -- set interface vxlan1 type=vxlan options:remote_ip=192.168.91.134 options:key=flow # 创建vxlan,ip是对端的ip
[root@zabbix-node1 ~]# ovs-vsctl show
61238121-5f2e-40da-bdf7-07c0667d9090
Bridge "ovs0"
Port "ovs0"
Interface "ovs0"
type: internal
Port "veth1pl3467"
tag: 200
Interface "veth1pl3467"
Port "vxlan1"
Interface "vxlan1"
type: vxlan
options: {key=flow, remote_ip="192.168.91.134"}
Port "veth1pl1568"
tag: 100
Interface "veth1pl1568"
Port "veth1pl3320"
tag: 100
Interface "veth1pl3320"
Port "veth1pl1621"
tag: 200
Interface "veth1pl1621"
Port "veth1pl3919"
Interface "veth1pl3919"
Port "ens33"
Interface "ens33"
Port "veth1pl3368"
tag: 100
Interface "veth1pl3368"
Port "veth1pl3419"
tag: 200
Interface "veth1pl3419"
ovs_version: "2.4.0"
192.168.91.134上同理:
[root@linux-node2 ~]# docker run --name con10 -itd ubuntu:14.04 /bin/bash
[root@linux-node2 ~]# ovs-vsctl add-br ovs0 #如果有ovs就不需要再创建了
[root@linux-node2 ~]# pipework ovs0 con10 192.168.0.10/24 # 给容器分配地址并挂到ovs0上
[root@linux-node2 ~]# ovs-vsctl add-port ovs0 vxlan1 -- set interface vxlan1 type=vxlan options:remote_ip=192.168.91.133 options:key=flow # 创建vxlan
[root@linux-node2 ~]# ovs-vsctl show
95cbcb52-3564-4453-8de0-fee6b6a5389e
Bridge "ovs0"
Port "veth1pl2051"
Interface "veth1pl2051"
Port "ens33"
Interface "ens33"
Port "ovs0"
Interface "ovs0"
type: internal
Port "vxlan1"
Interface "vxlan1"
type: vxlan
options: {key=flow, remote_ip="192.168.91.133"}
ovs_version: "2.4.0"
验证:
[root@linux-node2 ~]# docker exec con10 ping 192.168.0.9 # con10容器中ping con9的地址,可通
PING 192.168.0.9 (192.168.0.9) 56(84) bytes of data.
64 bytes from 192.168.0.9: icmp_seq=1 ttl=64 time=11.9 ms
64 bytes from 192.168.0.9: icmp_seq=2 ttl=64 time=2.05 ms
或者进入容器
[root@linux-node2 ~]# docker exec -it con10 /bin/bash
root@70006a39f7f9:/# ping -c 3 192.168.0.9
PING 192.168.0.9 (192.168.0.9) 56(84) bytes of data.
64 bytes from 192.168.0.9: icmp_seq=1 ttl=64 time=50.1 ms
64 bytes from 192.168.0.9: icmp_seq=2 ttl=64 time=54.7 ms
64 bytes from 192.168.0.9: icmp_seq=3 ttl=64 time=27.3 ms
[root@zabbix-node1 ~]# docker exec -it con9 /bin/bash
root@56f27731b150:/# ping -c 3 192.168.0.10
PING 192.168.0.10 (192.168.0.10) 56(84) bytes of data.
64 bytes from 192.168.0.10: icmp_seq=1 ttl=64 time=11.0 ms
64 bytes from 192.168.0.10: icmp_seq=2 ttl=64 time=8.17 ms
64 bytes from 192.168.0.10: icmp_seq=3 ttl=64 time=9.90 ms
OVS常用操作:
1.添加网桥:ovs-vsctl add-br 交换机名
2.删除网桥:ovs-vsctl del-br 交换机名
3.添加端口:ovs-vsctl add-port 交换机名 端口名(网卡名)
4.删除端口:ovs-vsctl del-port 交换机名 端口名(网卡名)
5.连接控制器:ovs-vsctl set-controller 交换机名 tcp:IP地址:端口号
6.断开控制器:ovs-vsctl del-controller 交换机名
7.列出所有网桥:ovs-vsctl list-br
8.列出网桥中的所有端口:ovs-vsctl list-ports 交换机名
9.列出所有挂接到网卡的网桥:ovs-vsctl port-to-br 端口名(网卡名)
10.查看open vswitch的网络状态:ovs-vsctl show
11.查看 Open vSwitch 中的端口信息(交换机对应的 dpid,以及每个端口的 OpenFlow 端口编号,端口名称,当前状态等等):ovs-ofctl show 交换机名
12.修改dpid:ovs-vsctl set bridge 交换机名 other_config:datapath-id=新DPID
13.修改端口号:ovs-vsctl set Interface 端口名 ofport_request=新端口号
14.查看交换机中的所有 Table:ovs-ofctl dump-tables ovs-switch
15.查看交换机中的所有流表项:ovs−ofctl dump−flows ovs-switch
16.删除编号为 100 的端口上的所有流表项:ovs-ofctl del-flows ovs-switch “in_port=100”
17.添加流表项(以“添加新的 OpenFlow 条目,修改从端口 p0 收到的数据包的源地址为 9.181.137.1”为例):
ovs-ofctl add-flow ovs-switch “priority=1 idle_timeout=0,in_port=100,actions=mod_nw_src:9.181.137.1,normal”
18.查看 OVS 的版本信息:ovs-appctl –version
19.查看 OVS 支持的 OpenFlow 协议的版本:ovs-ofctl –version