记录学习neutron l3 HA实现的过程。
1. router所在的所有节点的namespace中都会启动keepalived服务,通过keepalived服务来控制节点的选举:
keepalived的进程: keepalived -P -f /var/lib/neutron/ha_confs/d188f462-ae87-455d-9445-da00c842e78e/keepalived.conf -p /var/lib/neutron/ha_confs/d188f462-ae87-455d-9445-da00c842e78e.pid -r /var/lib/neutron/ha_confs/d188f462-ae87-455d-9445-da00c842e78e.pid-vrrp
keepalived的配置文件:
vrrp_instance VR_1 {
state BACKUP
interface ha-eca0c14d-f0
virtual_router_id 1
priority 50
nopreempt
advert_int 1
track_interface {
ha-eca0c14d-f0
}
virtual_ipaddress {
169.254.0.1/24 dev ha-eca0c14d-f0
}
virtual_ipaddress_excluded {
10.168.89.167/24 dev qg-eb9e70a6-0a
172.16.5.1/24 dev qr-ca16028e-41
fe80::f816:3eff:febb:31bc/64 dev qr-ca16028e-41 scope link
fe80::f816:3eff:fee8:4fda/64 dev qg-eb9e70a6-0a scope link
}
virtual_routes {
0.0.0.0/0 via 10.168.89.254 dev qg-eb9e70a6-0a
}
}
kilo neutron l3 ha的实现
主要围绕以下几个问题:
1. l3 agent的调度策略
2. keepalived 和 neutron-keepalived-state-change 服务是什么时候创建的
3. keepalived 和 neutron-keepalived-state-change 如何实现l3 ha
4. l3 ha 通常会遇到的问题以及解决的办法
neutron l3 相关的代码:
1. 配置文件中配置了service_plugins 指定加载l3_router_plugin:
service_plugins = neutron.services.l3_router.l3_router_plugin.L3RouterPlugin
其中plugin_type 设置成了constants.L3_ROUTER_NAT, 所以之后可以通过
manager.NeutronManager.get_service_plugins().get(service_constants.L3_ROUTER_NAT)来获得这个plugin
2. l3_router_plugin中定义了supported_extension_aliases = ["dvr", "router", "ext-gw-mode",
"extraroute", "l3_agent_scheduler",
"l3-ha"]
继承的顺序如下:
common_db_mixin.CommonDbMixin,
extraroute_db.ExtraRoute_db_mixin,
l3_hamode_db.L3_HA_NAT_db_mixin,
l3_gwmode_db.L3_NAT_db_mixin,
l3_dvrscheduler_db.L3_DVRsch_db_mixin,
l3_hascheduler_db.L3_HA_scheduler_db_mixin
一 创建router,执行的操作:
1. neutron server调用l3_hamode_db.L3_HA_NAT_db_mixin.create_router
1.1. 调用l3_db.L3_NAT_dbonly_mixin.create_router方法创建数据库记录
1.2. _create_ha_network如果当前没有ha network会创建ha network和 ha subnet, 同时会建立ha network和tenant的关系: 表ha_router_networks
1.3. _set_vr_id设置vrid(virtual router id)会在keepalived中使用, 用于识别同一个租户下的不同router, vrid的返回是1 到 254, 所以一个tenant最多只能建立254个router
1.4 _create_ha_interfaces 根据配置文件的min_l3_agent_per_router 和 max_l3_agent_per_router 以及当前l3_agent的个数来在HA Network上创建port
同时给这些port和router做绑定关系, agent和state初始化为null(表: ha_router_agent_port_bindings)
1.5 _notify_ha_interfaces_update,
1.5.1: scheduler router, kilo中支持两种调度策略(ChanceScheduler 和 LeastRouterScheduler)可以在neutron.conf中router_scheduler_driver指定。
ChanceScheduler: 表示随机分配策略
LeastRouterScheduler: 表示最少router优先的策略
其中schedule_router的过程中还会执行bind_router操作,这个操作其实是将ha_router_agent_port_binding表中的ha port分配给agent, 同时建立router和agent的关系(routerl3agentbindings)
1.5.2: rpc_cast, "routers_updated" 给这个router所分配的所有router
2. neutron l3 agent, agent/l3/agent.py
l3_agent的处理过程: L3NATAgent在初始化过程中会创建一个queue(queue里面存各个router的事件): self._queue = queue.RouterProcessingQueue(),
l3_agent会有一个循环不断处理queue里面的数据(_process_routers_loop)。如果处理过程中出现异常会触发一次fullsync,保证这个l3_agent是最新的一个状态。后面需要学习fullsync的过程。
routers_updated 所做的操作:
2.1 _process_router_if_compatible(检查兼容性)
2.1.1 检查配置文件中的external_network_bridge是否存在。
2.1.2 如果没有指定use_namespaces,则l3_agent只能处理一个router,所以判断更新事件的router_id和配置中的router_id是否一致。(这种情况可以忽略,现在一般都会用namespace)
2.1.3 如果router没有指定external gateway,且该agent不支持internal router(配置文件中:handle_internal_only_routers
),抛出RouterNotCompatibleWithAgent异常
2.1.4 之前的router_info中没有存改router信息执行_process_added_router, 否则_process_updated_router
2.2 _process_added_router(处理新增的router)
2.2.1 创建ha_router.HaRouter对象, 其中创建了namespaceManager 和iptablesManager
2.2.2 调用ha_router的initialize
2.2.2.1
router_info的initialize
创建namespace,同时setup lo设置以及设置namespace的网络转发参数, sysctl -w net.ipv4.ip_forward=1
2.2.2.2 _init_keepalived_manager, 创建keepalivedManager,初始化一些keepalived的参数(比如,vrid、ha_subnet_cidr等),但是还没有创建进程。
2.2.2.3 ha_network_added, 创建物理设备(ha_port, tag是由哪个值决定的?),把它绑定到br-int上,并将它放到namespace里面,同时配置相应的ip地址,169.254.192.x/18
$ ovs-vsctl --timeout=10 --oneline --format=json -- --if-exists del-port ha-255eb1bf-7d -- add-port br-int ha-255eb1bf-7d -- set Interface ha-255eb1bf-7d type=internal external_ids:iface-id=255eb1bf-7ba7-41d7-bc36-029e541bedfd external_ids:iface-status=active external_ids:attached-mac=fa:16:3e:3d:3e:ce 这个居然会创建tag ?? 应该是ovs-agent会创建相应的tag,得验证, external_ids只是为了保存信息。
2.2.2.4 update_initial_state, 判断是否keepalived的vip (vip的值怎么决定的?初始化的时候哪个节点作为vip节点?vip是由第一个可用的cidr为24的范围决定,初始化时所有的节点都为backup节点
)在当前agent的ha设置上来判断当前节点是master还是slave,同时会回调ensure_state_change来设置状态值。
2.2.2.5 spawn_state_change_monitor
创建neutron-keepalived-state-change进程, 参数包括router_id, namespace ,conf_dir, monitor_interface, monitor_cidr, pid_file, state_path, user 以及group
2.2.3 调用ha_router的
process
2.2.3.1 _ process_internal_ports, 处理router绑定的内部interface的port,刚创建的router还没有绑定interface,所以忽略。
2.2.3.2 process_external, 处理floatingip的绑定,同时执行iptables相关的规则。
2.2.3.3 enable_keepalived,
启动keepalived的进程。
直到这整个创建router的过程结束。
二 neutron-keepalived-state-change服务是怎么判断节点状态的变化
1. 首先neutron-keepalived-state-change会启动一个异步进程(
ip -o monitor address)去监听router namespace下ip地址的变化
2. 遍历所有地址的变化,有地址的增加则认为是master, 其它地址变化都是backup
3. 更改keepalived文件夹下的state文件, state文件保存了router在当前agent的状态(master/backup)
。
4. 通过unix domain socket来通知l3_agent 服务节点状态的变化。 (unix domain socket的server在初始化l3_agent的时候创建.ha.AgentMixin)
参考文档: https://wiki.openstack.org/wiki/Neutron/L3_High_Availability_VRRP