openstack octavia的实现与分析(二)原理,架构与基本流程
【了解】
其实说白了,Octavia就是将用户的API请求经过逻辑处理,转换成Haproxy或者Nginx的配置参数,下发到amphora虚机中。
Octavia的内部实现中,逻辑流程的处理主要使用TaskFlow库。
【基本概念】
LBaas
Load Balancing as a Service,在openstack平台上,LB被作为一种服务提供给用户,用户可以按需获取可配置的业务负载分担方案。
LBaaS(Load Balancer as a Service)是 OpenStack 的网络负载均衡服务,为用户提供应用集群负载均衡解决方案。LBaaS 支持将来自公网或内部网络的应用服务访问流量按照指定的均衡策略分发到资源池内的云主机,允许用户随时增加、减少提供应用服务的云主机而不影响业务可用性,有效保障了应用服务的响应速度和高可用。
以往,LBaaS 基于 Neutron 实现,LBaaS V1 API 在 Grizzly 版本被集成到 Neutron,功能模块的代码实现在 openstack/neutron-lbaas repo,支持 Plug-In 模式,提供了 HAProxy、F5 等多种 Driver 对接底层负载均衡器。LBaaS V2 API 在 Kilo 版本发布,Liberty 版本正式支持,同期发布的还有 Octavia Plugin。历经几个版本的迭代,Octavia 在 Pike 版本成为了需要在 Keystone 上注册 endpoint 的独立项目而不再是 Neutron 的一个服务插件。现在社区也正逐渐将 openstack/neutron-lbaas repo 实现的 Driver 迁移到 openstack/octavia repo,在 Queens 版本中 neutron-lbaas 正式被标记为废弃「Neutron-lbaas is now deprecated」。
为什么废弃 neutron-lbaas 扩展项目?社区给出了详尽的说明,简单总结一下有两点原因:
-
neutron-lbaas 与 Neutron 项目的耦合度太高,前者会直接使用 Neutron 的代码和 DB 从而导致 LBaaS API 的性能和扩展性不佳,而且 HAProxy Plugin 的实现也不具有高可用特性。总的来说,neutron-lbaas 不适用于大规模部署场景。
-
Ocatvia 项目已经成熟,可以向外提供稳定的 REST API,允许用户跨版本集成和迁移。同时,完全独立的状态会使 Ocatvia 发展得更加迅速。
OpenStack neutron-lbaas Deprecation FAQ 请浏览:
https://wiki.openstack.org/wiki/Neutron/LBaaS/Deprecation
项目组织的变化:
items | Old | New |
---|---|---|
Repo | openstack/neutron-lbaas | openstack/octavia |
CLI | neutronclient | octaviaclient (openstackclient 的扩展) |
Horizon panels | neutron-lbaas-dashboard | octavia-dashboard (Queens 开始支持) |
Octavia
Octavia 定位于电信运营商级别的可靠、可扩展负载均衡项目,加速 OpenStack LBaaS 在大规模应用场景中的落地。默认采用 HAProxy + Keepalived 组合的高可用负载均衡方案提供底层支撑。
简单总结一下 Octavia 的工作原理就是:Octavia 通过调用 Nova API 管理负载均衡器的 Lifecycle,调用 Neutron API 构建 LB Network 并接入业务网让负载均衡器纳管业务云主机,最后根据用户请求参数生成 HAProxy 和 Keepalived 的配置文件。前端为用户提供统一的业务访问入口(VIP),后端依靠负载均衡服务自动分发访问请求。
软件架构
网络架构
操作对象基本概念
Load Balancer:负载均衡服务的根操作对象,同时也是与 VIP 关联的逻辑对象。一个 Load Balancer 可以拥有一个或多个 VIPs。Load Balancer 需要占用 Neutron Subnet 的一个 Port,并从 Subnet 获取 IP 地址作为 VIP。
Subnet:下属 Neutron Network 的子网,用户业务云主机(Member)所处的网络,Subnet 与 Load Balancer 关联后,Load Balancer 拥有的 Amphora 才能与 Member 通信。
Listener:监听器,用户可通过其配置外部对VIP访问的端口,算法,类型等等。本质是 Subnet 的一个 Port,用于监听客户端对 Load Balancer(VIP)的访问请求,监听项为 HTTP/HTTPS、TCP 协议的元素(e.g. Port,URI),但不监听 IP 地址。符合监听规则(e.g. HTTP Port:80)的访问请求才会被转发到与 Listener 关联的 Pool 中。可以为一个 Load Balancer 设定若干个用于访问请求监听的 Listeners,一个 Listener 又可以关联多个 Pool。
Pool:类似于传统负载均衡系统中的 Backend Real Server Group 逻辑对象,作为 Member 的容器,接收 Listener 路由过来的客户端访问请求。通常的,会把业务类型相近的云主机划分到同一个 Pool,例如:Web 的动静分离场景。负责后端的虚拟机池。在Haproxy为driver的情况下,一个Pool对应着一个独立的network namespace中运行的HaProxy进程中管理的backend。一个VIP只会有一个Pool。
Member:传统负载均衡系统中的 Real Server,实际运行用户业务的云主机,被包含在一个 Pool 内,具有权重属性。Member 和 Pool one to one 关联。
Member 对应的是 pool 里面处理网络请求的一个 OpenStack Nova 虚机。
Health Monitor:Member 的 Health Check,与 Pool 关联,是一个单纯的 DB 对象,描述了运行在 Amphora 中的负载均衡器应该如何对 Pool 下属的 Member 进行健康状态检查的方法(e.g. HTTP Method、TCP、PING)。这是一个可选功能,但如果没有 Health Monitor,Pool 会认为所有 Member 都是 ACTIVE 的,哪怕 Member 其实不能响应。所以 Disabled Health Monitor 可能会造成负载均衡响应异常。它用来检测pool里面的member的状态,支持很多种检测方法,在neutron里面是可选的。
Amphora:为 Members 提供负载均衡服务的实体,类似于传统负载均衡系统中的 Frontend,默认为云主机,也可以是容器或裸机。Amphora 在用户新建 Load Balancer 的同时自动创建,一个 Load Balancer 可以拥有若干个 Amphora,这取决于用户选择的 loadbalancer_topology。
LB Network:全称 Load balancing management network,Octavia Controller 和 Amphora 通信的网络,每一个 Amphora 至少有一个 Port 接入 LB Network。LB Network 不会与任意一个租户关联,也不会暴露给其他的 OpenStack Project 使用。
HAProxy:运行在 Amphora 中的负载均衡器软件。
VIP:Virtual Load Balancer IP Address,与 Load Balancer 关联的虚拟 IP 地址,由运行在 Amphora 中的 Keepalived 应用 VRRP 协议原理来维护 VIP 的漂移和高可用性。
Layer 7 Switching:是针对七层 HTTP/HTTPS 协议的负载均衡功能,能够根据用户设定的 L7 Policy 将不同的客户端请求路由到不同的 Pool 中。
Layer 7 Policy:用于设定 Listener 将客户端请求转发到指定 Pool 的路由策略。当 Listener 关联了多个 Pool 时,可以通过设定 L7 Policy 来控制流量转发到指定的 Pool。Layer 7 Policy 只会与一个 Listener 关联,但可以关联多个 L7 Rule。例如:用户可以设定 URI 以 “/api” 开头的客户端请求都转发到 Listener 下的 Pool: “api_pool” 中。
Layer 7 Rule:本质是 HAProxy frontend section 下的 ACL 规则,可以根据是否满足规则的条件来确定最终处理客户请求的 Member。例如:用户可以设定 L7 Rule: “/api” 来匹配 URI 以 “/api” 开头的客户端请求,交由 Member: api_service 处理。Layer 7 Rule 与 Layer 7 Policy 结合使用实现 Layer 7 Switching 的功能。
Transport Layer Security (TLS) Termination:TLS Termination 是负载均衡器处理 HTTPS 协议的一种方式。通常的,HTTPS 协议要求客户端和服务端进行 3 次连接握手加上 9 次 SSL 安全验证握手,共 12 次握手才得以建立连接。可见如果在服务端(Member)上处理 SSL 握手,会对服务端造成比较大的压力。所以在负载均衡场景中,可以把这些压力转移到负载均衡服务器上,这就是负载均衡器的 TLS Termination 功能,将 HTTPS 连接中最耗时的部分从服务端剥离出来,让服务端专心于自身的业务负载。如果 Listener 设定了 HTTPS 的 Layer 7 Switching,那么 TLS Termination 将会非常有用。
基本概念之间的交互流程如下图:
【基本架构】
Amphora
负载均衡的载体,一般为云主机。(当然也可以使用物理机,将多个负载均衡配置到同一/两台Amphora节点上,提高数据包转发效率,但是有单点故障隐患)
manage-network
管理网络,通常管理数据走这条线路,东侧连接Amphora,西侧连接Octavia服务进程。
tenant-network
租户网络,内部通信使用,SLB转发报文通过租户网络到各个后端服务器上。
vip-network
服务地址,主要用于对外提供服务。
PS:vip-net和tenant-net可以是同一个网络,但是在生产环境中建议分开,以便于更好得划分网络安全隔离。
VM
后端服务器,用户的真实服务器
health-manager
Health Manager:用于监控 Member 的健康状态,如果出现故障,则自动进行故障转移。通过于 Agent 通信来更新 Amphora 中的负载均衡器的健康检查方式。
octavia里面进行健康检查的进程,主要有以下两个作用
1. 监听来自amphora虚拟机发来的运行状态数据,以此更新lb,listener,pool,member的状态,同时更新listener_statistics表(可作为计费依据),最重要的是更新amphora_health表。
2. 根据amphora_health数据表中的数据,找到异常状态的amphora虚拟机,对该虚拟机进行更换操作。(即删除旧的虚拟机,创建新的虚拟机并下发配置)
house-keeping
名副其实的 Housekeeping(家政)服务,保障 Octavia 的健康运行。
主要实现三个功能:
SpareAmphora: 清理虚拟机的池子, 确保空闲的amphorae池大小。
DatabaseCleanup: 定期清理数据库中已删除的amphorae记录。
CertRotation: 定期更新amphorae中的证书。
Agent:Amphora Agent,运行在 Amphorae 内,接收外部请求并组织 HAProxy 和 Keepalived,同时也负责上报 Member 的健康状态信息给 Health Manager。
Amphora Load Balancer Driver:负责 Controller 与 Amphora 在 LB Network 中的通信。
Octavia Worker
负责完成 API 请求,是 Octavia 主干功能的执行者。
主要作用是和nova,neutron等组件通信,用于虚拟机调度以及把对于虚拟机操作的指令下发给octavia agent。
实际的负载均衡业务逻辑,与 Nova 配合,完成 Amphora 的生命周期管理;与 Neutron 配合,完成 LB Network 接入 Subnet。还会通过与 Agent 通信将执行指令下发到 Amphora,支持插件框架。
基本流程如下:
Ocatvia Daemon 列表
octavia-api.service
octavia-worker.service
octavia-health-manager.service
octavia-housekeeping.service
【API 】
如下表:
Balancers |
GET |
/v2/lbaas/loadbalancers |
List Load Balancers |
|
POST |
/v2/lbaas/loadbalancers/{loadbalancer_id} |
Create a Load Balancer |
|
GET |
/v2/lbaas/loadbalancers/{loadbalancer_id} |
Show Load Balancer details |
|
PUT |
/v2/lbaas/loadbalancers/{loadbalancer_id} |
Update a Load Balancer |
|
DELETE |
/v2/lbaas/loadbalancers/{loadbalancer_id} |
Remove a Load Balancer |
|
GET |
/v2/lbaas/loadbalancers/{loadbalancer_id}/stats |
Get Load Balancer statistics |
|
GET |
/v2/lbaas/loadbalancers/{loadbalancer_id}/status |
Get the Load Balancer status tree |
|
PUT |
/v2/lbaas/loadbalancers/{loadbalancer_id}/failover |
Failover a load balancer |
Listeners |
GET |
/v2/lbaas/listeners |
List Listeners |
|
POST |
/v2/lbaas/listeners |
Create Listener |
|
GET |
/v2/lbaas/listeners/{listener_id} |
Show Listener details |
|
PUT |
/v2/lbaas/listeners/{listener_id} |
Update a Listener |
|
DELETE |
/v2/lbaas/listeners/{listener_id} |
Remove a Listener |
|
GET |
/v2/lbaas/listeners/{listener_id}/stats |
Get Listener statistics |
Pools |
|
|
|
|
GET |
/v2/lbaas/pools |
List Pools |
|
POST |
/v2/lbaas/pools |
Create Pool |
|
GET |
/v2/lbaas/pools/{pool_id} |
Show Pool details |
|
PUT |
/v2/lbaas/pools/{pool_id} |
Update a Pool |
|
DELETE |
/v2/lbaas/pools/{pool_id} |
Remove a Pool |
Members |
|
|
|
|
GET |
/v2/lbaas/pools/{pool_id}/members |
List Members |
|
POST |
/v2/lbaas/pools/{pool_id}/members |
Create Member |
|
GET |
/v2/lbaas/pools/{pool_id}/members/{member-id} |
Show Member details |
|
PUT |
/v2/lbaas/pools/{pool_id}/members/{member_id} |
Update a Member |
|
PUT |
/v2/lbaas/pools/{pool_id}/members |
Batch Update Members |
|
DELETE |
/v2/lbaas/pools/{pool_id}/members/{member_id} |
Remove a Member |
Health Monitor |
|
|
|
|
GET |
/v2/lbaas/healthmonitors |
List Health Monitors |
|
POST |
/v2/lbaas/healthmonitors |
Create Health Monitor |
|
GET |
/v2/lbaas/healthmonitors/{healthmonitor_id} |
Show Health Monitor details |
|
PUT |
/v2/lbaas/healthmonitors/{healthmonitor_id} |
Update a Health Monitor |
|
DELETE |
/v2/lbaas/healthmonitors/{healthmonitor_id} |
Remove a Health Monitor |
L7 Policies |
|
|
|
|
GET |
/v2/lbaas/l7policies |
List L7 Policies |
|
POST |
/v2/lbaas/l7policies |
Create an L7 Policy |
|
GET |
/v2/lbaas/l7policies/{l7policy_id} |
Show L7 Policy details |
|
PUT |
/v2/lbaas/l7policies/{l7policy_id} |
Update a L7 Policy |
|
DELETE |
/v2/lbaas/l7policies/{l7policy_id} |
Remove a L7 Policy |
L7 Rules |
|
|
|
|
GET |
/v2/lbaas/l7policies/{l7policy_id}/rules |
List L7 Rules |
|
POST |
/v2/lbaas/l7policies/{l7policy_id}/rules |
Create an L7 Rule |
|
GET |
/v2/lbaas/l7policies/{l7policy_id}/rules/{l7rule_id} |
Show L7 Rule details |
|
PUT |
/v2/lbaas/l7policies/{l7policy_id}/rules/{l7rule_id} |
Update a L7 Rule |
|
DELETE |
/v2/lbaas/l7policies/{l7policy_id}/rules/{l7rule_id} |
Remove a L7 Rule |
Quotas |
|
|
|
|
GET |
/v2/lbaas/quotas |
List Quota |
|
GET |
/v2/lbaas/quotas/defaults |
Show Quota Defaults |
|
GET |
/v2/lbaas/quotas/{project_id} |
Show Project Quota |
|
PUT |
/v2/lbaas/quotas/{project_id} |
Update a Quota |
|
DELETE |
/v2/lbaas/quotas/{project_id} |
Reset a Quota |
Providers |
|
|
|
|
GET |
/v2/lbaas/providers |
List Providers |
|
GET |
/v2/lbaas/providers/{provider}/flavor_capabilities |
Show Provider Flavor Capabilities |
Flavors |
|
|
|
|
GET |
/v2.0/lbaas/flavors |
List Flavors |
|
POST |
/v2.0/lbaas/flavors |
Create Flavor |
|
GET |
/v2.0/lbaas/flavors/{flavor_id} |
Show Flavor Details |
|
PUT |
/v2.0/lbaas/flavors/{flavor_id} |
Update a Flavor |
|
DELETE |
/v2.0/lbaas/flavors/{flavor_id} |
Remove a Flavor |
Flavor Profiles |
|
|
|
|
GET |
/v2.0/lbaas/flavorprofiles |
List Flavor Profiles |
|
POST |
/v2.0/lbaas/flavorprofiles |
Create Flavor Profile |
|
GET |
/v2.0/lbaas/flavorprofiles/{flavorprofile_id} |
Show Flavor Profile Details |
|
PUT |
/v2.0/lbaas/flavorprofiles/{flavorprofile_id} |
Update a Flavor Profile |
|
DELETE |
/v2.0/lbaas/flavorprofiles/{flavorprofile_id} |
Remove a Flavor Profile |
Amphorae |
|
|
|
|
GET |
/v2/octavia/amphorae |
List Amphora |
|
GET |
/v2/octavia/amphorae/{amphora_id} |
Show Amphora details |
|
GET |
/v2/octavia/amphorae/{amphora_id}/stats |
Show Amphora Statistics |
|
PUT |
/v2/octavia/amphorae/{amphora_id}/config |
Configure Amphora |
|
PUT |
/v2/octavia/amphorae/{amphora_id}/failover |
【数据结构】
以上是octavia主要数据表的拓扑图。
我们可以发现,load_balancer表几乎被关联到了所有的关键表,health_monitor是通过pool表去关联到listener和member的。
opertatingstatus和provisioning_status关联到了所有的关键表,主要作用是体现当前组件状态。
amphora_health主要体现amphora-agent的状态。
listener_statistics表,根据来自amphorae虚拟机发送的运行状态数据,实时维护对应
amphora_id与listener_id(主键)
的bytes_in,bytes_out,active_connections,total_connections字段,可以作为计费依据。
【主要流程】
创建loadbalancer
现支持single和active standby(主备双活)两种模式的loadbalancer。
P版本只支持single。
创建loadbalancer的参数中可以指定 vip 绑定的 port,如果没有指定,octavia 会自动(在 API 层)创建:
普通创建 lb 时,在 API 层会创建 lb 和 vip 的数据库记录,然后把请求交由 worker 处理。
创建loadbalancer,Octavia会创建两个虚拟机(active standby)。
如果配置enable_anti_affinity,则会针对这个 lb 先在Nova创建ServerGroup(这个ServerGroup的ID会记录在DB中),两个虚拟机就会创建在不同的host上。
虚拟机的flavor、image、network、security group、keypair信息都是从配置文件中获取。
有了虚拟机后,同时在入参的subnet下给两个虚拟机分别挂载网卡,并将VIP作为address pair配置到网卡。
然后,向虚拟机发送REST API, 参数中有VIP所在 subnet 的 CIDR,网关 IP,vrrp port 的 mac 地址,vrrp port 的 IP 地址等信息。
向amphora发送消息配置 keepalived 服务( active standby模式)。
至此,一个 loadbalancer 就创建结束了。基本上,后面创建listener、pool、member、health monitor,都是围绕这两个虚拟机,对haproxy(nginx)和keepalived进程进行配置。
在 octavia 中,资源之间的映射关系如下:
lb: 就是两个管理员/租户的虚拟机
listener: 虚拟机里面的一个 haproxy (nginx)进程,frontend 配置
pool: haproxy (nginx)配置中的一个 backend
member: backend 配置中的一个 member
上文中,frontend指的是前端,定义一系列监听套字节,接收客户端请求;backend指的是后端,定义一系列后端服务器,请求转发。
创建完 lb,登录 amphora 验证创建 lb 后的网络配置,可以看到默认只能看到管理 IP,只有在 namespace 中才能看到 vrrp 网卡信息。
amphora-agent 启动脚本是 octavia repo 中 cmd 目录下的 agent.py。
amphora-agent 还做一件事,定时向 health-monitor 发送haproxy的运行时信息,该信息是通过向haproxy进程发送socket查询命令获取到。
创建 listener 流程
在Octavia中,一个listener就对应amphorae 中一个haproxy进程。
首先生成haproxy配置文件,向amp发送消息,生成对应该 listener 的 haproxy 服务脚本。
再次向 amphorae 发送消息启动 haproxy 服务:
先确定listener的配置目录(/var/lib/octavia/{listener-id}/)在不在
如果是active standby,更新keepalived对各个haproxy的check脚本,
/var/lib/octavia/vrrp/check_scripts/haproxy_check_script.sh
启动haproxy服务,service haproxy-{listener_id} start
创建pool
创建 pool 的实现基本跟创建 listener 一致,在 amphorae 中仅仅是在 haproxy 的配置文件增加backend配置。
添加 member
在添加 member 之前,amphorae 虚拟机上已经有管理 port 和 vrrp port,其中 vrrp port 在命名空间中。
参考:https://www.cnblogs.com/liuxia912/p/11209968.html
https://blog.csdn.net/jmilk/article/details/81279795