Tag Archives: Neutron

本文由王为撰写,首发于 UnitedStack 官方博客和官方微信公众号,转载前请联系作者。

文章里 MidoNet 的分析不多,其实很值得研究,关注的同学可以一起探讨。

文章基于我在 ArchSummit2015 深圳 会议上的演讲整理而成,所以可能讨论的不够细致。

前言

当我们提到 OpenStack 的网络,很多人会望而生畏,说 OpenStack 网络好复杂、Neutron 难以维护、Overlay 网络性能低下…… 这样的印象阻碍了 OpenStack 特别是 Neutron 在企业的部署脚步,事实上从 OpenStack 诞生起,其网络的模型和设计就一直在进化并且保持着高效、快速的迭代,特别是从 Neutron 诞生,Legacy 网络、Provider 网络、L3 HA、L2 Population、DVR、DragonFlow 相继提出,我们看到 Neutron 在其每一个 Cycle 都在向企业级的生产软件靠近,本文将尝试对 OpeStack 的网络发展做一个综合性的总结和比较。

从 Nova-network 说起

我们知道最初 OpenStack 只有 Nova 和 Swift 两个组件,所以 Nova 除了提供基础的计算服务,包括调度、块设备和网络也一并由 Nova 提供,当时的网络是什么样呢?为什么现在还有很多 Superuser 还在使用 Nova-network?

最开始,大家期望中的 OpenStack 网络是什么样的?

  1. 能给虚拟机提供 IP 地址;
  2. 虚拟机在需要时可以连通外网;
  3. 相同网络下的虚拟机之间允许内部通信;
  4. 一些虚拟机还希望能获得一个外网 IP 来对外提供服务。

最后特别对于公有云,租户间还需要保证网络隔离。

基于以上需求,Nova-network 提供了这样的参考模型(VlanManager+MultiHost):

1

首先,dnsmasq 进程绑定在租户的网桥上,用于提供 DHCP 服务,提供 IP 地址;然后,计算节点上配置默认路由并将一个网口连接至公网,这样虚拟机按默认路由发送的报文将被网桥以节点的默认路由送出,发往公网的接入层;同一租户的网络处于同于 Vlan,通过网桥广播允许其互相通信;不同租户的虚拟机如果则通过节点上的路由表路由到对应网桥并转发(见上图);如果虚拟机需要公网 IP,则可以在计算节点上直接起 NAT 规则对应到相应内网 IP。

整个模型很简单明了,全部使用 Linux 中较为成熟的网络技术, 所有路由选择由本地决定,不依赖某个单点,这个在 Nova-network 中被称为 MultiHost,是Nova-network 的重要特性,所以其一出世就获得了很多人的青睐。

但是 Nova-network 的缺点也是很明显的:

  1. 因为 Vlan 技术固有缺陷,一个 Region 下无法服务太多租户;
  2. 路由实现粗糙,路由决策和 NAT 依赖 IP 地址,所以很难实现Overlap IP,用户的 IP 管理不自由;
  3. 前面说不同租户(其实是不同网络)之间似乎可以在没有公网IP的情况下互香通讯,但这是有条件的,再看前面的图,我们看到如果想在计算节点下做路由决策,让数据包成功封装另一个租户的 Vlan,我们需要这个计算节点拥有另一个租户的网桥,而且因为这个链路的非对称性,对方节点也需要相同的要求。因为 Nova-network 的网桥是按需建立的(不然太多),所以其实这种通信是无法保障的。

最后,Nova-network 提供的网络高级功能很有限,只有基本的安全组,很难满足用户需求,而且将网络紧耦合在计算服务中也不符合云计算的架构,所以社区最终成立了 Neutron 项目。

Neutron 的艰难前行

Neutron 的诞生承载着大家对面向大型云基础设施的网络服务的期望,它在一开始就着手设计了基于 Overlay 网络的网络模型,通过先进的 VxLan 和 NVGRE 协议, Neutron 克服了很多在 Nova-network 中无法解决的网络问题。Overlay 网络是什么的,简单的说,它是一个逻辑网,运行在物理网之上,一般要求物理网 IP 可达,然后通过 UDP 等三层传输协议承载二层,形成 L2 over L3 的模型,这样我们就可以实现突破物理拓扑的任意自定义网络拓扑、Overlap IP 等。

2

首先针对 Nova-network 面临的几个问题,VxLan、NVGRE 等都支持上千万的租户数量,远远满足一般需求;其次通过 L2 over L3,用户完全实现了自定网络拓扑,没有 IP 地址的限制;不同网络间拥有不用的 VxLan tag,当需要在不同网络下互相通信时,可以通过路由器路由转换 VxLan tag,不再有种种限制。

针对 Nova-network 的高级功能匮乏的问题,借助灵活的网络模型和虚拟路由器的实现,Neutron 拥有自定义路由、VPNaaS、FWaaS 和 LBaaS 等多种高级功能。此外,由于 Neutron 定义良好的北向接口和 Plugin-extension 架构,它可以支持大量厂商的设备,用户拥有彻底的自主选择权,厂商拥有高度的自主开发空间。

既然我们说的这么好,为什么很多人对其都不满意呢?原因也很多:

  1. Neutron 使用了 Namespace、Open vSwitch、网桥、veth、iptables 等技术,其中有些内容,特别是 OVS 对很多人都是比较陌生的,而且在一开始,其稳定性也受人质疑,这让人们有了充分的质疑理由;
  2. 南北向通讯和跨网络通讯都依赖于网络节点,而这个节点在默认的模型下是单点。
  3. Overlay 网络的默认性能并不能让人满意,需要专业工程师或厂商设计方案和调优。

软件的复杂度随着软件功能的丰富和接口的复杂性的上升几乎是必然的,Open vSwitch 的稳定性和性能也一直在提升,所以社区决定要发动力量主要解决第二个问题。

首先是 HA,企业 IT 系统首先关心的,莫过于系统的稳定性,一个可靠的 HA 方案是社区首先考虑的。很多网络服务的高可用都是借助 VRRP 协议的,Neutron 也不例外,通过 Keepalived + conntrackd,实现 Master 和 Slave 共同维护 VIP,一旦 Master 挂掉了,VIP 将自动飘到 Slave 节点上,因为 conntrackd 始终在自动拷贝session 信息,所以理论上可以实现用户的无感知自动切换。

3

L3 HA 确实实现了高可用,但是东西流量还是没有优化啊,这里面一大原因是 VxLan本来支持组播的,但是 OVS 目前支持有限,我们总是不得把一些无效的 ARP 广播发送出去。比如说下图中,A 的广播包其实只对 3 和 4 有用,但是 2 和 5 也收到了:

4

如何优化,这里的问题是虚拟机不知道通信对方的位置,可是 Neutron 知道啊,Neutron 数据库中保存着每一个 Port 联接的虚拟机信息、其 IP、MAC 地址、其宿主机信息等等,所以如果有新的虚拟机建立起来,连接了网络,那么 Neutron 就往所有 Agent 发送消息,告诉他们新的 Port 的所有信息,大家就低头检查看看自己是不是也有这个网络的虚拟机,如果有就更新流表规则,将来要请求这个 IP 的 ARP 可以直接回应,如果没有就忽略。这就是 L2 Population 和 ARP responder。

OK,更加优化了一步,但是他也有问题啊,就是

  1. 因为消息是广播的,很耗费资源;
  2. 跨网络的通讯还要依赖于路由器;
  3. 它目前没办法和 L3 HA 共同工作!

为什么它无法和 L3 HA 共同工作呢,因为 L2 Pop 假定了每个 Port 都工作在一个固定的节点上,这样 L2 Pop 才能将 ARP 和 Tunnel 引过去,然而 L3 HA 破坏了这个假设…… Bug 的 report 见 Launchpad 上的 #1365476 ,目前尚未解决……

Read More →

前几个星期,社区通过了一个 Patch 来解决一个遗留很久的 DHCP 相关的问题,这个 Patch 并不复杂(review 地址是 https://review.openstack.org/#/c/185486/),但为什么这么做却有一点故事,拿出和大家聊一聊。

事情从 DHCP HA 说起。我们知道 Neutron 的架构是每个“网络”(Network),都会有一个相应的 namespace 名为 qdhco-XXX(XXX 为网络的 UUID)运行在网络节点上。这个网络命名空间内会有一个  tuntap 设备,名为 tapXXX(XXX 为 port 的 ID),然后有一个 dnsmasq 进程与之绑定。

dnsmasq.png

这样,每当新的虚拟机启动,自动广播 DHCP 请求,namespace 下的 dnsmasq 将收到这个广播包并根据 dhcp-hostfile 里的内容对 VM 给予回应,分配并确认其 IP 地址。这一切都挺好的,先不考虑网络规模很大时 dnsmasq 的承载能力, 不考虑将 dhcp 分布式时,it works。

但如果我们想尝试将 DHCP 做 HA 呢?考虑到如果这个 dnsmasq 进程挂掉了,或者这个网络节点上的 ovs 异常了,甚至网络节点挂掉了…… 嗯,让我们先从 DHCP 的流程说起。

IPv4 版的 DHCP 是按照 RFC 2131 Dynamic Host Configuration Protocol 标准的,先撇开其具体细节,大概的 DHCP 流程是这样的:

[caption id="" align="alignnone" width="640"] dhcp[/caption]

首先在 DHCP 发现阶段,客户端发送目的地址为 255.255.255.255 的 UDP 广播包,然后服务端回复 DHCP OFFER,包含分配的 IP、默认路由、租约有效期等等。为了避免同一个网络下有多个 DHCP 服务端,而客户端只接受一个 DHCP 结果,所以客户端需要再发广播通知所有 DHCP 服务端自己接受了哪个 DHCP 分配结果,这个包里含有它自己给自己确定的 IP 地址,这个 IP 地址来自于哪个 DHCP 服务端(服务端的 IP 地址)。最后服务端广播一条 ACK 作为结束。 Read More →

原帖由 Neutron PTL: @Kyle 发在社区:

http://specs.openstack.org/openstack/neutron-specs/priorities/kilo-priorities.html

重构类:

  • REST API、RPC 等都将重构;
  • WSGI 从自己写的原生 API 改为由 pecan 实现;
  • 降低从 nova-network 迁移到 neutron 的难度;
  • 将第三方的 drivers 从主目录分出来;
  • 分割高级服务功能(LBaaS、VPNaaS、FWaaS)

测试类:

  • 增加全栈测试;
  • 增加更多的功能测试;

Agent 类:

  • L2 Agent:抽象、功能测试、OVSDB、ML2 Agent;
  • DHCP Agent:重启优化、负载均衡调度、死亡 Agent 重新调度、功能测试

新功能:

  • 插件化的 IPAM(IP 地址管理);
  • 实现 Trunk Port,主要为 NFV 使用;
  • 提高 Agent 子进程的可监视性;
  • 使用“daemon mode”代替 rootwrap 提高调用系统指令的的性能

吐槽:

重构动作好大,对 Neutron 有很多修改的公司又被坑苦了;

Read More →

Neutron 的软件架构

综述

OpenStack 是目前开源界第二大的项目,参与的厂商之多可谓少见,同时作为目前最大的以 Python 作为主要语言的项目,可以说这个项目是经过重重困难发展起来的,算是目前在发展的分布式系统软件大作了,面对这么一个项目,我想我们有很多值得学习和借鉴的地方,因为时间和个人经验的缘故,我在这里主要与大家分享以 Neutron 为例的 OpenStack 软件设计。

Why Python

设计一个分布式系统可以说会面对诸多挑战,这不只是 Python 会遇到的,使用别的语言也会碰到,但是呢,Python 作为一个与 Java 等语言相比不够成熟的语言可能会面临一些其他可能已经在一些语言下解决了的问题,在 OpenStack 社区里就有人提过多次这个问题,为什么我们选择 Python,而非别的语言。

在我看来,一个大型软件的选型是一个复杂的事情,对于 OpenStack,可能第一是因为历史原因。因为我们知道 OpenStack 最早的源代码是 Rackspace 和 NASA 一起贡献的,他们当初内部的选择为我们建立了一个基调,如果再用其他语言重写的话,可能在当时是一个不合实际的考虑;再有,OpenStack 与其说是一个大型软件,倒不如说是一个框架,它的虚拟化来自于 KVM、Qemu 等的支持,它的网络来自于 Open vSwitch、iptables 等的支持,至于存储,也需要 lvm、Ceph 作为底层。那么 OpenStack 是干嘛的呢,它是一个总的调度器,集成这一切功能,完成一个真正的自由云计算软件。做运维的同学一般比较熟的语言都是 Shell、Python,老一点的可能熟悉 Perl,为什么?因为这些脚本语言,很适合做这种调度的工作,或者说它很适合做粘合剂,正如一些人称 Python 为“胶水语言‘一样,它能够方便的粘合各个组件,而且代码量相对少,可以让人专注于高层的事情,而不是为了底层费脑筋;再有,作为一个高级语言,Python 有着一些相对完美的特性,比如社区的有过提交的开发者有数千,活跃的开发者也有几百,为什么 OpenStack 能快速吸引这么多开发者,所有人都是之前就接触过 Python 么?不是的,很多人都是现学的,因为 Python 的基本语法真的很简单,只需要看一个晚上第二天就能阅读 OpenStack 基本的代码了,这对吸引开发者来说很有好处,就像为什么有些公司做项目首先考虑 Java,因为好招人啊!Python 作为一个学习曲线平滑的语言,可以说为吸引开发者带来很多方便。再有,反射、自省这些高级特性也不缺,这位开发带来了方便,丰富的库,比如Paste、Routes、requests、WebOb、alembic、Jinja2 等,更是提升前期效率的利器。

分布式系统中面临的问题

连接建立与服务初始化
事件分离与事件处理程序分派
IPC 与网络协议处理
静态和动态组件
并发与同步

Neutron 简介

因为很多人对 OpenStack 不那么熟,我就先简单介绍下 Neutron 是什么。Neutron 是 OpenStack 的虚拟网络组件,用洋气点的话说,就是一个 SDN 控制器。为什么我们需要虚拟网络?过去我们只给客户提供虚拟机,你花钱,我租你一台,想连接上就再买个公网 IP,就像很多人在 DigitalOcean 做得一样(当然 DigitalOcean 现在也有虚拟网络)。那有了虚拟网络可以干什么呢?我们来看一下 UStack 控制面板里的一张图:
Read More →

之前一直没有好好看过 Neutron API 服务的实现,这几天好好看了一下,对 WSGI、paste.deploy、Webob、routes 熟悉的人估计很快就能看完,可惜我对上面的概念/库没有个熟悉的,所以看了好久才看明白…… 下面是记录,这一部分主要是从 main 开始逐句分析 server 启动的大概过程,主要针对 API,对 RPC 的介绍等下次在看。

安装 Neutron-server 后,其将作为一个服务,启动,和别的服务一样,启动文件在 /etc/init.d,这里挑选部分:

. /etc/rc.d/init.d/functions  
# 执行 /etc/rc.d/init.d/functions,主要是引用里面的函数

prog=neutron
exec="/usr/bin/$prog-server"  # 目标执行文件是/usr/bin/neutron-server
configs=(
   "/usr/share/$prog/$prog-dist.conf" \
   "/etc/$prog/$prog.conf" \
   "/etc/$prog/plugin.ini" \
)  # 配置文件位置
pidfile="/var/run/$prog/$prog.pid"
logfile="/var/log/$prog/server.log"

[ -e /etc/sysconfig/$prog ] && . /etc/sysconfig/$prog
#如果存在 /etc/sysconfig/neutron 则执行

lockfile=/var/lock/subsys/$prog-server

start() {
   [ -x $exec ] || exit 5  # 若 /usr/bin/neutron-server 存在且可执行则运行
   for config in ${configs[@]}; do
       [ -f $config ] || exit 6  # 检验文件是否存在且为普通文件
   done
   echo -n $"Starting $prog: "
   daemon --user neutron --pidfile $pidfile "$exec ${configs[@]/#/--config-file } --log-file $logfile &>/dev/null & echo \$! > $pidfile"
   # 引号部分比较复杂,其实是执行这么一句话:
   # "/usr/bin/neutron-server --config-file /usr/share/neutron/neutron-dist.conf
   # --config-file /etc/neutron/neutron.conf --config-file /etc/neutron/plugin.ini --log-file
   # /var/log/neutron/server.log",并丢弃其输出,然后获得其 pid,把 pid 输出到
   # /var/run/neutron/neutron.pid,去掉执行 /usr/bin/neutron-server 时加的乱七八糟一大堆参数
   # 其实简化相当与这样:
   # daemon --user neutron --pidfile /var/run/neutron/neutron.pid /usr/bin/neutron-server
   # damon 是来自 /etc/rc.d/init.d/functions 用于产生 service 的函数
   retval=$? # 获取 damon 执行后的状态值
   echo
   [ $retval -eq 0 ] && touch $lockfile
   # 执行成功(状态值为0)则更新 /var/lock/subsys/neutron-server 的使用/更新时间为当前
   return $retval
}

ok,这个启动脚本主要还是执行 /usr/bin/neutron-server,我们看下这个脚本的内容:

#!/usr/bin/python
# PBR Generated from 'console_scripts'

import sys

from neutron.server import main

if __name__ == "__main__":
   sys.exit(main())

就是执行了一下 neutron.server.main(),下面我们来看下这个函数(server/__init__.py文件): Read More →