--file filename.img导出虚拟机快照
125 | + 虚拟机快照导入
126 | 1. 通过glance image-create --file导入虚拟机快照
127 | [live snapshot]:http://docs.openstack.org/trunk/openstack-ops/content/snapshots.html
128 |
129 |
130 | ###虚拟机快照当前的BP
131 | - 包含内存、CPU状态等数据的快照。
132 | 该BP目前计划解决该问题(目前代码已经完成,在review中):
133 | https://blueprints.launchpad.net/nova/+spec/live-snapshot-vms
134 | 实现方式:
135 | 通过glance container来存储instance的root盘、内存快照、虚拟机xml信息等。
136 | 不足:
137 | 只提供基于image的虚拟机的live snapshot,而不提供基于volume的卷的live snapshot。
138 |
139 | - 虚拟机所有盘的快照。
140 | 该BP还在draft解决,完全没有开始:
141 | https://blueprints.launchpad.net/nova/+spec/instance-level-snapshots
142 |
143 | ###待完善
144 | + 快照树
145 | 目前虚拟机快照未保存快照链信息,只能知道时间先后顺序,无法知道快照关系。
146 | (因为是全量快照,暂时不需要。)
147 | + 导出包含metadata的image
148 | 便于后续重新导入image
149 | + 增量快照
150 | 虚拟机增量快照(与目前机制相差较大,影响大)
151 |
152 | ###其他
153 | openstack和版本对快照的思路略有不同。openstack因为存在镜像管理,所以虚拟机快照更多的是
154 | 通过镜像方式管理。而版本不存在镜像管理,更多的是通过存储来保存和使用镜像。
155 |
156 | ###BP列表
157 | + 在线虚拟机快照(包含内存、CPU状态) 开发中 Next
158 | https://blueprints.launchpad.net/nova/+spec/live-snapshot-vms
159 | + Live snapshot基础能力 完成
160 | https://blueprints.launchpad.net/nova/+spec/live-snapshots
161 | + libvirt无中断快照 完成
162 | https://blueprints.launchpad.net/nova/+spec/libvirt-live-snapshots
163 | + Qemu辅助卷快照(带内部VSS等?只支持一致性卷快照而非虚拟机) 完成
164 | https://blueprints.launchpad.net/nova/+spec/qemu-assisted-snapshots
165 | https://wiki.openstack.org/wiki/Cinder/GuestAssistedSnapshotting
166 | + Instacne全卷快照: draft阶段
167 | https://blueprints.launchpad.net/nova/+spec/instance-level-snapshots
168 | + Lined clone: draft阶段
169 | https://blueprints.launchpad.net/nova/+spec/linked-snapshot
170 | + 感觉像是利用linked clone快速clone虚拟机
171 | https://blueprints.launchpad.net/nova/+spec/nova-fast-snapshot
172 | + IBM一个哥们儿提的(关注)
173 | https://blueprints.launchpad.net/nova/+spec/driver-specific-snapshot
174 | + 带fsfreeze的快照实现 draft阶段
175 | https://blueprints.launchpad.net/nova/+spec/quiesced-image-snapshots-with-qemu-guest-agent
176 |
177 | + 关联的一个重要BP
178 | https://wiki.openstack.org/wiki/Raksha
179 |
180 | + 社区为什么不愿意加入vm snapshot功能
181 | http://blog.csdn.net/duan101101/article/details/19424479
182 |
183 | ###备注
184 | [1]: http://docs.openstack.org/user-guide/content/cli_manage_images.html#glance-image-list
185 | [2]: http://docs.openstack.org/trunk/openstack-ops/content/snapshots.html
186 | [3]: http://www.sebastien-han.fr/blog/2012/12/10/openstack-perform-consistent-snapshots/
187 | [4]: http://docs.openstack.org/image-guide/content/
188 |
189 | [底层原理过程]:http://kashyapc.com/tag/snapshots/
190 |
191 |
--------------------------------------------------------------------------------
/network.md:
--------------------------------------------------------------------------------
1 | 原文地址: https://blogs.oracle.com/ronen/entry/diving_into_openstack_network_architecture
2 | ### 前言
3 | openstack网络功能强大同时也相对更复杂。本系列文章通过Oracle OpenStack Tech
4 | Preview介绍openstack的配置,通过各种场景和例子说明openstack各种不同的网络组件。
5 | 本文的目的在于提供openstack网络架构的全景图并展示各个模块是如何一起协作的。这对openstack的初学者以及希望理解openstack网络原理的人会非常有帮助。
6 | 首先,我们先讲解下一些基础并举例说明。
7 |
8 | 根据最新的icehouse版用户调查,基于open vswitch插件的Neutron在生产环境和POC环境都被广泛使用,所以在这个系列的文章中我们主要分析这种openstack网络的配置。当然,我们知道openstack网络支持很多种配置,尽管neutron+open vswitch是最常用的配置,但是我们从未说它是最好或者最高效的一种方式。Neutron+open vswitch仅仅是一个例子,对任何希望理解openstack网络的人是一个很好的切入点。即使你打算使用其他类型的网络配置比如使用不同的neutron插件或者根本不使用neutron,这篇文章对你理解openstack网络仍是一个很好的开始。
9 |
10 | 我们在例子中使用的配置是Oracle OpenStack Tech Preview所提供的一种配置。安装它非常简单,并且它是一个很好的参考。在这种配置中,我们在所有服务器上使用eth2作为虚拟机的网络,所有虚拟机流量使用这个网卡。Oracle OpenStack Tech Preview使用VLAN进行L2隔离,进而提供租户和网络隔离,下图展示了我们如何进行配置和部署:
11 | 
12 |
13 | 第一篇文章会略长,我们将聚焦于openstack网络的一些基本概念。我们将讨论open vswitch、network namespaces、linux bridge、veth pairs等几个组件。注意这里不打算全面介绍这些组件,只是为了理解openstack网络架构。可以通过网络上的其他资源进一步了解这些组件。
14 |
15 | ### Open vSwitch (OVS)
16 | 在Oracle OpenStack Tech Preview中用于连接虚拟机和物理网口(如上例中的eth2),就像上边部署图所示。OVS包含bridages和ports,OVS bridges不同于与linux bridge(使用brctl命令创建)。让我们先看下OVS的结构,使用如下命令:
17 |
18 | # ovs-vsctl show
19 | 7ec51567-ab42-49e8-906d-b854309c9edf
20 | Bridge br-int
21 | Port br-int
22 | Interface br-int
23 | type: internal
24 | Port "int-br-eth2"
25 | Interface "int-br-eth2"
26 | Bridge "br-eth2"
27 | Port "br-eth2"
28 | Interface "br-eth2"
29 | type: internal
30 | Port "eth2"
31 | Interface "eth2"
32 | Port "phy-br-eth2"
33 | Interface "phy-br-eth2"
34 | ovs_version: "1.11.0"
35 |
36 | 我们看到标准的部署在compute node上的OVS,拥有两个网桥,每个有若干相关联的port。上边的例子是在一个没有任何虚拟机的计算节点上。我们可以看到eth2连接到个叫br-eth2的网桥上,我们还看到两个叫“int-br-eth2"和”phy-br-eth2“的port,事实上是一个veth pair,作为虚拟网线连接两个bridages。我们会在后边讨论veth paris。
37 |
38 | 当我们创建一个虚拟机,br-int网桥上会创建一个port,这个port最终连接到虚拟机(我们会在后边讨论这个连接)。这里是启动一个虚拟机后的OVS结构:
39 |
40 | # ovs-vsctl show
41 | efd98c87-dc62-422d-8f73-a68c2a14e73d
42 | Bridge br-int
43 | Port "int-br-eth2"
44 | Interface "int-br-eth2"
45 | Port br-int
46 | Interface br-int
47 | type: internal
48 | Port "qvocb64ea96-9f"
49 | tag: 1
50 | Interface "qvocb64ea96-9f"
51 | Bridge "br-eth2"
52 | Port "phy-br-eth2"
53 | Interface "phy-br-eth2"
54 | Port "br-eth2"
55 | Interface "br-eth2"
56 | type: internal
57 | Port "eth2"
58 | Interface "eth2"
59 | ovs_version: "1.11.0"
60 |
61 | ”br-int“网桥现在有了一个新的port"qvocb64ea96-9f" 连接VM,并且被标记为vlan1。虚拟机的每个网卡都需要对应在"br-int”网桥上创建一个port。
62 |
63 | OVS中另一个有用的命令是dump-flows,以下为例子:
64 |
65 | # ovs-ofctl dump-flows br-int
66 | NXST_FLOW reply (xid=0x4):
67 | cookie=0x0, duration=735.544s, table=0, n_packets=70, n_bytes=9976,idle_age=17, priority=3,in_port=1,dl_vlan=1000 actions=mod_vlan_vid:1,NORMAL
68 | cookie=0x0, duration=76679.786s, table=0, n_packets=0, n_bytes=0,idle_age=65534, hard_age=65534, priority=2,in_port=1 actions=drop
69 | cookie=0x0, duration=76681.36s, table=0, n_packets=68, n_bytes=7950,idle_age=17, hard_age=65534, priority=1 actions=NORMAL
70 |
71 | 如上所述,VM相连的port使用了Vlan tag 1。然后虚拟机网络(eth2)上的port使用tag1000。OVS会修改VM和物理网口间所有package的vlan。在openstack中,OVS
72 | agent 控制open vswitch中的flows,用户不需要进行操作。如果你想了解更多的如何控制open vswitch中的流,可以参考http://openvswitch.org中对ovs-ofctl的描述。
73 |
74 | ### Network Namespaces (netns)
75 | 网络namespace是linux上一个很cool的特性,它的用途很多。在openstack网络中被广泛使用。网络namespace是拥有独立的网络配置隔离容器,并且该网络不能被其他名字空间看到。网络名字空间可以被用于封装特殊的网络功能或者在对网络服务隔离的同时完成一个复杂的网络设置。在Oracle OpenStack Tech Preview中我们使用最新的R3企业版内核,该内核提供给了对netns的完整支持。
76 |
77 | 通过如下例子我们展示如何使用netns命令控制网络namespaces。
78 | 定义一个新的namespace:
79 |
80 | # ip netns add my-ns
81 | # ip netns list
82 | my-ns
83 |
84 | 我们说过namespace是一个隔离的容器,我们可以在namspace中进行各种操作,比如ifconfig命令。
85 |
86 | # ip netns exec my-ns ifconfig -a
87 | lo Link encap:Local Loopback
88 | LOOPBACK MTU:16436 Metric:1
89 | RX packets:0 errors:0 dropped:0 overruns:0 frame:0
90 | TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
91 | collisions:0 txqueuelen:0
92 | RX bytes:0 (0.0 b) TX bytes:0 (0.0 b)
93 |
94 | 我们可以在namespace中运行任何命令,比如对debug非常有用的tcddump命令,我们使用ping、ssh、iptables命令。
95 | 连接namespace和外部:
96 | 连接到namespace和namespace直接连接的方式有很多,我们主要聚集在openstack中使用的方法。openstack使用了OVS和网络namespace的组合。OVS定义接口,然后我们将这些接口加入namespace中。
97 |
98 | # ip netns exec my-ns ifconfig -a
99 | lo Link encap:Local Loopback
100 | LOOPBACK MTU:65536 Metric:1
101 | RX packets:0 errors:0 dropped:0 overruns:0 frame:0
102 | TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
103 | collisions:0 txqueuelen:0
104 | RX bytes:0 (0.0 b) TX bytes:0 (0.0 b)
105 |
106 | my-port Link encap:Ethernet HWaddr 22:04:45:E2:85:21
107 | BROADCAST MTU:1500 Metric:1
108 | RX packets:0 errors:0 dropped:0 overruns:0 frame:0
109 | TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
110 | collisions:0 txqueuelen:0
111 | RX bytes:0 (0.0 b) TX bytes:0 (0.0 b)
112 |
113 | 现在我们可以增加更多的ports到OVS bridge,并且连接到其他namespace或者其他设备比如物理网卡。Neutron使用网络namespace来实现网络服务,如DHCP、routing、gateway、firewall、load balance等。下一篇文章我们会讨论更多细节 。
114 |
115 | ### Linux bridge and veth pairs
116 | Linux bridge用于连接OVS port和虚拟机。ports负责连通OVS bridge和linux bridge或者两者与虚拟机。linux bridage主要用于安全组增强。安全组通过iptables实现,iptables只能用于linux bridage而非OVS bridage。
117 |
118 | Veth对在openstack网络中大量使用,也是debug网络问题的很好工具。Veth对是一个简单的虚拟网线,所以一般成对出现。通常Veth对的一端连接到bridge,另一端连接到另一个bridge或者留下在作为一个网口使用。
119 |
120 | 这个例子中,我们将创建一些veth对,把他们连接到bridge上并测试联通性。这个例子用于通常的Linux服务器而非openstack节点:
121 | 创建一个veth对,注意我们定义了两端的名字:
122 |
123 | # ip link add veth0 type veth peer name veth1
124 |
125 | # ifconfig -a
126 |
127 | .
128 |
129 | .
130 |
131 | veth0 Link encap:Ethernet HWaddr 5E:2C:E6:03:D0:17
132 |
133 | BROADCAST MULTICAST MTU:1500 Metric:1
134 |
135 | RX packets:0 errors:0 dropped:0 overruns:0 frame:0
136 |
137 | TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
138 |
139 | collisions:0 txqueuelen:1000
140 |
141 | RX bytes:0 (0.0 b) TX bytes:0 (0.0 b)
142 |
143 | veth1 Link encap:Ethernet HWaddr E6:B6:E2:6D:42:B8
144 |
145 | BROADCAST MULTICAST MTU:1500 Metric:1
146 |
147 | RX packets:0 errors:0 dropped:0 overruns:0 frame:0
148 |
149 | TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
150 |
151 | collisions:0 txqueuelen:1000
152 |
153 | RX bytes:0 (0.0 b) TX bytes:0 (0.0 b)
154 |
155 | .
156 |
157 | .
158 |
159 |
160 | 为了让例子更有意义,我们将创建如下配置:
161 |
162 | veth0 => veth1 =>br-eth3 => eth3 ======> eth2 on another Linux server
163 |
164 | br-eht3: 一个基本的Linux bridge,连接veth1和eth3
165 | eth3: 一个没有设定IP的物理网口,该网口连接着斯有网络
166 | eth2: 远端Linux服务器上的一个物理网口,连接着私有网络并且被配置了IP(50.50.50.1)
167 | 一旦我们创建了这个配置,我们将通过veth0 ping 50.50.50.1这个远端IP,从而测试网络联通性:
168 |
169 |
170 |
171 | # brctl addbr br-eth3
172 |
173 | # brctl addif br-eth3 eth3
174 |
175 | # brctl addif br-eth3 veth1
176 |
177 | # brctl show
178 |
179 | bridge name bridge id STP enabled interfaces
180 |
181 | br-eth3 8000.00505682e7f6 no eth3
182 |
183 | veth1
184 |
185 | # ifconfig veth0 50.50.50.50
186 |
187 | # ping -I veth0 50.50.50.51
188 |
189 | PING 50.50.50.51 (50.50.50.51) from 50.50.50.50 veth0: 56(84) bytes of data.
190 |
191 | 64 bytes from 50.50.50.51: icmp_seq=1 ttl=64 time=0.454 ms
192 |
193 | 64 bytes from 50.50.50.51: icmp_seq=2 ttl=64 time=0.298 ms
194 |
195 |
196 | 如果命名不像例子中这么显而易见,导致我们无法支持veth设备的两端,我们可以使用ethtool命令查询。ethtool命令返回index号,通过ip link命令查看对应的设备:
197 |
198 | # ethtool -S veth1
199 |
200 | NIC statistics:
201 |
202 | peer_ifindex: 12
203 |
204 | # ip link
205 |
206 | .
207 |
208 | .
209 |
210 | 12: veth0: mtu 1500 qdisc pfifo_fast state UP qlen 1000
211 |
212 |
213 | ### 总结
214 | 文章中,我们快速了解了OVS/网络namespaces/Linux bridges/veth对。这些组件在openstack网络架构中大量使用,理解这些组件有助于我们理解不同的网络场景。下篇文章中,我们会了解虚拟机之间/虚拟机与外部网络之间如何进行通信。
215 |
--------------------------------------------------------------------------------
/network3.md:
--------------------------------------------------------------------------------
1 | ### 深入理解openstack网络架构(3)-----路由
2 | 前文中,我们学习了openstack网络使用的几个基本网络组件,并通过一些简单的use case解释网络如何连通的。本文中,我们会通过一个稍微复杂(其实仍然相当基本)的use case(两个网络间路由)探索网络的设置。 路由使用的组件与连通内部网络相同,使用namespace创建一个隔离的container,允许subnet间的网络包中转。
3 | 记住我们在第一篇文章中所说的,这只是使用OVS插件的例子。openstack还有很多插件使用不同的方式,我们提到的只是其中一种。
4 |
5 | ### Use case #4: Routing traffic between two isolated networks
6 | 现实中,我们会创建不同的网络用于不同的目的。我们也会需要把这些网络连接起来。因为两个网络在不同的IP段,我们需要router将他们连接起来。为了分析这种设置,我们创建另一个network(net2)并配置一个20.20.20.0/24的subnet。在创建这个network后,我们启动一个Oracle Linux的虚拟机,并连接到net2。下图是从OpenstackGUI上看到的网络拓扑图:
7 | 
8 |
9 | 进一步探索,我们会在openstack网络节点上看到另一个namespace,这个namespace用于为新创建的网络提供服务。现在我们有两个namespace,每个network一个。
10 |
11 | # ip netns list
12 | qdhcp-63b7fcf2-e921-4011-8da9-5fc2444b42dd
13 | qdhcp-5f833617-6179-4797-b7c0-7d420d84040c
14 |
15 | 可以通过nova net-list查看network的ID信息,或者使用UI查看网络信息。
16 |
17 | # nova net-list
18 | +--------------------------------------+-------+------+
19 | | ID | Label | CIDR |
20 | +--------------------------------------+-------+------+
21 | | 5f833617-6179-4797-b7c0-7d420d84040c | net1 | None |
22 | | 63b7fcf2-e921-4011-8da9-5fc2444b42dd | net2 | None |
23 | +--------------------------------------+-------+------+
24 |
25 |
26 | 我们新创建的network,net2有自己的namespace,这个namespace与net1是分离的。在namespace中,我们可以看到两个网络接口,一个local,一个是用于DHCP服务。
27 |
28 |
29 | # ip netns exec qdhcp-63b7fcf2-e921-4011-8da9-5fc2444b42dd ip addr
30 | 1: lo: mtu 65536 qdisc noqueue state UNKNOWN
31 | link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
32 | inet 127.0.0.1/8 scope host lo
33 | inet6 ::1/128 scope host
34 | valid_lft forever preferred_lft forever
35 | 19: tap16630347-45: mtu 1500 qdisc noqueue state UNKNOWN
36 | link/ether fa:16:3e:bd:94:42 brd ff:ff:ff:ff:ff:ff
37 | inet 20.20.20.3/24 brd 20.20.20.255 scope global tap16630347-45
38 | inet6 fe80::f816:3eff:febd:9442/64 scope link
39 | valid_lft forever preferred_lft forever
40 |
41 |
42 | net1和net2两个network没有被联通,我们需要创建一个router,通过router将两个network联通。Openstack Neutron向用户提供了创建router并将两个或多个network连接的能力。router其实只是一个额外的namespace。
43 | 使用Neutron创建router可以通过GUI或者命令行操作:
44 |
45 | # neutron router-create my-router
46 | Created a new router:
47 | +-----------------------+--------------------------------------+
48 | | Field | Value |
49 | +-----------------------+--------------------------------------+
50 | | admin_state_up | True |
51 | | external_gateway_info | |
52 | | id | fce64ebe-47f0-4846-b3af-9cf764f1ff11 |
53 | | name | my-router |
54 | | status | ACTIVE |
55 | | tenant_id | 9796e5145ee546508939cd49ad59d51f |
56 | +-----------------------+--------------------------------------+
57 |
58 | 现在我们将两个netwrok通过router连接:
59 |
60 | 查看subnet的ID:
61 |
62 | # neutron subnet-list
63 | +--------------------------------------+------+---------------+------------------------------------------------+
64 | | id | name | cidr | allocation_pools |
65 | +--------------------------------------+------+---------------+------------------------------------------------+
66 | | 2d7a0a58-0674-439a-ad23-d6471aaae9bc | | 10.10.10.0/24 | {"start": "10.10.10.2", "end": "10.10.10.254"} |
67 | | 4a176b4e-a9b2-4bd8-a2e3-2dbe1aeaf890 | | 20.20.20.0/24 | {"start": "20.20.20.2", "end": "20.20.20.254"} |
68 | +--------------------------------------+------+---------------+------------------------------------------------+
69 |
70 | 将subnet 10.10.10.0/24添加到router:
71 |
72 | # neutron router-interface-add fce64ebe-47f0-4846-b3af-9cf764f1ff11 subnet=2d7a0a58-0674-439a-ad23-d6471aaae9bc
73 | Added interface 0b7b0b40-f952-41dd-ad74-2c15a063243a to router fce64ebe-47f0-4846-b3af-9cf764f1ff11.
74 |
75 | 将subnet 20.20.20.0/24添加到router:
76 |
77 |
78 | # neutron router-interface-add fce64ebe-47f0-4846-b3af-9cf764f1ff11 subnet=4a176b4e-a9b2-4bd8-a2e3-2dbe1aeaf890
79 | Added interface dc290da0-0aa4-4d96-9085-1f894cf5b160 to router fce64ebe-47f0-4846-b3af-9cf764f1ff11.
80 |
81 |
82 | 此时,我们在查看网络拓扑会发现两个网络被router打通:
83 | 
84 |
85 | 我们还可以发现两个网络接口连接到router,作为各自subnet的gateway。
86 |
87 | 我们可以看到为router创建的namespace。
88 |
89 | # ip netns list
90 | qrouter-fce64ebe-47f0-4846-b3af-9cf764f1ff11
91 | qdhcp-63b7fcf2-e921-4011-8da9-5fc2444b42dd
92 | qdhcp-5f833617-6179-4797-b7c0-7d420d84040c
93 |
94 | 我们进入namespace内部可以看到:
95 |
96 |
97 | # ip netns exec qrouter-fce64ebe-47f0-4846-b3af-9cf764f1ff11 ip addr
98 | 1: lo: mtu 65536 qdisc noqueue state UNKNOWN
99 | link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
100 | inet 127.0.0.1/8 scope host lo
101 | inet6 ::1/128 scope host
102 | valid_lft forever preferred_lft forever
103 | 20: qr-0b7b0b40-f9: mtu 1500 qdisc noqueue state UNKNOWN
104 | link/ether fa:16:3e:82:47:a6 brd ff:ff:ff:ff:ff:ff
105 | inet 10.10.10.1/24 brd 10.10.10.255 scope global qr-0b7b0b40-f9
106 | inet6 fe80::f816:3eff:fe82:47a6/64 scope link
107 | valid_lft forever preferred_lft forever
108 | 21: qr-dc290da0-0a: mtu 1500 qdisc noqueue state UNKNOWN
109 | link/ether fa:16:3e:c7:7c:9c brd ff:ff:ff:ff:ff:ff
110 | inet 20.20.20.1/24 brd 20.20.20.255 scope global qr-dc290da0-0a
111 | inet6 fe80::f816:3eff:fec7:7c9c/64 scope link
112 | valid_lft forever preferred_lft forever
113 |
114 | 我们看到两个网络接口,“qr-dc290da0-0a“ 和 “qr-0b7b0b40-f9。这两个网络接口连接到OVS上,使用两个network/subnet的gateway IP。
115 |
116 |
117 | # ovs-vsctl show
118 | 8a069c7c-ea05-4375-93e2-b9fc9e4b3ca1
119 | Bridge "br-eth2"
120 | Port "br-eth2"
121 | Interface "br-eth2"
122 | type: internal
123 | Port "eth2"
124 | Interface "eth2"
125 | Port "phy-br-eth2"
126 | Interface "phy-br-eth2"
127 | Bridge br-ex
128 | Port br-ex
129 | Interface br-ex
130 | type: internal
131 | Bridge br-int
132 | Port "int-br-eth2"
133 | Interface "int-br-eth2"
134 | Port "qr-dc290da0-0a"
135 | tag: 2
136 | Interface "qr-dc290da0-0a"
137 | type: internal
138 | Port "tap26c9b807-7c"
139 | tag: 1
140 | Interface "tap26c9b807-7c"
141 | type: internal
142 | Port br-int
143 | Interface br-int
144 | type: internal
145 | Port "tap16630347-45"
146 | tag: 2
147 | Interface "tap16630347-45"
148 | type: internal
149 | Port "qr-0b7b0b40-f9"
150 | tag: 1
151 | Interface "qr-0b7b0b40-f9"
152 | type: internal
153 | ovs_version: "1.11.0"
154 |
155 |
156 | 我们可以看到,这些接口连接到”br-int",并打上了所在network对应的VLAN标签。这里我们可以通过gateway地址(20.20.20.1)成功的ping通router namespace:
157 |
158 | 
159 |
160 | 我们还可以看到IP地址为20.20.20.2可以ping通IP地址为10.10.10.2的虚拟机:
161 |
162 | 
163 |
164 | 两个subnet通过namespace中的网络接口互相连通。在namespace中,Neutron将系统参数net.ipv4.ip_forward设置为1。
165 | 命令查看如下:
166 |
167 |
168 | # ip netns exec qrouter-fce64ebe-47f0-4846-b3af-9cf764f1ff11 sysctl net.ipv4.ip_forward
169 | net.ipv4.ip_forward = 1
170 |
171 | 我们可以看到namespace中的系统参数net.ipv4.ip_forward被设置,这种设置不会对namespace外产生影响。
172 |
173 | ### 总结
174 | 创建router时,Neutron会创建一个叫qrouter-的namespace。subnets通过OVS的br-int网桥上的网络接口接入router。
175 | 网络接口被设置了正确的VLAN,从而可以连入它们对应的network。例子中,网络接口qr-0b7b0b40-f9的IP被设置为10.10.10.1,VLAN标签为1,它可以连接到“net1”。通过在namespace中设置系统参数net.ipv4.ip_forward为1,从而允许路由生效。
176 |
177 | 本文介绍了如何使用network namespace创建一个router。下一篇文章中,我们会探索浮动IP如何使用iptables工作。这也许更复杂但是依然使用这些基本的网络组件。
178 |
--------------------------------------------------------------------------------
/trim.md:
--------------------------------------------------------------------------------
1 | diff --git a/nova/tests/virt/libvirt/test_config.py b/nova/tests/virt/libvirt/test_config.py
2 | index e0363ed..0fef2da 100644
3 | --- a/nova/tests/virt/libvirt/test_config.py
4 | +++ b/nova/tests/virt/libvirt/test_config.py
5 | @@ -463,6 +463,44 @@ class LibvirtConfigGuestDiskTest(LibvirtConfigBaseTest):
6 | self.assertEqual(obj.source_type, 'file')
7 | self.assertEqual(obj.serial, '7a97c4a3-6f59-41d4-bf47-191d7f97f8e9')
8 |
9 | + def test_config_file_discard(self):
10 | + obj = config.LibvirtConfigGuestDisk()
11 | + obj.driver_name = "qemu"
12 | + obj.driver_format = "qcow2"
13 | + obj.driver_cache = "none"
14 | + obj.driver_discard = "unmap"
15 | + obj.source_type = "file"
16 | + obj.source_path = "/tmp/hello.qcow2"
17 | + obj.target_dev = "/dev/hda"
18 | + obj.target_bus = "ide"
19 | + obj.serial = "7a97c4a3-6f59-41d4-bf47-191d7f97f8e9"
20 | +
21 | + xml = obj.to_xml()
22 | + self.assertXmlEqual(xml, """
23 | +
24 | +
25 | +
26 | +
27 | + 7a97c4a3-6f59-41d4-bf47-191d7f97f8e9
28 | + """)
29 | +
30 | + def test_config_file_discard_parse(self):
31 | + xml = """
32 | +
33 | +
34 | +
35 | +
36 | + 7a97c4a3-6f59-41d4-bf47-191d7f97f8e9
37 | + """
38 | + xmldoc = etree.fromstring(xml)
39 | +
40 | + obj = config.LibvirtConfigGuestDisk()
41 | + obj.parse_dom(xmldoc)
42 | +
43 | + self.assertEqual(obj.driver_discard, 'unmap')
44 | +
45 | + pass
46 | +
47 | def test_config_block(self):
48 | obj = config.LibvirtConfigGuestDisk()
49 | obj.source_type = "block"
50 | diff --git a/nova/tests/virt/libvirt/test_utils.py b/nova/tests/virt/libvirt/test_utils.py
51 | index 827b2cf..68dc495 100644
52 | --- a/nova/tests/virt/libvirt/test_utils.py
53 | +++ b/nova/tests/virt/libvirt/test_utils.py
54 | @@ -47,6 +47,11 @@ blah BLAH: bb
55 | disk_type = libvirt_utils.get_disk_type(path)
56 | self.assertEqual(disk_type, 'raw')
57 |
58 | + def test_get_hw_disk_discard(self):
59 | + self.assertEqual('unmap', libvirt_utils.get_hw_disk_discard("unmap"))
60 | + self.assertEqual('ignore', libvirt_utils.get_hw_disk_discard("ignore"))
61 | + self.assertIsNone(libvirt_utils.get_hw_disk_discard("fake"))
62 | +
63 | def test_list_rbd_volumes(self):
64 | conf = '/etc/ceph/fake_ceph.conf'
65 | pool = 'fake_pool'
66 | @@ -339,3 +344,5 @@ ID TAG VM SIZE DATE VM CLOCK
67 | self.assertEqual(67108864, image_info.virtual_size)
68 | self.assertEqual(98304, image_info.disk_size)
69 | self.assertEqual(3, len(image_info.snapshots))
70 | +
71 | +
72 | diff --git a/nova/virt/libvirt/config.py b/nova/virt/libvirt/config.py
73 | index 7ff03ff..0e3e54f 100644
74 | --- a/nova/virt/libvirt/config.py
75 | +++ b/nova/virt/libvirt/config.py
76 | @@ -481,6 +481,7 @@ class LibvirtConfigGuestDisk(LibvirtConfigGuestDevice):
77 | self.driver_name = None
78 | self.driver_format = None
79 | self.driver_cache = None
80 | + self.driver_discard = None
81 | self.source_path = None
82 | self.source_protocol = None
83 | self.source_name = None
84 | @@ -511,7 +512,8 @@ class LibvirtConfigGuestDisk(LibvirtConfigGuestDevice):
85 | dev.set("device", self.source_device)
86 | if (self.driver_name is not None or
87 | self.driver_format is not None or
88 | - self.driver_cache is not None):
89 | + self.driver_cache is not None or
90 | + self.driver_discard is not None):
91 | drv = etree.Element("driver")
92 | if self.driver_name is not None:
93 | drv.set("name", self.driver_name)
94 | @@ -519,6 +521,8 @@ class LibvirtConfigGuestDisk(LibvirtConfigGuestDevice):
95 | drv.set("type", self.driver_format)
96 | if self.driver_cache is not None:
97 | drv.set("cache", self.driver_cache)
98 | + if self.driver_discard is not None:
99 | + drv.set("discard", self.driver_discard)
100 | dev.append(drv)
101 |
102 | if self.source_type == "file":
103 | @@ -613,6 +617,7 @@ class LibvirtConfigGuestDisk(LibvirtConfigGuestDevice):
104 | self.driver_name = c.get('name')
105 | self.driver_format = c.get('type')
106 | self.driver_cache = c.get('cache')
107 | + self.driver_discard = c.get('discard')
108 | elif c.tag == 'source':
109 | if self.source_type == 'file':
110 | self.source_path = c.get('file')
111 | diff --git a/nova/virt/libvirt/imagebackend.py b/nova/virt/libvirt/imagebackend.py
112 | index 4caf9e0..3e16b98 100644
113 | --- a/nova/virt/libvirt/imagebackend.py
114 | +++ b/nova/virt/libvirt/imagebackend.py
115 | @@ -70,6 +70,11 @@ __imagebackend_opts = [
116 | cfg.StrOpt('images_rbd_ceph_conf',
117 | default='', # default determined by librados
118 | help='Path to the ceph configuration file to use'),
119 | + cfg.StrOpt('hw_disk_discard',
120 | + default=None,
121 | + help='Discard option for nova managed disks (valid options '
122 | + 'are: ignore, unmap). Need Libvirt(1.0.6) Qemu1.5 '
123 | + '(raw format) Qemu1.6(qcow2 format'),
124 | ]
125 |
126 | CONF = cfg.CONF
127 | @@ -80,6 +85,8 @@ CONF.import_opt('preallocate_images', 'nova.virt.driver')
128 | LOG = logging.getLogger(__name__)
129 |
130 |
131 | +
132 | +
133 | @six.add_metaclass(abc.ABCMeta)
134 | class Image(object):
135 |
136 | @@ -92,6 +99,8 @@ class Image(object):
137 | """
138 | self.source_type = source_type
139 | self.driver_format = driver_format
140 | + self.discard_mode = libvirt_utils.get_hw_disk_discard(
141 | + CONF.libvirt.hw_disk_discard)
142 | self.is_block_dev = is_block_dev
143 | self.preallocate = False
144 |
145 | @@ -134,6 +143,7 @@ class Image(object):
146 | info.target_bus = disk_bus
147 | info.target_dev = disk_dev
148 | info.driver_cache = cache_mode
149 | + info.driver_discard = self.discard_mode
150 | info.driver_format = self.driver_format
151 | driver_name = libvirt_utils.pick_disk_driver_name(hypervisor_version,
152 | self.is_block_dev)
153 | @@ -549,6 +559,8 @@ class Rbd(Image):
154 | ' images_rbd_pool'
155 | ' flag to use rbd images.'))
156 | self.pool = CONF.libvirt.images_rbd_pool
157 | + self.discard_mode = libvirt_utils.get_hw_disk_discard(
158 | + CONF.libvirt.hw_disk_discard)
159 | self.ceph_conf = ascii_str(CONF.libvirt.images_rbd_ceph_conf)
160 | self.rbd_user = ascii_str(CONF.libvirt.rbd_user)
161 | self.rbd = kwargs.get('rbd', rbd)
162 | @@ -622,6 +634,7 @@ class Rbd(Image):
163 | info.device_type = device_type
164 | info.driver_format = 'raw'
165 | info.driver_cache = cache_mode
166 | + info.driver_discard = self.discard_mode
167 | info.target_bus = disk_bus
168 | info.target_dev = disk_dev
169 | info.source_type = 'network'
170 | diff --git a/nova/virt/libvirt/utils.py b/nova/virt/libvirt/utils.py
171 | index af0cd40..02a5cba 100644
172 | --- a/nova/virt/libvirt/utils.py
173 | +++ b/nova/virt/libvirt/utils.py
174 | @@ -28,6 +28,7 @@ from oslo.config import cfg
175 | from nova.i18n import _
176 | from nova.i18n import _LI
177 | from nova.i18n import _LW
178 | +from nova.i18n import _LE
179 | from nova.openstack.common import log as logging
180 | from nova.openstack.common import processutils
181 | from nova import utils
182 | @@ -535,3 +536,13 @@ def is_mounted(mount_path, source=None):
183 | if exc.errno == errno.ENOENT:
184 | LOG.info(_LI("findmnt tool is not installed"))
185 | return False
186 | +
187 | +
188 | +def get_hw_disk_discard(hw_disk_discard):
189 | + """Check valid and get hw_disk_discard value from Conf.
190 | + """
191 | + if hw_disk_discard not in ('unmap', 'ignore'):
192 | + LOG.error(_LE("ignoring unrecognized hw_disk_discard='%s' value"),
193 | + hw_disk_discard)
194 | + return None
195 | + return hw_disk_discard
196 |
--------------------------------------------------------------------------------
/openstack/nfvi-realtime.md:
--------------------------------------------------------------------------------
1 | ### openstack特性之虚拟机实时性
2 | 虚拟机实时性特性是openstack M版本引入的。
3 | 虚拟机实时性特性,旨在改善提供低延迟的CPU调度能力。
4 |
5 | 实时性虚拟机主要用于跑需要对CPU执行延迟要求苛刻的负载。典型的如NFV场景的应用,也可以用于金融市场高频交易等场合。
6 |
7 | ### 原理
8 | 目前主要有以下手段改善实时性:
9 | + CPU pinning
10 | 防止虚拟机之间互相“steal time”,从而影响CPU调度延迟。
11 | + 主机资源
12 | 解决kernel task占用CPU,导致的CPU调度延迟。
13 | + QEMU Emulator thread pin
14 | 解决QEMU Emulator线程占用CPU,导致的CPU调度延迟。
15 | + Guest VCPU调度策略
16 | 给guest vCPUs配置合适的调度策略,解决调度导致的CPU延迟。
17 | + 使用大页
18 | 确保Guest内存不会被swap到host上。
19 | + 防止QEMU内存swap
20 | 配置QEMU内存不被swap,避免内存swap导致的延迟。
21 |
22 | ### 使用注意
23 | 实时性是存在代价的。为了在最坏情况下,满足对CPU延迟的苛刻要求,整个系统的吞吐能力都要做妥协。
24 | 因此,无条件使用实时性,并不合理。只有在业务负载真的需要时,才开启这个选项。
25 | 很多情况下,仅仅使用CPU pinning就可以满足业务的对实时性的 要求。
26 |
27 | 根据社区的测试效果:
28 | + baremetal + dedicated cpu + non-realtime scheduler
29 | worst case latency:150微秒,mean latency:2微秒
30 | + KVM + dedicated cpu + realtime scheduler
31 | worst case latency:14微秒, mean latency:<10微秒
32 |
33 | ### 使用方法
34 | 为了达到最优的效果,需要配合使用之前的numa亲和特性、dedicated cpu pinning特性、huge page特性。
35 | 由于开启实时是有代价的,一般来说,需要通过host aggregate将支持实时和不支持实时的computes host分开。
36 |
37 | + flavor中增加“hw:cpu_realtime=yes|no"开启实时策略
38 | + 前提是配置了”hw:cpu_policy"为"dedicated"。
39 | + kvm主要做了配置:1. QEMU和guest RAM lock 2. 所有的vCPUs使用固定的实时调度策略。
40 | + flavor中增加hw:cpu_realtime_mask=^0-1参数控制emulator使用的cpu
41 | + 这个必须配置的。
42 | + 将某些vCPUs分配给emulator使用,且使用非实时调度策略。其他的vCPU会使用实时调度策略。(默认虚拟机会使用所有vCPU给emulator用)。
43 | + 更进一步的在主机上固定一些pCPU供emulator使用,在P版本才完成(没仔细看,不确定做了什么事)[URL](https://blueprints.launchpad.net/nova/+spec/libvirt-emulator-threads-policy)。
44 |
45 | ### 例子
46 |
47 | ```shell
48 | # 如果不配置cpu绑定会出现以下错误。
49 | [stack@localhost devstack]$ openstack server create --flavor realtime --image cirros-0.3.4-x86_64-uec realtime
50 | Cannot set realtime policy in a non dedicated cpu pinning policy (HTTP 400) (Request-ID: req-95b9c93c-cbac-4f1b-bf37-4942afa53860)
51 |
52 | # 如果不配置配置cpu mask会出现以下错误
53 | [stack@localhost devstack]$ openstack server create --flavor realtime --image cirros-0.3.4-x86_64-uec realtime
54 | Realtime policy needs vCPU(s) mask configured with at least 1 RT vCPU and 1 ordinary vCPU. See hw:cpu_realtime_mask or hw_cpu_realtime_mask (HTTP 400) (Request-ID: req-0f09c25a-9f56-4baf-9519-71d5b3abae29)
55 |
56 | openstack flavor create --ram 1024 --vcpu 4 --disk 1 realtime4
57 | openstack flavor set --property hw:cpu_realtime=yes realtime4
58 | openstack flavor set --property hw:cpu_policy=dedicated realtime4
59 | openstack flavor set --property hw:cpu_realtime_mask=^0-1 realtime4
60 | openstack server create --flavor realtime4 --image cirros-0.3.4-x86_64-uec realtime4
61 |
62 |
63 | [stack@localhost devstack]$ sudo virsh list
64 | Id Name State
65 | ----------------------------------------------------
66 | 3 instance-00000003 running
67 |
68 | [stack@localhost devstack]$ sudo virsh show 3
69 | error: unknown command: 'show'
70 | [stack@localhost devstack]$ sudo virsh dumpxml 3
71 |
72 | instance-00000003
73 | bcd4164b-f0da-4f70-8864-6514ff5c1c54
74 |
75 |
76 |
77 | realtime4
78 | 2017-05-05 09:14:48
79 |
80 | 1024
81 | 1
82 | 0
83 | 0
84 | 4
85 |
86 |
87 | admin
88 | admin
89 |
90 |
91 |
92 |
93 | 1048576
94 | 1048576
95 |
96 |
97 |
98 |
99 | 4
100 |
101 | 4096
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 | /machine
115 |
116 |
117 |
118 | OpenStack Foundation
119 | OpenStack Nova
120 | 15.0.4
121 | 187ec700-6ff3-4e83-87b2-9559c4406874
122 | bcd4164b-f0da-4f70-8864-6514ff5c1c54
123 | Virtual Machine
124 |
125 |
126 |
127 | hvm
128 | /opt/stack/data/nova/instances/bcd4164b-f0da-4f70-8864-6514ff5c1c54/kernel
129 | /opt/stack/data/nova/instances/bcd4164b-f0da-4f70-8864-6514ff5c1c54/ramdisk
130 | root=/dev/vda console=tty0 console=ttyS0
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 | |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 | destroy
150 | restart
151 | destroy
152 |
153 | /usr/bin/qemu-kvm
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 | system_u:object_r:svirt_image_t:s0:c687,c779
216 |
217 |
218 |
219 | +107:+107
220 |
221 |
222 | ```
223 |
224 | ### 参考
225 | 1. https://specs.openstack.org/openstack/nova-specs/specs/mitaka/implemented/libvirt-real-time.html
226 | 2. https://review.openstack.org/#/c/225893/3/specs/mitaka/approved/libvirt-emulator-threads-policy.rst
227 | 3. https://blueprints.launchpad.net/nova/+spec/libvirt-emulator-threads-policy
228 |
--------------------------------------------------------------------------------
/network4.md:
--------------------------------------------------------------------------------
1 | ### 深入理解openstack网络架构(4)-----连接到public network
2 | 在上一篇文章中,我们介绍了openstack中的路由,了解到openstack如何通过namespace实现的router将两个network连通。本文中,我们进一步分析路由功能,说明实现内部internal network和public network的路由(而不仅仅是internal network之间)。
3 | 我们还会分析neutron如何将浮动IP配置给虚拟机,从而实现public network与虚拟机的连通。
4 |
5 | ### Use case #5: Connecting VMs to the public network
6 | 所谓“public network”,指openstack部署环境以外的网络。这个网络可以是datacenter中的另一个网络、internet、或者一个不被openstack控制的私有网络。
7 |
8 | 与public network通信,我们需要在openstack中创建一个network并设置为public。这个network用于虚拟机与public network通信。虚拟机不能直接连接到这个新创建的属性为public的network,所有网络流量必须使用openstack创建的router从private network路由到public network。在openstack中创建public network,我们只需要使用neutron net-create 命令,并将router:external设置为True。
9 | 在我们的例子中,public newtork叫做“my-public”。
10 |
11 | # neutron net-create my-public --router:external=True
12 | Created a new network:
13 | +---------------------------+--------------------------------------+
14 | | Field | Value |
15 | +---------------------------+--------------------------------------+
16 | | admin_state_up | True |
17 | | id | 5eb99ac3-905b-4f0e-9c0f-708ce1fd2303 |
18 | | name | my-public |
19 | | provider:network_type | vlan |
20 | | provider:physical_network | default |
21 | | provider:segmentation_id | 1002 |
22 | | router:external | True |
23 | | shared | False |
24 | | status | ACTIVE |
25 | | subnets | |
26 | | tenant_id | 9796e5145ee546508939cd49ad59d51f |
27 | +---------------------------+--------------------------------------+
28 |
29 |
30 | 在我们的环境中,控制节点的eth3是一个没有绑定IP的网卡。我们使用它接入外部public network。因此我们将eth3加入OVS网桥"br-ex",Neutron会将虚拟机向外部网络的发送的网络包路由到这个bridge。
31 |
32 |
33 | # ovs-vsctl add-port br-ex eth3
34 | # ovs-vsctl show
35 | 8a069c7c-ea05-4375-93e2-b9fc9e4b3ca1
36 | .
37 | .
38 | .
39 | Bridge br-ex
40 | Port br-ex
41 | Interface br-ex
42 | type: internal
43 | Port "eth3"
44 | Interface "eth3"
45 | .
46 | .
47 | .
48 |
49 |
50 | 我们在eth3上创建了一个IP范围是180.180.180.0/24的public network。这个public network存在于datacenter中,通过gateway 180.180.180.1可以连接到datacenter网络。为了将这个网络与Openstack环境相连,我们需要在“my-public"这个network,上创建一个有相同IP范围的subnet,并告诉neutron这个network的gateway。
51 |
52 |
53 | # neutron subnet-create my-public 180.180.180.0/24 --name public_subnet --enable_dhcp=False --allocation-pool start=180.180.180.2,end=180.180.180.100 --gateway=180.180.180.1
54 | Created a new subnet:
55 | +------------------+------------------------------------------------------+
56 | | Field | Value |
57 | +------------------+------------------------------------------------------+
58 | | allocation_pools | {"start": "180.180.180.2", "end": "180.180.180.100"} |
59 | | cidr | 180.180.180.0/24 |
60 | | dns_nameservers | |
61 | | enable_dhcp | False |
62 | | gateway_ip | 180.180.180.1 |
63 | | host_routes | |
64 | | id | ecadf103-0b3b-46e8-8492-4c5f4b3ea4cd |
65 | | ip_version | 4 |
66 | | name | public_subnet |
67 | | network_id | 5eb99ac3-905b-4f0e-9c0f-708ce1fd2303 |
68 | | tenant_id | 9796e5145ee546508939cd49ad59d51f |
69 | +------------------+------------------------------------------------------+
70 |
71 |
72 | 然后,我们需要将router接入我们新创建的public network,使用下列命令创建:
73 |
74 |
75 | # neutron router-gateway-set my-router my-public
76 | Set gateway for router my-router
77 |
78 |
79 | 注意:我们在两种情况下使用术语“public network",一个是datacenter中真实的public network,为了区分我们把它(180.180.180.0/24)叫做"external public network"。另一个是openstack中我们使用的"public network",我们称之为“my-public"的接口网络。
80 | 我们还涉及两个”gateways“,一个是外部Public network用的gateway(180.180.180.1),另一个是router中的gateway接口(180.180.180.2)。
81 |
82 | 执行上述的操作后,router上(之前已经拥有两个网络接口,连接两个不同的internal network)增加了第三个网络接口(被称作gateway)。router可以有多个网络接口,连接普通的internal subnet或者作为gateway连入“my-public"网络。一个经常犯的错误是,试图以通常网络接口的方式接入public network,操作可能成功,但是却并不能与外部网络连通。
83 | 在我们创建一个public network,subnet并接入router,网络拓扑看起来是这样的:
84 |
85 | 
86 |
87 | 进入router的namespace中,我们看到其中增加了一个180.180.180.0/24网段IP的网络接口,IP为180.180.180.2:
88 |
89 |
90 | # ip netns exec qrouter-fce64ebe-47f0-4846-b3af-9cf764f1ff11 ip addr
91 | .
92 | .
93 | 22: qg-c08b8179-3b: mtu 1500 qdisc noqueue state UNKNOWN
94 | link/ether fa:16:3e:a4:58:40 brd ff:ff:ff:ff:ff:ff
95 | inet 180.180.180.2/24 brd 180.180.180.255 scope global qg-c08b8179-3b
96 | inet6 2606:b400:400:3441:f816:3eff:fea4:5840/64 scope global dynamic
97 | valid_lft 2591998sec preferred_lft 604798sec
98 | inet6 fe80::f816:3eff:fea4:5840/64 scope link
99 | valid_lft forever preferred_lft forever
100 | .
101 | .
102 |
103 | 在这里router的gateway地址180.180.180.2与虚拟机是联通的,虚拟机可以ping到它。我们也能从虚拟机ping到外部网络的gateway180.180.180.1以及这个gateway所连的网络。
104 | 如果我们查看router namespace,发现iptables的NAT talbe中有以下两行规则。
105 |
106 |
107 | # ip netns exec qrouter-fce64ebe-47f0-4846-b3af-9cf764f1ff11 iptables-save
108 | .
109 | .
110 | -A neutron-l3-agent-snat -s 20.20.20.0/24 -j SNAT --to-source 180.180.180.2
111 | -A neutron-l3-agent-snat -s 10.10.10.0/24 -j SNAT --to-source 180.180.180.2
112 |
113 | .
114 | .
115 |
116 |
117 | 因此,从net1或net2向外网发出的网络包,其源IP地址会被修改为180.180.180.2。我们可以在虚拟机中ping外网的某个地址,看下请求包的IP地址是否是这个IP地址。
118 |
119 | namespace中的路由表会把所有外部流量路由到外网的gateway(180.180.180.1)。
120 |
121 |
122 | # ip netns exec qrouter-fce64ebe-47f0-4846-b3af-9cf764f1ff11 route -n
123 | Kernel IP routing table
124 | Destination Gateway Genmask Flags Metric Ref Use Iface
125 | 0.0.0.0 180.180.180.1 0.0.0.0 UG 0 0 0 qg-c08b8179-3b
126 | 10.10.10.0 0.0.0.0 255.255.255.0 U 0 0 0 qr-15ea2dd1-65
127 | 20.20.20.0 0.0.0.0 255.255.255.0 U 0 0 0 qr-dc290da0-0a
128 | 180.180.180.0 0.0.0.0 255.255.255.0 U 0 0 0 qg-c08b8179-3b
129 |
130 |
131 | 虚拟机中发出的流向public network的请求,会被NAT映射为源地址为180.180.180.2,然后发给public network的gateway。同样,我们可以看到在namespace中ip forward功能是启动的。
132 |
133 |
134 | # ip netns exec qrouter-fce64ebe-47f0-4846-b3af-9cf764f1ff11 sysctl net.ipv4.ip_forward
135 | net.ipv4.ip_forward = 1
136 |
137 |
138 | ### Use case #6: Attaching a floating IP to a VM
139 |
140 | 现在,虚拟机可以访问public network。下一步,我们尝试允许外部客户访问Openstack环境中的虚拟机,通过floating IP可以完成这个功能。 Floating IP由外部网络提供,用户可以将它设置给虚拟机,从而允许外部客户接入虚拟机。
141 |
142 | 创建Floating IP,第一步是按照上一个usecase的讲解,将虚拟机连入外部网络。第二步时使用命令行,产生一个浮动IP。
143 |
144 |
145 | # neutron floatingip-create public
146 | Created a new floatingip:
147 | +---------------------+--------------------------------------+
148 | | Field | Value |
149 | +---------------------+--------------------------------------+
150 | | fixed_ip_address | |
151 | | floating_ip_address | 180.180.180.3 |
152 | | floating_network_id | 5eb99ac3-905b-4f0e-9c0f-708ce1fd2303 |
153 | | id | 25facce9-c840-4607-83f5-d477eaceba61 |
154 | | port_id | |
155 | | router_id | |
156 | | tenant_id | 9796e5145ee546508939cd49ad59d51f |
157 | +---------------------+--------------------------------------+
158 |
159 |
160 | 根据"my-public" network的能力,用户可以创建很多这样的IP。将浮动IP与虚拟机关联,可以通过命令行或者GUI完成。
161 | 下图是GUI的例子:
162 |
163 | 
164 |
165 | 在router namespace中我们可以看到,新增加了3跳iptabales规则:
166 |
167 |
168 | -A neutron-l3-agent-OUTPUT -d 180.180.180.3/32 -j DNAT --to-destination 20.20.20.2
169 | -A neutron-l3-agent-PREROUTING -d 180.180.180.3/32 -j DNAT --to-destination 20.20.20.2
170 | -A neutron-l3-agent-float-snat -s 20.20.20.2/32 -j SNAT --to-source 180.180.180.3
171 |
172 |
173 | 这些规则主要是对Floating IP进行NAT操作。对于router收到的目的地址为180.180.180.3的请求,会被转换成目标地址为20.20.20.2。反之亦然。
174 |
175 | 绑定Floating IP后,我们可以连接到虚拟机。需要确认安全组规则已经被设置,从而允许这样连接:
176 |
177 |
178 | nova secgroup-add-rule default icmp -1 -1 0.0.0.0/0
179 | nova secgroup-add-rule default tcp 22 22 0.0.0.0/0
180 |
181 |
182 | 这两条规则,允许ping和ssh。
183 |
184 | Iptables是一个复杂而强大的工具。如果想更好的理解iptables规则,可以查看iptables的帮助文件。
185 |
186 | ### Summary
187 |
188 | 本文介绍了如何将openstack环境中的虚拟机与public network连通。通过namespace和routing table,虚拟机不仅能在openstack环境内的不同网络间实现消息路由,还能与外部网络连通。
189 |
190 | 本文是这个系列文章的最后一篇。网络是opesntack最复杂的部分,是理解openstack的一个关键。阅读这四篇文章,对理解和分析openstack各种网络拓扑是很好的入门。使用我们提到的这些内容,可以更好的理解诸如Firewall as a service、Load Balance as a service、Metadata service这些网络概念。基本的学习方式是,进入namespace中,看究竟是如何利用Linux网络能力实现这些功能的。
191 |
192 | 我们在最开始说过,这些use case中我们只是使用了openstack众多网络配置方法的一种。我们的例子都是用了open vswitch 插件,可以独立于网络设备使用。通过与这里的例子对比,有助于分析其他的插件和功能。很多情况下,商业插件会使用open vswitch/bridges/namespace以及一些类似的方法和原理。
193 |
194 | 本系列文章的目的,在于让大多数用户了解oepnstack网络。文章中自下而上,使用一下简单的usecase,试着分析了openstack network 的整个结构以及如何工作的。与网上的其他一些资料不同,我们没有介绍各种openstack网络agent以及他们的功能,而是讲了他们做什么以及如何做的。下一步,你可以查阅这些资料,试着了解不同的agents是如何实现这些功能的。
195 |
196 | 全文结束。
197 |
--------------------------------------------------------------------------------
/network2.md:
--------------------------------------------------------------------------------
1 | ### 深入理解openstack网络架构(2)----Basic Use Cases
2 |
3 | 在上一篇文章中,我们了解了几个网络组件,如openvswitch/network namespace/Linux bridges/veth pairs。这篇文章中,我们将用3个简单的use case,展示这些基本网络组件如何以工作从而实现openstack的SDN方案。
4 | 在这些use case中,我们会了解整个网络配置和他们如何一起运行。use case如下:
5 |
6 | 1. 创建网络——我们创建网络时,发生了什么。如何创建多个隔离的网络。
7 | 2. 创建虚拟机——一旦我们有了网络,我们可以创建虚拟机并将其接入网络。
8 | 3. 虚拟机的DHCP请求——opensack可以自动为虚拟机配置IP。通过openstack neutron控制的DHCP服务完成。我们来了解这个服务如何运行,DHCP请求和回应是什么样子的?
9 |
10 | 这篇文章中,我们会展示网络连接的原理,我们会了解网络包如何从A到B。我们先了解已经完成的网络配置是什么样子的?然后我们讨论这些网络配置是如何以及何时创建的?我个人认为,通过例子和具体实践看到真实的网络接口如何工作以及如何将他们连接起来是非常有价值的。然后,一切真相大白,我们知道网络连接如何工作,在后边的文章中,我将进一步解释neutron如何配置这些组件,从而提供这样的网络连接能力。
11 |
12 | 我推荐在你自己的环境上尝试这些例子或者使用Oracle Openstack Tech Preview。完全理解这些网络场景,对我们调查openstack环境中的网络问题非常有帮助。
13 |
14 | ### Use case #1: Create Network
15 | 创建network的操作非常简单。我们可以使用GUI或者命令行完成。openstack的网络仅供创建该网络的租户使用。当然如果这个网络是“shared”,它也可以被其他所有租户使用。一个网络可以有多个subnets,但是为了演示目的和简单,我们仅为每一个network创建一个subnet。
16 | 通过命令行创建network:
17 |
18 | # neutron net-create net1
19 |
20 | Created a new network:
21 |
22 | +---------------------------+--------------------------------------+
23 |
24 | | Field | Value |
25 |
26 | +---------------------------+--------------------------------------+
27 |
28 | | admin_state_up | True |
29 |
30 | | id | 5f833617-6179-4797-b7c0-7d420d84040c |
31 |
32 | | name | net1 |
33 |
34 | | provider:network_type | vlan |
35 |
36 | | provider:physical_network | default |
37 |
38 | | provider:segmentation_id | 1000 |
39 |
40 | | shared | False |
41 |
42 | | status | ACTIVE |
43 |
44 | | subnets | |
45 |
46 | | tenant_id | 9796e5145ee546508939cd49ad59d51f |
47 |
48 | +---------------------------+--------------------------------------+
49 |
50 | 为这个network创建subnet:
51 |
52 | # neutron subnet-create net1 10.10.10.0/24
53 |
54 | Created a new subnet:
55 |
56 | +------------------+------------------------------------------------+
57 |
58 | | Field | Value |
59 |
60 | +------------------+------------------------------------------------+
61 |
62 | | allocation_pools | {"start": "10.10.10.2", "end": "10.10.10.254"} |
63 |
64 | | cidr | 10.10.10.0/24 |
65 |
66 | | dns_nameservers | |
67 |
68 | | enable_dhcp | True |
69 |
70 | | gateway_ip | 10.10.10.1 |
71 |
72 | | host_routes | |
73 |
74 | | id | 2d7a0a58-0674-439a-ad23-d6471aaae9bc |
75 |
76 | | ip_version | 4 |
77 |
78 | | name | |
79 |
80 | | network_id | 5f833617-6179-4797-b7c0-7d420d84040c |
81 |
82 | | tenant_id | 9796e5145ee546508939cd49ad59d51f |
83 |
84 | +------------------+------------------------------------------------+
85 |
86 |
87 | 现在我们有了一个network和subnet,网络拓扑像这样:
88 | 
89 |
90 | 现在让我们深入看下到底发生了什么?在控制节点,我们一个新的namespace被创建:
91 |
92 | # ip netns list
93 |
94 | qdhcp-5f833617-6179-4797-b7c0-7d420d84040c
95 |
96 |
97 | 这个namespace的名字是qdhcp- (参见上边),让我们深入namespace中看看有什么?
98 |
99 | # ip netns exec qdhcp-5f833617-6179-4797-b7c0-7d420d84040c ip addr
100 |
101 | 1: lo: mtu 65536 qdisc noqueue state UNKNOWN
102 |
103 | link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
104 |
105 | inet 127.0.0.1/8 scope host lo
106 |
107 | inet6 ::1/128 scope host
108 |
109 | valid_lft forever preferred_lft forever
110 |
111 | 12: tap26c9b807-7c: mtu 1500 qdisc noqueue state UNKNOWN
112 |
113 | link/ether fa:16:3e:1d:5c:81 brd ff:ff:ff:ff:ff:ff
114 |
115 | inet 10.10.10.3/24 brd 10.10.10.255 scope global tap26c9b807-7c
116 |
117 | inet6 fe80::f816:3eff:fe1d:5c81/64 scope link
118 |
119 | valid_lft forever preferred_lft forever
120 |
121 | 我们发下在namespace下有两个网络接口,一个是loop设备,另一个叫“tap26c9b807-7c”。这个接口设置了IP地址10.10.10.3,他会接收dhcp请求(后边会讲)。接下来我们来跟踪下“tap26c9b807-7c”的网络连接性。我们从OVS上看下这个接口所连接的OVS网桥"br-int"。
122 |
123 | # ovs-vsctl show
124 | 8a069c7c-ea05-4375-93e2-b9fc9e4b3ca1
125 | Bridge "br-eth2"
126 | Port "br-eth2"
127 | Interface "br-eth2"
128 | type: internal
129 | Port "eth2"
130 | Interface "eth2"
131 | Port "phy-br-eth2"
132 | Interface "phy-br-eth2"
133 | Bridge br-ex
134 | Port br-ex
135 | Interface br-ex
136 | type: internal
137 | Bridge br-int
138 | Port "int-br-eth2"
139 | Interface "int-br-eth2"
140 | Port "tap26c9b807-7c"
141 | tag: 1
142 | Interface "tap26c9b807-7c"
143 | type: internal
144 | Port br-int
145 | Interface br-int
146 | type: internal
147 | ovs_version: "1.11.0"
148 |
149 | 由上可知,veth pair的两端“int-br-eth2” 和 "phy-br-eth2",这个veth pari连接两个OVS网桥"br-eth2"和"br-int"。上一篇文章中,我们解释过如何通过ethtool命令查看veth pairs的两端。就如下边的例子:
150 |
151 | # ethtool -S int-br-eth2
152 | NIC statistics:
153 | peer_ifindex: 10
154 | .
155 | .
156 |
157 | #ip link
158 | .
159 | .
160 | 10: phy-br-eth2: mtu 1500 qdisc pfifo_fast state UP qlen 1000
161 | .
162 | .
163 |
164 | 注意“phy-br-eth2”连接到网桥"br-eth2",这个网桥的一个网口是物理网卡eth2。这意味着我们创建的网络创建了一个连接到了物理网卡eth2的namespace。eth2所在的虚拟机网络会连接所有的虚拟机的。
165 |
166 | ##### 关于网络隔离:
167 | Openstack支持创建多个隔离的网络,也可以使用多种机制完成网络间的彼此隔离。这些隔离机制包括VLANs/VxLANs/GRE tunnels,这个在我们部署openstack环境时配置。本文中我们选择了VLANs。当使用VLAN标签作为隔离机制,Neutron会从预定义好的VLAN池中选择一个VLAN标签,并分配给一个新创建的network。通过分配VLAN标签给network,Neutron允许在一个物理网卡上创建多个隔离的网络。与其他的平台的最大的区别是,用户不需要负责管理VLAN如何分配给networks。Neutron会负责管理分配VLAN标签,并负责回收。在我们的例子中,net1使用VLAN标签1000,这意味着连接到该网络的虚拟机,发出的包会被打上VLAN标签1000然后发送到物理网络中。对namespace也是同样的,如果我们希望namespace连接到某个特定网络,我们需要确保这个namespace发出的/接收的包被正确的打上了标签。
168 |
169 | 在上边的例子中,namespace中的网络接口“tap26c9b807-7c”被分配了VLAN标签1。如果我们从OVS观察下,会发现VLAN1会被改为VLAN1000,当包进入eth2所在的uxniji网络。反之亦然。我们通过OVS的dump-flows命令可以看到进入虚拟机网络的网络包在br-eth2上进行了VLAN标签的修改:
170 |
171 | # ovs-ofctl dump-flows br-eth2
172 | NXST_FLOW reply (xid=0x4):
173 | cookie=0x0, duration=18669.401s, table=0, n_packets=857, n_bytes=163350, idle_age=25, priority=4,in_port=2,dl_vlan=1 actions=mod_vlan_vid:1000,NORMAL
174 | cookie=0x0, duration=165108.226s, table=0, n_packets=14, n_bytes=1000, idle_age=5343, hard_age=65534, priority=2,in_port=2 actions=drop
175 | cookie=0x0, duration=165109.813s, table=0, n_packets=1671, n_bytes=213304, idle_age=25, hard_age=65534, priority=1 actions=NORMAL
176 |
177 | 从网络接口到namespace我们看到VLAN标签的修改如下:
178 |
179 | # ovs-ofctl dump-flows br-int
180 | NXST_FLOW reply (xid=0x4):
181 | cookie=0x0, duration=18690.876s, table=0, n_packets=1610, n_bytes=210752, idle_age=1, priority=3,in_port=1,dl_vlan=1000 actions=mod_vlan_vid:1,NORMAL
182 | cookie=0x0, duration=165130.01s, table=0, n_packets=75, n_bytes=3686, idle_age=4212, hard_age=65534, priority=2,in_port=1 actions=drop
183 | cookie=0x0, duration=165131.96s, table=0, n_packets=863, n_bytes=160727, idle_age=1, hard_age=65534, priority=1 actions=NORMAL
184 |
185 |
186 | 总之,当用户创建network,neutrong会创建一个namespace,这个namespace通过OVS连接到虚拟机网络。OVS还负责namespace与虚拟机网络之间VLAN标签的修改。现在,让我们看下创建虚拟机时,发生了什么?虚拟机是怎么连接到虚拟机网络的?
187 | ### Use case #2: Launch a VM
188 | 从Horizon或者命令行创建并启动一个虚拟机,下图是从Horzion创建的例子:
189 | 
190 | 挂载网络并启动虚拟机:
191 | 
192 | 一旦虚拟机启动并运行,我们发下nova支持给虚拟机绑定IP:
193 |
194 | # nova list
195 | +--------------------------------------+--------------+--------+------------+-------------+-----------------+
196 | | ID | Name | Status | Task State | Power State | Networks |
197 | +--------------------------------------+--------------+--------+------------+-------------+-----------------+
198 | | 3707ac87-4f5d-4349-b7ed-3a673f55e5e1 | Oracle Linux | ACTIVE | None | Running | net1=10.10.10.2 |
199 | +--------------------------------------+--------------+--------+------------+-------------+-----------------+
200 |
201 | nova list命令显示虚拟机在运行中,并被分配了IP 10.10.10.2。我们通过虚拟机定义文件,查看下虚拟机与虚拟机网络之间的连接性。
202 | 虚拟机的配置文件在目录/var/lib/nova/instances//下可以找到。通过查看虚拟机定义文件,libvirt.xml,我们可以看到虚拟机连接到网络接口“tap53903a95-82”,这个网络接口连接到了Linux网桥 “qbr53903a95-82”:
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 | 通过brctl查看网桥信息如下:
211 |
212 | # brctl show
213 | bridge name bridge id STP enabled interfaces
214 | qbr53903a95-82 8000.7e7f3282b836 no qvb53903a95-82
215 | tap53903a95-82
216 |
217 | 网桥有两个网络接口,一个连接到虚拟机(“tap53903a95-82 “),另一个( “qvb53903a95-82”)连接到OVS网桥”br-int"。
218 |
219 |
220 | # ovs-vsctl show
221 | 83c42f80-77e9-46c8-8560-7697d76de51c
222 | Bridge "br-eth2"
223 | Port "br-eth2"
224 | Interface "br-eth2"
225 | type: internal
226 | Port "eth2"
227 | Interface "eth2"
228 | Port "phy-br-eth2"
229 | Interface "phy-br-eth2"
230 | Bridge br-int
231 | Port br-int
232 | Interface br-int
233 | type: internal
234 | Port "int-br-eth2"
235 | Interface "int-br-eth2"
236 | Port "qvb53903a95-82"
237 | tag: 3
238 | Interface "qvb53903a95-82"
239 | ovs_version: "1.11.0"
240 |
241 |
242 | 我们之前看过,OVS网桥“br-int"连接到"br-eth2",通过veth pair(int-br-eth2,phy-br-eth2 ),br-eth2连接到物理网卡eth2。整个流入如下:
243 |
244 | VM -> tap53903a95-82 (virtual interface) -> qbr53903a95-82 (Linux bridge) -> qvb53903a95-82 (interface connected from Linux bridge to OVS bridge br-int) -> int-br-eth2 (veth one end) -> phy-br-eth2 (veth the other end) -> eth2 physical interface.
245 |
246 | 与虚拟机相连的Linux bridage主要用于基于Iptables的安全组设置。安全组用于对虚拟机的网络隔离进行增强,由于iptables不能用于OVS网桥,因此我们使用了Linux网桥。后边我们会看到Linux网桥的规则设置。
247 |
248 | VLAN tags:我们在第一个use case中提到过,net1使用VLAN标签1000,通过OVS我们看到qvo41f1ebcf-7c使用VLAN标签3。VLAN标签从3到1000的转换在OVS中完成,通过br-eth2中实现。
249 | 总结如下,虚拟机通过一组网络设备连入虚拟机网络。虚拟机和网络之间,VLAN标签被修改。
250 |
251 | ### Use case #3: Serving a DHCP request coming from the virtual machine
252 | 之前的use case中,我们看到了一个叫dhcp-的namespace和虚拟机,两者最终连接到物理网络eth2。他们都会被打上VLAN标签1000。
253 | 我们看到该namespace中的网络接口使用IP 10.10.10.3。因为虚拟机和namespace彼此连接并在相同子网,因此可以ping到对方。如下图,虚拟机中网络接口被分配了IP 10.10.10.2,我们尝试ping namespace中的网络接口的IP:
254 | 
255 |
256 | namespace与虚拟机之间连通,并且可以互相ping通,对于定位问题非常有用。我们可以从虚拟机ping通namespace,可以使用tcpdump或其他工具定位网络中断问题。
257 |
258 | 为了响应虚拟机的dhcp请求,Neutron使用了”dnsmasq“的Linux工具,这个工具是一个轻量的DNS、DHCP服务,更多的信息请查看(http://www.thekelleys.org.uk/dnsmasq/docs/dnsmasq-man.html)。我们可以在控制节点通过PS命令看到:
259 |
260 | dnsmasq --no-hosts --no-resolv --strict-order --bind-interfaces --interface=tap26c9b807-7c --except-interface=lo --pid-file=/var/lib/neutron/dhcp/5f833617-6179-4797-b7c0-7d420d84040c/pid --dhcp-hostsfile=/var/lib/neutron/dhcp/5f833617-6179-4797-b7c0-7d420d84040c/host --dhcp-optsfile=/var/lib/neutron/dhcp/5f833617-6179-4797-b7c0-7d420d84040c/opts --leasefile-ro --dhcp-range=tag0,10.10.10.0,static,120s --dhcp-lease-max=256 --conf-file= --domain=openstacklocal
261 |
262 | DHCP服务在namespace中连接到了一个tap接口(“--interface=tap26c9b807-7c”),从hosts文件我们可以看到:
263 |
264 | # cat /var/lib/neutron/dhcp/5f833617-6179-4797-b7c0-7d420d84040c/host
265 | fa:16:3e:fe:c7:87,host-10-10-10-2.openstacklocal,10.10.10.2
266 |
267 | 之前的console输出可以看到虚拟机MAC为fa:16:3e:fe:c7:87 。这个mac地址与IP 10.10.10.2 关联,当包含该MAC的DHCP请求到达,dnsmasq返回10.10.10.2。在这个初始过程(可以重启网络服务触发)中从namespace中看,可以看到如下的DHCP请求:
268 |
269 | # ip netns exec qdhcp-5f833617-6179-4797-b7c0-7d420d84040c tcpdump -n
270 | 19:27:12.191280 IP 0.0.0.0.bootpc > 255.255.255.255.bootps: BOOTP/DHCP, Request from fa:16:3e:fe:c7:87, length 310
271 | 19:27:12.191666 IP 10.10.10.3.bootps > 10.10.10.2.bootpc: BOOTP/DHCP, Reply, length 325
272 |
273 | 总之,DHCP服务由dnsmasq提供,这个服务由Neutron配置,监听在DHCP namespace中的网络接口上。Neutron还配置dnsmasq中的MAC/IP映射关系,所以当DHCP请求时会受到分配给它的IP。
274 |
275 | ### 总结
276 | 本文,我们基于之前讲解的各种网络组件,分析了三种use case下网络如何连通的。这些use cases对了解整个网络栈以及了解虚拟机/计算节点/DHCP namespace直接如何连通很有帮助。
277 | 根据我们的分析,我们确信启动虚拟机、虚拟机发出DHCP请求、虚拟机收到正确的IP后这个网络按照我们预想的工作。我们看到一个包经过一长串路径最终到达目的地,如果这一切成功,意味着这些组件功能正常。
278 | 下一篇文章中,我们会学习更复杂的neutron服务并分析他们如何工作。
279 |
--------------------------------------------------------------------------------