1.网络虚拟化
引入
上一篇讲提到的其中一个问题
问:为什么可以不需要实际的交换机路由器,也能弄出网络来?
答:是因为OpenStack中采用了网络虚拟化技术
先来说说为什么需要网络虚拟化技术,不要会怎么样?
没有网络虚拟化出现的问题
(1) MAC和ARP表项不足
代码语言:txt复制假设一个互联网云计算中心的服务器有5000台,按照1:20的比例进行虚拟化,则有10万个虚拟机。
通常每个虚拟机会配置两个业务网口,这样这个云计算中心就有20万个虚拟网口,对应的就是需要20万个MAC地址和IP地址。云计算要求资源灵活调度,业务资源任意迁移。也就是说任意一个虚拟机可以在整个云计算网络中任意迁移。这就要求全网在一个统一的二层网络中。
全网任意交换机都有可能学习到全网所有的MAC表项。与此对应的则是,目前业界主流的接入交换机的MAC表项只有32K,基本无法满足互联网云计算的需求。
另外,网关需要记录全网所有主机、所有网口的ARP信息。这就需要网关设备的有效ARP表项超过20万。大部分的网关设备芯片都不具备这种能力。
(2)4K VLAN Trunk
传统的大二层网络支持任意VLAN的虚拟机迁移到网络的任意位置,一般有两种方式。
方式一
代码语言:txt复制虚拟机迁移后,通过自动化网络管理平台动态的在虚拟机对应的所有端口上下发VLAN配置;
代码语言:txt复制同时,还需要动态删除迁移前虚拟机对应所有端口上的VLAN配置。这种方式的缺点是实现非常复杂,同时自动化管理平台对多厂商设备还面临兼容性的问 题,所以很难实现。
方式二
代码语言:txt复制在云计算网络上静态配置VLAN,在所有端口上配置VLAN trunk all。这种方式的优点是非常简单,是目前主流的应用方式。
代码语言:txt复制但这也带来了巨大的问题:任一VLAN内如果出现广播风暴,则全网所有VLAN内的虚拟机都会受到风暴影响,出现业务中断。
(3)VLAN上限问题
云计算网络中有可能出现多租户需求。如果租户及业务的数量规模超出VLAN的上限(4K),则无法支撑客户的需求。
(4)虚拟机迁移网络依赖问题
VM迁移需要在同一个二层域内,基于IP子网的区域划分限制了二层网络连通性的规模。
原文描述
OpenStack中的网络虚拟化
在OpenStack 是通过 Neutron 组件在物理网络环境之上提供满足多项目要求的虚拟网络和服务。
Neutron 提供的网络虚拟化能力包括:
(1)接收客户的操作请求
代码语言:txt复制在上一篇中,我们创建一个网络时,我们发过去的请求,是由Neutron-Server的API进行接受处理的
(2)租户(项目)隔离性
代码语言:txt复制在创建时,还可以选择一个对应项目,使它们同名不同项目间的网络互相不冲突
2.环境准备
添加用户
- 创建一个ctf1用户属于ctf项目
[root@controller /(keystone_admin)]# openstack user create ctf1 --project ctf --password 123456 --email ctf1@vip.com
--------------------- ----------------------------------
| Field | Value |
--------------------- ----------------------------------
| default_project_id | 2c9ab6ba08b94b0cab0cb4407a073bee |
| domain_id | default |
| email | ctf1@vip.com |
| enabled | True |
| id | a24342d7e2834d6ea54426690226c7de |
| name | ctf1 |
| options | {} |
| password_expires_at | None |
--------------------- ----------------------------------
- 添加一个角色
[root@controller /(keystone_admin)]# openstack role add --project ctf --user ctf1 _member_
创建云主机规格
代码语言:txt复制[root@controller /(keystone_admin)]# openstack flavor create --vcpus 1 --ram 218 --disk 5 web.ciross
上传镜像
- 先上传到/opt目录下
[root@controller opt(keystone_admin)]# ls -lh
总用量 13M
-rw-r--r-- 1 root root 13M 12月 18 20:17 cirros-0.3.4-x86_64-disk.img
drwxr-xr-x. 2 root root 6 6月 18 2018 rh
- 再上传到openstack中
[root@controller opt(keystone_admin)]# openstack image create ciross --public --disk-format qcow2 --file /opt/cirros-0.3.4-x86_64-disk.img
创建主机聚合
- 创建名称叫cputer的主机聚合,区域叫cpu
[root@controller /(keystone_admin)]# openstack aggregate create cputer --zone cpu
- 添加计算机点主机到聚合中
[root@controller /(keystone_admin)]#openstack aggregate add host cputer computer
3.Flat网络
需求:现在要在CTF项目中创建2个云主机一个在控制节点,一个在计算节点,网络类型为Flat网络,测试连通性
控制节点
先删除之前创建的ctf_net网络,配置flat网络
1.编辑neutron配置文件
代码语言:txt复制[root@controller /]# vim /etc/neutron/plugins/ml2/ml2_conf.ini
[ml2]
#网络驱动类型
type_drivers=flat,vlan,vxlan,gre,local
#这里写租户网络类型,可以写多种
tenant_network_types=flat
#neutron采用的虚拟交换机
mechanism_drivers=openvswitch
#上面写了flat,这里就要写flat对应的配置
[ml2_type_flat]
#flat物理网络类型,在创建的时候必须指定对应的这个名称
flat_networks=external
2.配置第二块网卡
代码语言:txt复制[root@controller network-scripts]# pwd
/etc/sysconfig/network-scripts
[root@controller network-scripts]# cat ifcfg-ens38
TYPE="Ethernet"
BOOTPROTO="none"
NAME="ens38"
DEVICE="ens38"
ONBOOT="yes"
[root@controller network-scripts]# ifup ens38
3.添加新OVS网桥
- 添加一个新的ovs网桥,并把第二块网卡桥接到上面去
[root@controller network-scripts]# ovs-vsctl add-br br-ens38
[root@controller network-scripts]# ovs-vsctl add-port br-ens38 ens38
- 编辑OVS代理文件
[ovs]
tenant_network_type=flat
bridge_mappings=external:br-ens38
integration_bridge=br-int
tunnel_bridge=br-tun
local_ip=192.168.150.10
- 重启服务
#生效的是ml2_conf.ini配置文件
[root@controller /]# systemctl restart neutron-server
#生效的是openvswitch_agent.ini配置文件
[root@controller /]# systemctl restart neutron-openvswitch-agent
4.创建Flat网络
注意:这个是以admi身份创建的flat类型网络
上面中的物理网络也就是刚刚写在ml2_conf.ini配置文件中的这一条
代码语言:txt复制#flat物理网络类型
flat_networks=external
这个代表什么意思?
这种网络称为Provider Network 是由 OpenStack 管理员创建的,直接对应于真实物理机中的已有物理网络的一个网段。
为什么要这个东西?
如果云主机要访问其他计算节点的主机,数据包就必须通过自身的物理网卡走出去,所以它的作用是当云主机要访问外部网络时,走哪个物理网卡
Provider Network有三个属性
- provider:physical_network (物理网络的逻辑名称,比如刚刚那个external)
- provider:network_type (网络类型,有vxlan, gre, vlan, flat, local,geneve)
- provider:segmentation_id (网段ID,比如VLAN号,GRE网络的 Tunnel ID,VXLAN 网络的 VNI)
建议使用命令来创建,WEB界面中创建时遇到到的问题报错信息不是很明显
上面的操作相当于命令
代码语言:txt复制[root@controller /(keystone_admin)]# openstack network create ctf_net --project ctf --provider-network-type flat --provider-physical-network external
指定子网
子网在openstack中它是一个ipv4或ipv6的一个地址池,它必须与一个网络相关联,可以给用户分配ip,指定网关、DNS。
分配一个地址池
现在已经创建成功
创建子网的操作相当于命令
代码语言:txt复制openstack subnet create ctf_subnet --project ctf --allocation-pool start=172.16.199.10,end=172.16.199.100 --subnet-range 172.16.199.0/24 --network ctf_net
5.创建一个云主机
- 复制原来的admin配置文件,修改成ctf1
[root@controller ~(keystone_netuser1)]# cat keystonerc_ctf1
unset OS_SERVICE_TOKEN
export OS_USERNAME=ctf1
export OS_PASSWORD='123456'
export OS_REGION_NAME=RegionOne
export OS_AUTH_URL=http://192.168.150.10:5000/v3
export PS1='[u@h W(keystone_ctf1)]$ '
export OS_PROJECT_NAME=ctf
export OS_USER_DOMAIN_NAME=Default
export OS_PROJECT_DOMAIN_NAME=Default
export OS_IDENTITY_API_VERSION=3
- 使用ciross镜像所在ctf_net网络(不是子网的id,是网络的id)上创建一个云主机
[root@controller ~(keystone_ctf1)]# openstack network list
[root@controller ml2(keystone_ctf1)]# openstack network list
-------------------------------------- --------- --------------------------------------
| ID | Name | Subnets |
-------------------------------------- --------- --------------------------------------
| 5892263b-fec8-4be0-ae86-f8e86ee5f311 | ctf_net | 6cb6193a-cb9c-47e3-99e5-d36a2747b0e2 |
-------------------------------------- --------- --------------------------------------
[root@controller ~(keystone_ctf1)]# openstack server create serverA --image ciross --flavor web.ciross --nic net-id=5892263b-fec8-4be0-ae86-f8e86ee5f311
6.查看网络信息
- 查看虚拟机的网卡信息
[root@controller ~]# virsh domiflist instance-00000003
接口 类型 源 型号 MAC
-------------------------------------------------------
tap9f9c98cb-13 bridge qbr9f9c98cb-13 virtio fa:16:3e:66:e4:5b
- 查看linux网格信息
[root@controller ~]# brctl show
bridge name bridge id STP enabled interfaces
qbr9f9c98cb-13 8000.aa908a6357a5 no qvb9f9c98cb-13
tap9f9c98cb-13
查看网络命名空间
代码语言:txt复制[root@controller ~]# ip netns show
qdhcp-5892263b-fec8-4be0-ae86-f8e86ee5f311 (id: 0)
查看网络命名空间的网卡信息
代码语言:txt复制[root@controller ~]# ip netns exec qdhcp-5892263b-fec8-4be0-ae86-f8e86ee5f311 ip add
36: tap91000a6c-33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default qlen 1000
link/ether fa:16:3e:c6:53:03 brd ff:ff:ff:ff:ff:ff
inet 172.16.199.10/24 brd 172.16.199.255 scope global tap91000a6c-33
valid_lft forever preferred_lft forever
inet6 fe80::f816:3eff:fec6:5303/64 scope link
valid_lft forever preferred_lft forever
查看OVS交换机的信息
代码语言:txt复制[root@controller opt(keystone_admin)]# ovs-vsctl show
Bridge br-int
Controller "tcp:127.0.0.1:6633"
is_connected: true
fail_mode: secure
#给子网分配dhcp的设备
Port "tap91000a6c-33"
tag: 3
Interface "tap91000a6c-33"
type: internal
#连接到ens38网卡的设备
Port "int-br-ens38"
Interface "int-br-ens38"
type: patch
options: {peer="phy-br-ens38"}
#linux虚拟交换机连接自己的设备
Port "qvo9f9c98cb-13"
tag: 3
Interface "qvo9f9c98cb-13"
Bridge "br-ens38"
Controller "tcp:127.0.0.1:6633"
is_connected: true
fail_mode: secure
#连接br-int的设备
Port "phy-br-ens38"
Interface "phy-br-ens38"
type: patch
options: {peer="int-br-ens38"}
Port "ens38"
Interface "ens38"
ovs_version: "2.11.0"
主机连接结构图
tap
代码语言:txt复制模拟一个二层的网络设备,可以接受和发送二层数据包
代码语言:txt复制它是ServerA虚拟机连接到linux虚拟网桥间的一个中间设备
qbr
代码语言:txt复制因为ovs没有数据包过滤的功能所以qbr的存在主要是为了辅助iptables来实现 security group功能,有时候也被称为安全网桥。
qvb
代码语言:txt复制neutron veth, Linux Bridge-side,它是linux虚拟网桥连接,OVS交换机的一个接口设备
qvo
代码语言:txt复制neutron veth, OVS-side,专门给inux虚拟网桥连接的一个接口设备
br-int
代码语言:txt复制它是计算节点中专门用来给虚拟机内部通信的一个交换机
namespace
代码语言:txt复制linux内核功能中用来实现隔离的一套机制,不同 namespace 中的资源之间彼此不可见。
代码语言:txt复制上面创建的一个子网就是在一个namespace中,可以用ip netns show 查看到
计算节点
1.添加第二块网卡
- 不需要设置ip地址,启用它就可以
[root@computer network-scripts]# cat ifcfg-ens38
TYPE="Ethernet"
BOOTPROTO="none"
NAME="ens38"
DEVICE="ens38"
ONBOOT="yes"
#启用网卡
[root@computer network-scripts]# ifup ens38
2.添加OVS网桥
- 添加一个新的ovs网桥,并把第二块网卡桥接到上面去
[root@computer /]# ovs-vsctl add-br br-ens38
[root@computer /]# ovs-vsctl add-port br-ens38 ens38
3.配置ovs代理文件
- 配置ovs代理文件添加映射
[root@computer ml2]# vim /etc/neutron/plugins/ml2/openvswitch_agent.ini
[ovs]
tenant_network_type=flat
bridge_mappings=external:br-ens38
4.重启服务
代码语言:txt复制[root@computer ml2]# systemctl restart neutron-openvswitch-agent.service
5.创建云主机
- 在计算节点上创建云主机
[root@controller /(keystone_netuser1)]# openstack server create ServerB --image ciross --flavor web.ciross --nic net-id=5892263b-fec8-4be0-ae86-f8e86ee5f311 --availability-zone cpu
连接性测试
如果发现云主机,dhcp获取半天,可以把接口
ServerA
- 网卡信息
$ sudo ifconfig eth0 172.16.199.60 netmask 255.255.255.0 up
$ ifconfig
eth0 Link encap:Ethernet HWaddr FA:16:3E:66:E4:5B
inet addr:172.16.199.60 Bcast:172.16.199.255 Mask:255.255.255.0
inet6 addr: fe80::f816:3eff:fe66:e45b/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:433 errors:0 dropped:0 overruns:0 frame:0
TX packets:127 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:56264 (54.9 KiB) TX bytes:11878 (11.5 KiB)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:16436 Metric:1
RX packets:12 errors:0 dropped:0 overruns:0 frame:0
TX packets:12 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:1020 (1020.0 B) TX bytes:1020 (1020.0 B)
- ping->ServerB
$ ping 172.16.199.70
PING 172.16.199.70 (172.16.199.70): 56 data bytes
64 bytes from 172.16.199.70: seq=0 ttl=64 time=11.517 ms
64 bytes from 172.16.199.70: seq=1 ttl=64 time=1.633 ms
64 bytes from 172.16.199.70: seq=2 ttl=64 time=1.387 ms
--- 172.16.199.70 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 1.387/4.845/11.517 ms
ServerB
- 网卡信息
$ sudo ifconfig eth0 172.16.199.70 netmask 255.255.255.0 up
$ ifconfig
eth0 Link encap:Ethernet HWaddr FA:16:3E:12:F3:D9
inet addr:172.16.199.70 Bcast:172.16.199.255 Mask:255.255.255.0
inet6 addr: fe80::f816:3eff:fe12:f3d9/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:24 errors:0 dropped:0 overruns:0 frame:0
TX packets:9 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:3368 (3.2 KiB) TX bytes:1750 (1.7 KiB)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:16436 Metric:1
RX packets:12 errors:0 dropped:0 overruns:0 frame:0
TX packets:12 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:1020 (1020.0 B) TX bytes:1020 (1020.0 B)
- ping->ServerA
$ ping 172.16.199.60
PING 172.16.199.60 (172.16.199.60): 56 data bytes
64 bytes from 172.16.199.60: seq=0 ttl=64 time=12.311 ms
64 bytes from 172.16.199.60: seq=1 ttl=64 time=2.079 ms
64 bytes from 172.16.199.60: seq=2 ttl=64 time=1.782 ms
--- 172.16.199.60 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 1.782/5.390/12.311 ms
流程分析
首先说说什么是flat网络
- flat网络叫扁平网络,独占一个物理网卡设备,一般用于网关出口
- flat网络里的所有主机都在同子网里,相比vlan没有任何的隔离
- 适用于小范围的网络结构
图示
ServerA要与ServerB能够相互通信,它的数据包就必须要走br-ens38,通过br-ens38到物理网卡ens38,再到对方的ens38物理网卡,逐层传递直到虚拟机。
为了简洁表示,上面省去了tab、qvb与qvo
引出-Neutron的架构
Plugin/Agent架构
Neutron-Server提供一个api接口负责接收其他组件发来的请求
Core Plugins主要负责二层交换
Service Plugins主要负责三层路由,二者大部分都是和数据库通讯
Plugins将和数据库通讯以后的数据做一层封装写入到缓存MQ队列
L2 agent负责二层交换的服务
L3 agent负责三层路由的服务
DHCP agent负责自动获取网络地址的服务
ML2
上面的网络是一个二层结构,没有通过路由器,在neutron中是由neutron-plugin里的l2来管理的
ml2插件是通过对接下面的驱动来实现各种网络虚拟化功能的
它的配置文件在/etc/neutron/plugins/ml2/ml2_conf.ini
DHCP agent
- Neutron是用开源软件dnsmasq来给云主机提供DHCP和DNS服务的
- 每个网络的DHCP运行在一个network namespace中,namespace由qdhcp-<DHCP-UUID>命名
- 这里它不存在DHCP中继的问题,因为它是每一个子网都有一个对应的DHCP进程
云主机通过DHCP获取地址的过程
1.nova-compute向Neutron Server 发送一个请求虚拟机IP地址的请求
2.Neutron Server为虚拟机创建MAC地址和IP地址,将此信息存储到数据库当中
3.Neutron Server同时将这个信息异步发送给DHCP agent
4.DHCP agent收到对应信息以后再发送给dnsmasq,后者将它保存起来
5.nova创建虚拟机以后会初始化MAC地址
6.当虚拟机启动的时候,默认的ip地址是0.0.0.0,会发送一个广播,dnsmasq会监听到虚拟机发送的报文,对应的将对应MAC地址的IP地址返回给虚拟机,这样虚拟机启动完成以后就会有IP地址
原文字描述
L3 agent
- L3 agent负责路由、浮动IP分配、地址转换和安全组管理
- 通过iptables实现安全组、路由以及地址转换
- 每个虚拟路由运行在一个network namespace中,每个namespace 由qroute-<router-UUID>命名
这里提前讲了L3 agent,下节讲vlan网络