0%

项目文件都在 xsc/src/server/ 目录下,目录结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
server/
├── dumpVulCSV.js
├── index.js
├── initial.js
├── lib
│   └── smsSender.js
├── model
│   ├── allSitesAreaStat.js
│   ├── allSitesVulStat.js
│   ├── apiKey.js
│   ├── assetServicePort.js
│   ├── assetStatusStat.js
│   ├── baselineResult.js
│   ├── baselineScript.js
│   ├── constants.js
│   ├── flowLog.js
│   ├── flowLogStatis.js
│   ├── index.js
│   ├── monitorPort.js
│   ├── newsCategory.js
│   ├── news.js
│   ├── osStat.js
│   ├── portStat.js
│   ├── questionAnswer.js
│   ├── questionNaire.js
│   ├── servicePort.js
│   ├── serviceStat.js
│   ├── siteAreaStat.js
│   ├── site.js
│   ├── siteVulStat.js
│   ├── tag.js
│   ├── task.js
│   ├── user.js
│   ├── vulDetail.js
│   ├── vul.js
│   └── vulTrash.js
├── plugins
│   ├── auth
│   │   ├── handlers
│   │   │   └── tokenHandler.js
│   │   ├── index.js
│   │   └── routes
│   │   ├── changePassword.js
│   │   ├── hjLogin.js
│   │   ├── index.js
│   │   ├── login.js
│   │   ├── logout.js
│   │   ├── refreshToken.js
│   │   ├── register.js
│   │   └── smsRegister.js
│   ├── redis.js
│   └── worker.js
├── registerPlugins.js
└── routes
├── admin
│   ├── newsCategory.js
│   ├── news.js
│   ├── README.md
│   ├── user.js
│   └── vulDetail.js
├── ass
│   └── stat
│   ├── area.js
│   ├── count.js
│   ├── index.js
│   ├── kind.js
│   ├── level.js
│   ├── name.js
│   ├── range.js
│   ├── top.js
│   └── vul.js
├── baseline
│   ├── index.js
│   └── script
│   ├── add.js
│   ├── delete.js
│   ├── detail.js
│   ├── list.js
│   └── update.js
├── changePassword.js
├── common
│   ├── captcha.js
│   ├── qiniu_token.js
│   └── sms.js
├── flowLog.js
├── flowStatis.js
├── index.js
├── monitorPort.js
├── profile.js
├── qanswer
│   ├── add.js
│   ├── detail.js
│   ├── index.js
│   └── score.js
├── qnaire
│   ├── detail.js
│   ├── index.js
│   ├── list.js
│   └── update.js
├── relatedDomain
│   ├── index.js
│   ├── list.js
│   ├── setToSite.js
│   └── stat.js
├── servicePort.js
├── site
│   ├── add.js
│   ├── areaStat.js
│   ├── baselineDelete.js
│   ├── baselineList.js
│   ├── batchAdd.js
│   ├── delete.js
│   ├── detail.js
│   ├── index.js
│   ├── list.js
│   ├── orgList.js
│   ├── safeStat.js
│   ├── servicePortList.js
│   ├── update.js
│   └── vulList.js
├── stat
│   ├── assetStatus.js
│   ├── index.js
│   ├── os.js
│   ├── port.js
│   └── service.js
├── syncBaselineFailed.js
├── syncBaseline.js
├── syncFlow.js
├── syncVulsFaild.js
├── syncVuls.js
├── tag
│   ├── add.js
│   ├── delete.js
│   ├── index.js
│   ├── list.js
│   └── update.js
├── task
│   ├── addBaseline.js
│   ├── add.js
│   ├── deleteTask.js
│   ├── detail.js
│   ├── index.js
│   ├── list.js
│   ├── retry.js
│   ├── runningNum.js
│   ├── status.js
│   └── vulList.js
└── vul
├── apiKey.js
├── downloadDocx.js
├── siteVulList.js
├── stat
│   ├── area.js
│   ├── count.js
│   ├── index.js
│   ├── kind.js
│   ├── level.js
│   ├── name.js
│   └── range.js
├── vulDetail.js
└── vul.js

../server/model/ 目录下都是表的定义;

../plugins/ 目录下是一下登录、认证等的处理;

../routes/ 目录下包括资产(/ass/stat)、基线baseline、站点site、任务task、漏洞vul

所有的文件夹基本都有一个 index.js 文件,用来保存所有暴露出来的接口。

BeautifulSoup 库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# coding:utf-8
from urllib.request import urlopen
from bs4 import BeautifulSoup
from urllib.error import HTTPError
import re

# 基本用法,创建 BeautifulSoup 对象
html = urlopen("http://www.pythonscraping.com/pages/page1.html")
bsObj = BeautifulSoup(html.read(), 'lxml')
print(bsObj.h1) # 打印标题

# 一个异常处理
def get_title(url):
try:
html = urlopen(url)
except HTTPError as e:
return None
try:
bs_obj = BeautifulSoup(html.read())
title = bs_obj.body.h1 # 同样可以打印标题
except AttributeError as e:
return None
return title


title = get_title("http://www.pythonscraping.com/pages/page1.html")
if title is None:
print("Title could not be found")
else:
print(title)

html = urlopen("http://www.pythonscraping.com/pages/warandpeace.html")
bsObj = BeautifulSoup(html.read(), 'lxml')
print(bsObj.h1)
nameList = bsObj.findAll("span", {"class": "green"}) # 找到 span 标签,属性为 class=green 的内容
for name in nameList:
print(name)
print(name.get_text()) # 获取到文本内容

html = urlopen("http://www.pythonscraping.com/pages/page3.html") # 处理子标签
bsObj = BeautifulSoup(html, 'lxml')
for child in bsObj.find("table", {"id": "giftList"}).children: # 子标签
print(child)

html = urlopen("http://www.pythonscraping.com/pages/page3.html") # 处理兄弟标签
bsObj = BeautifulSoup(html)
for sibling in bsObj.find("table", {"id": "giftList"}).tr.next_siblings: # 下面的兄弟标签
print(sibling)

html = urlopen("http://www.pythonscraping.com/pages/page3.html") # 处理父标签
bsObj = BeautifulSoup(html, 'lxml')
print(bsObj.find("img", {"src": "../img/gifts/img1.jpg"
}).parent.previous_sibling.get_text()) # 父标签的前一个标签

html = urlopen("http://www.pythonscraping.com/pages/page3.html")
bsObj = BeautifulSoup(html, 'lxml')
images = bsObj.findAll("img", {"src": re.compile("\.\.\/img\/gifts/img.*\.jpg")}) # 可以同时使用正则表达式
for image in images:
print(image["src"]) # 获取属性

print()

images = bsObj.findAll("img") # 取属性
for image in images:
print(image.attrs['src']) # 同样可以获取属性

爬虫的异常处理

异常处理

爬虫中的异常分为两种,一种是 HTTPError,另一种是 URLError,URLError 是 HTTPError 的父类,URLError不包括异常的状态码及原因而 HTTPError 包括,因此使用以下的方法来输出异常状态码和原因:

1
2
3
4
5
6
7
8
9
10
import urllib.error
import urllib.request

try:
urllib.request.urlopen("http://blog.csdn.net")
except urllib.error.URLError as e:
if hasattr(e,"code"):
print(e.code)
if hasattr(e,"reason"):
print(e.reason)

异常原因

产生 URLError 的原因有以下几种:

  1. 连不上服务器
  2. 远程 URL 不存在
  3. 本地没有网络
  4. 触发 HTTPError 子类

常见异常

301:重定向到新的 URL,永久性

302:非永久性的重定向

304:请求资源未更新

400:非法请求

401:请求未授权

403:禁止访问

404:找不到页面

500:服务器内部出错

501:服务器不支持实现请求所需要的功能

浏览器伪装技术

1
2
3
4
5
6
7
8
9
10
11
12
import urllib.request

url="http://blog.csdn.net/weiwei_pig/article/details/52123738"
# 添加浏览器的 User-Agent
headers=("User-Agent","Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.22 Safari/537.36 SE 2.X MetaSr 1.0")
opener=urllib.request.build_opener() # 创建对象
opener.addheaders=[headers] # 添加浏览器头

data=opener.open(url).read()
fh=open("F:/天善-Python数据分析与挖掘课程/result/22/4.html","wb")
fh.write(data)
fh.close()

Neutorn ML2 plugin 默认使用的 mechanism driver 是 open vswitch 而不是 linux bridge。但是 linux bridge 技术非常成熟,open vswitch 实现的 Neutron 虚拟网络较为复杂,不易理解;而 linux bridge 方案更直观。先理解 linux bridge 方案后再学习 open vswitch 方案会更容易。

配置 linux-bridge mechanism driver

配置文件位于 /etc/neutron/neutron.conf

控制节点和计算节点都需要在各自的 neutron.conf 中配置 core_plugin 选项。然后需要让 ML2 使用 linux-bridge mechanism driver。 ML2 的配置文件位于/etc/neutron/plugins/ml2/ml2_conf.ini

Local Network

在 ML2 中 enable local network

网络示例:

local network 的特点是不会与宿主机的任何物理网卡相连,也不关联任何的 VLAN ID。对于每个 local netwrok,ML2 linux-bridge 会创建一个 bridge,instance 的 tap 设备会连接到 bridge。位于同一个 local network 的 instance 会连接到相同的 bridge,这样 instance 之间就可以通信了。

配置文件位于 /etc/neutron/plugins/ml2/ml2_conf.ini

Flat Network

原理与配置

flat network 是不带 tag 的网络,要求宿主机的物理网卡直接与 linux bridge 连接,这意味着:每个 flat network 都会独占一个物理网卡

/etc/neutron/plugins/ml2/ml2_conf.ini 设置 flat network 相关参数。

需要指明 flat 网络与物理网卡的对应关系:

  • 各个节点中 label 与物理网卡的对应关系可以不一样
  • 如果要创建多个 flat 网络,需要定义多个 label,用逗号隔开,也需要用到多个物理网卡

DHCP 服务的配置

Neutron 提供 DHCP 服务的组件是 DHCP agen,默认通过 dnsmasq 实现 DHCP 功能。

配置 DHCP agent

DHCP agent 的配置文件位于/etc/neutron/dhcp_agent.ini

dhcp_driver

使用 dnsmasq 实现 DHCP

interface_driver

使用 linux bridge 连接 DHCP NameSpace interface

当创建 network 并在 subnet 上 enable DHCP 时,网络节点上的 DHCP agent 会启动一个 dnsmasq 进程为该 network 提供 DHCP 服务。

dnsmasq 是一个提供 DHCP 和 DNS 服务的开源软件。dnsmasq 与 network 是一对一关系,一个 dnsmasq 进程可以为同一 netowrk 中所有 enable 了 DHCP 的 subnet 提供服务。

DHCP agent 会为每个 network 创建一个目录 /opt/stack/data/neutron/dhcp/,用于存放该 network 的 dnsmasq 配置文件。

dnsmasq 重要的启动参数

–dhcp-hostsfile

存放 DHCP host 信息的文件,这里的 host 在我们这里实际上就是 instance。dnsmasq 从该文件获取 host 的 IP 与 MAC 的对应关系。每个 host 对应一个条目,信息来源于 Neutron 数据库。

–interface

指定提供 DHCP 服务的 interface。dnsmasq 会在该 interface 上监听 instance 的 DHCP 请求。

用 NameSpace 隔离 DHCP 服务

Neutron 通过 dnsmasq 提供 DHCP 服务,而 dnsmasq 如何独立的为每个 network 服务呢?答案是通过 Linux Network NameSpace 隔离。

在二层网络上,VLAN 可以将一个物理交换机分割成几个独立的虚拟交换机。类似地,在三层网络上,Linux network NameSpace 可以将一个物理三层网络分割成几个独立的虚拟三层网络。

每个 NameSpace 都有自己独立的网络栈,包括 route table,firewall rule,network interface device 等。

Neutron 通过 NameSpace 为每个 network 提供独立的 DHCP 和路由服务,从而允许租户创建重叠的网络。如果没有 NameSpace,网络就不能重叠。

NameSpace 是在 Linux 底层上对进程加以隔离的

1
ip netns list  # 列出所有的 namespace

其实,宿主机本身也有一个 namespace,叫 root namespace,拥有所有物理和虚拟 interface device。物理 interface 只能位于 root namespace。

新创建的 namespace 默认只有一个 loopback device。管理员可以将虚拟 interface,例如 bridge,tap 等设备添加到某个 namespace。

veth pair

veth pair 是一种成对出现的特殊网络设备,它们象一根虚拟的网线,可用于连接两个 namespace。向 veth pair 一端输入数据,在另一端就能读到此数据。

可以通过 ip netns exec <network namespace name> <command>管理 namespace。例如:

详见:获取 DHCP IP 的过程

Vlan Network

原理

因为物理网卡 eth1 上面可以走多个 vlan 的数据,那么物理交换机上与 eth1 相连的的 port 要设置成 trunk 模式,而不是 access 模式。

配置

/etc/neutron/plugins/ml2/ml2_conf.ini 设置 Vlan network 相关参数。

上面配置定义了 label 为 “default” 的 vlan network,vlan id 的范围是 3001 - 4000。这个范围是针对普通用户在自己的租户里创建 network 的范围。因为普通用户创建 network 时并不能指定 vlan id,Neutron 会按顺序自动从这个范围中取值。

对于 admin 则没有 vlan id 的限制,admin 可以创建 id 范围为 1-4094 的 vlan network。

接着需要指明 vlan network 与物理网卡的对应关系:

Router

L3 agent

Neutron 的路由服务是由 L3 agent 提供的。 除此之外,L3 agent 通过 iptables 提供 firewall 和 floating ip 服务。

配置

L3 agent 需要正确配置才能工作,配置文件为 /etc/neutron/l3_agent.ini,位于控制节点或网络节点上。

interface_driver 是最重要的选项,如果 mechanism driver 是 linux bridge,则:

interface_driver = neutron.agent.linux.interface.BridgeInterfaceDriver

如果选用 open vswitch,则:

interface_driver = neutron.agent.linux.interface.OVSInterfaceDriver

L3 agent 运行在控制或网络节点上。

1
neutron agent-list

l3 agent 会为每个 router 创建了一个 namespace,通过 veth pair 与 TAP 相连,然后将 Gateway IP 配置在位于 namespace 里面的 veth interface 上,这样就能提供路由了。

Floating IP

当租户网络连接到 Neutron router,通常将 router 作为默认网关。当 router 接收到 instance 的数据包,并将其转发到外网时:

  1. router 会修改包的源地址为自己的外网地址,这样确保数据包转发到外网,并能够从外网返回。
  2. router 修改返回的数据包,并转发给真正的 instance。

这个行为被称作 Source NAT

如果需要从外网直接访问 instance,则可以利用 floating IP。下面是关于 floating IP 必须知道的事实:

  1. floating IP 提供静态 NAT 功能,建立外网 IP 与 instance 租户网络 IP 的一对一映射。
  2. floating IP 是配置在 router 提供网关的外网 interface 上的,而非 instance 中。
  3. router 会根据通信的方向修改数据包的源或者目的地址。

小结一下:

  1. floating IP 能够让外网直接访问租户网络中的 instance。这是通过在 router 上应用 iptalbes 的 NAT 规则实现的。
  2. floating IP 是配置在 router 的外网 interface 上的,而非 instance,这一点需要特别注意。

VXLAN

本质上,VXLAN 和 VLAN 都是提供以太网二层服务的。

overlay network 是指建立在其他网络上的网络。overlay network 中的节点可以看作通过虚拟(或逻辑)链路连接起来的。overlay network 在底层可能由若干物理链路组成,但对于节点,不需要关心这些底层实现。目前 linux bridge 只支持 vxlan,不支持 gre;open vswitch 两者都支持。

VXLAN 为 Virtual eXtensible Local Area Network。正如名字所描述的,VXLAN 提供与 VLAN 相同的以太网二层服务,但拥有更强的扩展性和灵活性。

VXLAN 的优势

  1. 支持更多的二层网段

    VLAN 使用 12-bit 标记 VLAN ID,最多支持 4094 个 VLAN,这对大型云部署会成为瓶颈。VXLAN 的 ID (VNI 或者 VNID)则用 24-bit 标记,支持 16777216 个二层网段。

  2. 能更好地利用已有的网络路径。

VLAN 使用 Spanning Tree Protocol 避免环路,这会导致有一半的网络路径被 block 掉。VXLAN 的数据包是封装到 UDP 通过三层传输和转发的,可以使用所有的路径。

  1. 避免物理交换机 MAC 表耗尽。

    由于采用隧道机制,TOR (Top on Rack) 交换机无需在 MAC 表中记录虚拟机的信息。

VXLAN 封装和包格式

VXLAN 是一种在现有物理网络设施中支持大规模多租户网络环境的解决方案。VXLAN 的传输协议是 IP + UDP。

VXLAN 定义了一个 MAC-in-UDP 的封装格式。在原始的 Layer 2 网络包前加上 VXLAN header,然后放到 UDP 和 IP 包中。通过 MAC-in-UDP 封装,VXLAN 能够在 Layer 3 网络上建立起了一条 Layer 2 的隧道。

包格式:

VXLAN Tunnel EndPoint

VXLAN 使用 VXLAN tunnel endpoint (VTEP) 设备处理 VXLAN 的封装和解封。每个 VTEP 有一个 IP interface,配置了一个 IP 地址。VTEP 使用该 IP 封装 Layer 2 frame,并通过该 IP interface 传输和接收封装后的 VXLAN 数据包。

VXLAN 独立于底层的网络拓扑;反过来,两个 VTEP 之间的底层 IP 网络也独立于 VXLAN。VXLAN 数据包是根据外层的 IP header 路由的,该 header 将两端的 VTEP IP 作为源和目标 IP。

VXLAN 转发流程

配置

/etc/neutron/plugins/ml2/ml2_conf.ini 设置 VXLAN network 相关参数。

然后指定 VXLAN 的范围:

接着需要在 [VXLAN] 中配置 VTEP。

L2 Population

L2 Population 是用来提高 VXLAN 网络 Scalability 的

当 VXLAN 网络中的主机想要与其他的主机通信时,就会向网络中进行广播,询问对方主机的 MAC 地址,如果网络很大时,广播的成本就很大,所以 L2 Population 就出现了。

L2 Population 的作用是在 VTEP 上提供 Porxy ARP 功能,使得 VTEP 能够预先获知 VXLAN 网络中如下信息:

\1. VM IP – MAC 对应关系

\2. VM – VTEP 的对应关系

当 VM A 需要与 VM G 通信时:

\1. Host 1 上的 VTEP 直接响应 VM A 的 APR 请求,告之 VM G 的 MAC 地址。

\2. 因为 Host 1 上的 VTEP 知道 VM G 位于 Host 4,会将封装好的 VXLAN 数据包直接发送给 Host 4 的 VTEP。

这样就解决了 MAC 地址学习和 APR 广播的问题,从而保证了 VXLAN 的 Scalability。

VTEP 是如何提前获知 IP – MAC – VTEP 相关信息的呢?

答案是:

  1. Neutron 知道每一个 port 的状态和信息; port 保存了 IP,MAC 相关数据。
  2. instance 启动时,其 port 状态变化过程为:down -> build -> active。
  3. 每当 port 状态发生变化时,Neutron 都会通过 RPC 消息通知各节点上的 Neutron agent,使得 VTEP 能够更新 VM 和 port 的相关信息。

VTEP 可以根据这些信息判断出其他 Host 上都有哪些 VM,以及它们的 MAC 地址,这样就能直接与之通信,从而避免了不必要的隧道连接和广播。

配置

/etc/neutron/plugins/ml2/ml2_conf.ini 设置 L2 population mechanism driver。

同时在 [VXLAN] 中配置 enable L2 Population。

配置 L2 Population

Securet Group

安全组的原理是通过 iptables 对 instance 所在计算节点的网络流量进行过滤。

默认安全组

每个 Project(租户)都有一个命名为 “default” 的默认安全组。

「default」安全组有四条规则,其作用是:允许所有外出(Egress)的流量,但禁止所有进入(Ingress)的流量

1
iptables-save 命令查看相关规则

安全组有以下特性:

  1. 通过宿主机上 iptables 规则控制进出 instance 的流量。
  2. 安全组作用在 instance 的 port 上。
  3. 安全组的规则都是 allow,不能定义 deny 的规则。
  4. instance 可应用多个安全组叠加使用这些安全组中的规则。

FWaaS

FWaaS 的原理和传统网络一样,是在 Neutron 虚拟 router 上应用防火墙规则,控制进出租户网络的数据。最根本的实现方式还是 iptables。

FWaaS 有三个重要概念:Firewall、Policy 和 Rule。

Firewall

租户能够创建和管理的逻辑防火墙资源。Firewall 必须关联某个 Policy,因此必须先创建 Policy。

Firewall Policy

Policy 是 Rule 的集合,Firewall 会按顺序应用 Policy 中的每一条 Rule。

Firewall Rule

Rule 是访问控制规则,由源与目的子网 IP、源与目的端口、协议、allow 或 deny 动作组成。

安全组的应用对象是虚拟网卡,由 L2 Agent 实现,比如 neutron_openvswitch_agent 和 neutron_linuxbridge_agent。安全组会在计算节点上通过 iptables 规则来控制进出 instance 虚拟网卡的流量。也就是说:安全组保护的是 instance

FWaaS 的应用对象是 router,可以在安全组之前控制外部过来的流量,但是对于同一个 subnet 内的流量不作限制。也就是说:FWaaS 保护的是 subnet

启用 FWaaS

因为 FWaaS 是在 router 中实现的,所以 FWaaS 没有单独的 agent。已有的 L3 agent 负责提供所有 FWaaS 功能。

配置 firewall driver

Neutron 在 /etc/neutron/fwaas_driver.ini 文件中设置 FWaaS 使用的 driver。

配置 Neutron

在 Neutron 配置文件 /etc/neutron/neutron.conf 中启用 FWaaS plugin。

无规则的虚拟防火墙,不允许任何流量通过。

FWaaS 用于加强 Neutron 网络的安全性,与安全组可以配合使用。

下面将 FWaaS 和安全组做个比较。

相同点:

  1. 底层都是通过 iptables 实现。

不同点:

  1. FWaaS 的 iptables 规则应用在 router 上,保护整个租户网络;安全组则应用在虚拟网卡上,保护单个 instance。
  2. FWaaS 可以定义 allow 或者 deny 规则;安全组只能定义 allow 规则。

LBaaS

Load balancer 可以说是分布式系统中比较基础的组件。它接收前端发来的请求,然后将请求按照某种均衡策略转发给后端资源池中的某个处理单元,以完成处理。Load balancer 可以实现系统高可用和横向扩展。

LBaaS 有三个主要的概念:

Pool Member,Pool 和 Virtual IP

Pool Member

Pool Member 是 layer 4 的实体,拥有 IP 地址并通过监听端口对外提供服务。

例如 Pool Member 可以是一个 web server,IP 为 172.16.100.9 并通过 80 端口提供 HTTP 服务。

Pool

Pool 由一组 Pool Member 组成。这些 Pool Member 通常提供同一类服务。

例如一个 web server pool,包含:

web1:172.16.100.9:80

web2:172.16.100.10:80

Virtual IP

Virtual IP 也称作 VIP,是定义在 load balancer 上的 IP 地址。每个 pool member 都有自己的 IP,但对外服务则是通过 VIP。

OpenStack Neutron 目前默认通过 HAProxy 软件来实现 LBaaS。HAProxy 是一个流行的开源 load balancer。Neutron 也支持其他一些第三方 Load balancer。

配置 LBaaS agent

配置 LBaaS agent 的地方是 /etc/neutron/services/loadbalancer/haproxy/lbaas_agent.ini

interface_driver 的作用是设置 load balancer 的网络接口驱动,可以有两个选项:

Linux Bridge

interface_driver = neutron.agent.linux.interface.BridgeInterfaceDriver

Open vSwitch

interface_driver = neutron.agent.linux.interface.OVSInterfaceDriver

配置 LBaaS plugin

接下来需要配置:

  • 创建 Pool、VIP
  • 添加 Pool Member
  • 创建 Monitor 来监控负载均衡的状态

LBaas 实现机制

Neutron 是如何用 Haproxy 来实现负责均衡的。

在控制节点上运行 ip netns,我们发现 Neutron 创建了新的 namespace qlbaas-xxx

该 namespace 对应我们创建的 pool “web servers”。其命名格式为 qlbaas-< pool ID>。可以通过 ip a 查看其设置。

Load Balance Method 以及 Session Persistence

  1. Load Balance Method 是为新连接选择 member 的方法
  2. Session Persistence 是为同一个 client 的后续连接选择 member 的方法

两种方法介绍

架构图

与 OpenStack 其他服务一样,Neutron 采用的是分布式架构,包括 Neutorn Server、各种 plugin/agent、database 和 message queue。

  1. Neutron server 接收 api 请求。
  2. plugin/agent 实现请求。
  3. database 保存 neutron 网络状态。
  4. message queue 实现组件之间通信。

metadata-agent

instance 在启动时需要访问 nova-metadata-api 服务获取 metadata 和 userdata,这些 data 是该 instance 的定制化信息,比如 hostname, ip, public key 等。

但 instance 启动时并没有 ip,那如何通过网络访问到 nova-metadata-api 服务呢?

答案就是 neutron-metadata-agent。 该 agent 让 instance 能够通过 dhcp-agent 或者 l3-agent 与 nova-metadata-api 通信。

Neuton 架构总图

  • Neutron 通过 plugin 和 agent 提供网络服务
  • plugin 位于 Neutron server,包括 core plugin 和 service plugin
  • agent 位于各个节点,负责实现网络服务
  • core plugin 提供 L2 功能,ML2 是推荐的 plugin
  • 使用最广泛的 L2 agent 是 linux bridage 和 open vswitch
  • service plugin 和 agent 提供扩展功能,包括 dhcp, routing, load balance, firewall, vpn 等

实际网络分类

在实际环境中,通常会有四种网络:

  • Management 网络

    用于节点之间消息队列的内部通信和访问数据库服务

  • API 网络

    通过 API 网络向用户提供服务,Keystone, Nova, Neutron, Glance, Cinder, Horizon 的 endpoints 均配置在 API 网络上。通常,管理员也通过 API 网络 SSH 管理各个节点

  • VM 网络

    用于实例之间的通信,可以选择的类型包括 local, flat, vlan, vxlan 和 gre

  • External 网络

    External 网络指的是 VM 网络之外的网络,该网络不由 Neutron 管理。 Neutron 可以将 router attach 到 External 网络,为 instance 提供访问外部网络的能力

O(1) 称为常量复杂度,O(log n) 称为对数复杂度,O(n) 称为线性复杂度,O(n²) 称为平方复杂度,O(2ⁿ) 称为指数复杂度。

  • 基本算术运算是常量时间操作,逻辑运算是常量时间运算。
  • 组合对象有些是常量时间,有些不是。
    • 复制和切片通常需要线性时间(与长度有关,是 O(n) 时间操作)。
    • list 的元素访问和元素赋值(以及 tuple 的元素访问),是常量时间
    • dict 情况比较复杂。
  • 字符串也应该看做组合对象,许多操作不是常量时间。
  • 创建对象也需要时间和空间,所需的大小与对象的规模有关,通常应该看做线性时间和线性空间操作。
  • 构造新的的 list、set 结构,构造空结构(空表、空集合)是常量时间操作,而构造一个包含n个元素的结构,则至少需要 O(n) 时间。
  • 一些 list 操作的效率:元素访问和元素修改是常量时间操作,一般的加入/删除元素操作(即使只加入一个元素)都是 O(n) 时间操作,在表的最后加入和删除元素的操作效率高,在其他地方加入和删除元素的操作效率低。
  • 字典操作效率,加入新的键值对,最坏的情况复杂度是 O(n),但平均复杂度是 O(1)。
  • Python 的各种组合数据对象都没有预设的最大元素个数,从空间占用的角度看,其实际开销在存续期间可能变大,但通常不会缩小(即使后来元素变得很少了),比如删除元素。
  • 如果在程序中建立了一个表,此后一直将其作为全局变量的值,这个对象就会始终存在并占用存储空间。如果将其作为某个函数里局部变量的值,或者虽然作为全局变量的值,但是通过复制将其抛弃,这个对象就可以被回收。