背景
在 openstack 傳統的集中式路由場景下:
從圖中可以明顯看到東西向和南北向的流量會集中到網絡節點,這會使網絡節點成為瓶頸。
這些處理的核心是路由器服務。那么如果計算節點上自己就能實現路由器服務的話,無疑是更為合理的。這個思路是正確的,但具體實施起來有諸多的考量和細節問題。
為了降低網絡節點的負載,同時提高可擴展性,OpenStack 自 Juno 版本開始正式引入了分布式路由(Distributed Virtual Router,DVR)服務,來讓計算節點自己來處理原先的大量的東西向流量(不同 vpc 的 vm 之間的通信)和 DNAT 流量(有 floating IP 的 vm 跟外面的通信)。
這樣網絡節點只需要處理占到一部分的 SNAT (無 floating IP 的 vm 跟外面的通信)流量,大大降低了負載和整個系統對網絡節點的依賴。
DHCP 服務和 VPN 服務仍然需要集中在網絡節點上進行。這樣的優勢:
(1)東西向流量吞吐量增加。
(2)高東西流量下VM平均帶寬增加。
(3)南北向流量和東西向流量不再互相干擾。
(4)當東西向流量在同一個Hypervisor上,就不會走過不必要的路徑。
注意:openstack 比較新的官方安裝文檔把默認的網絡組件 openvswitch 改為 Linux bridge 了,原因這里不做深究。有資料顯示 dvr只能部署在 ovs 上,這個點需要注意一下。
流量走向
東西向
同一機器
路由器直接在 br-int 上轉發,不經過外部網橋。
不同機器
如圖所示,租戶 T1 的兩個不同子網的 vm:VM1 和 VM4 在不同機器上,VM1 要訪問 VM4,請求過程是計算節點 1 上的 IR1 起到路由器功能。返程的網包,則在計算節點 2 上的路由器 IR2 起作用。
兩個路由器的 id、內部接口、功能等其實都是一樣的。即同一個路由器,但是實際上在多個計算節點上存在。
但是同樣的路由器,如果都暴露在外部網絡上,會出現沖突。例如當請求包離開計算節點 1 時,帶的源應該是目標子網網關的 mac,但這個 mac 在計算節點 2 上同樣存在。
因此,在 br-int 上進行攔截,修改其源 mac 為 tunnel 端口的 mac。同樣的,計算節點 2 在 br-int 上攔截源mac 為這個 tunnel 端口的 mac,替換為正常的子網網關的 mac,直接扔給目標虛擬機。
南北向
無 floating IP(浮動IP)
這種情況(即 SNAT)下,跟傳統模式很類似。
租戶 T2 在外部,通過默認的 SNAT 網關訪問內部子網的 vm VM1。此時,網絡節點上的 T2-SNAT 起到路由器的作用
反過來,租戶 T2 內部子網的 vm VM1 試圖訪問外部網絡,則仍然經過網絡節點上的 T2-SNAT 路由器。
為何這種情況下必須從網絡節點走?這是因為對於外部網絡來說,看到的都是外部接口的地址,這個地址只有一個。
當然,如果以后每個計算節點上都可以帶有這樣一個 SNAT 默認外部地址的話,這種情況下的流量也是可以直接從計算節點出去的。
有 floating IP(浮動IP)
這種情況下,計算節點上的專門負責的外部路由器將負責進行轉發,即計算節點 1 上的 IR2 和計算節點 2上的 IR1。
網絡節點
服務基本沒變動,除了 L3 服務需要配置為 dvr_snat 模式。
命名空間上會多一個專門的 snat-xxx 命名空間,處理來自計算節點的無 floating IP 的南北向流量。
計算節點
需要額外啟用 l3_agent(dvr 模式),以及 metadata agent。
其實,跟傳統情況下的網絡節點十分類似。每個路由器有自己的命名空間,進行跨子網的轉發。
所不同的是,單獨有一個 qfloat-XXX 路由器(也在一個獨立命名空間中)來負責處理帶有 floating IP 的南北向流量。
這里面比較重要的地方,是可能有多個同樣的網關存在於多個計算節點上,因為同一個子網的虛機是可能存在在多個計算節點的。
要解決這個問題,也不難,合理處理好本地的 ARP 請求,讓本地對網關的請求攔截發給本地的路由器即可。
配置樣例
基本部署模型由一個控制器節點,兩個或多個網絡節點和多個計算節點組成。
控制節點配置
1.把以下部分加入/etc/neutron/neutron.conf:
[DEFAULT]
core_plugin = ml2
service_plugins = router
allow_overlapping_ips = True
router_distributed = True
l3_ha = True
l3_ha_net_cidr = 169.254.192.0/18
max_l3_agents_per_router = 3
min_l3_agents_per_router = 2
當配置router_distributed = True標志時,所有用戶創建的路由器是分布式的。 沒有它,只有特權用戶可以使用–distributed True創建分布式路由器。
類似地,當配置l3_ha = True標志時,所有用戶創建的路由器默認為HA。
因此,在配置文件中這兩個標志設置為True,所有用戶創建的路由器將默認為分布式HA路由器(DVR HA)。
同樣可以通過具有管理憑據的用戶在neutron router-create命令中設置標志來顯式實現:
$ neutron router-create name-of-router --distributed=True --ha=True1
max_l3_agents_per_router和min_l3_agents_per_router確定將被實例化的備份DVR / SNAT路由器的數量。
2.把以下部分加入/etc/neutron/plugins/ml2/ml2_conf.ini:
[ml2]
type_drivers = flat,vxlan
tenant_network_types = vxlan
mechanism_drivers = openvswitch,l2population
extension_drivers = port_security
[ml2_type_flat]
flat_networks = external
[ml2_type_vxlan]
vni_ranges = MIN_VXLAN_ID:MAX_VXLAN_ID
將MIN_VXLAN_ID和MAX_VXLAN_ID替換為適用於您的環境的VXLAN ID最小值和最大值。
當常規用戶創建網絡時,tenant_network_types選項中的第一個值將成為默認項目網絡類型。
網絡節點配置
1.配置Open vSwitch代理。 將以下內容添加到/etc/neutron/plugins/ml2/ml2_conf.ini中:
[ovs]
local_ip = TUNNEL_INTERFACE_IP_ADDRESS
bridge_mappings = external:br-ex
[agent]
enable_distributed_routing = True
tunnel_types = vxlan
l2_population = True
將TUNNEL_INTERFACE_IP_ADDRESS替換為處理VXLAN項目網絡的接口的IP地址。
2.配置L3代理。 將以下內容添加到/etc/neutron/l3_agent.ini中:
[DEFAULT]
ha_vrrp_auth_password = password
interface_driver = openvswitch
external_network_bridge =
agent_mode = dvr_snat
external_network_bridge選項故意不包含值。
計算節點配置
[ovs]
local_ip = TUNNEL_INTERFACE_IP_ADDRESS
bridge_mappings = external:br-ex
[agent]
enable_distributed_routing = True
tunnel_types = vxlan
l2_population = True
[securitygroup]
firewall_driver = neutron.agent.linux.iptables_firewall.OVSHybridIptablesFirewallDriver
配置L3代理,將以下內容加入/etc/neutron/l3_agent.ini:
[DEFAULT]
interface_driver = openvswitch
external_network_bridge =
agent_mode = dvr
將TUNNEL_INTERFACE_IP_ADDRESS替換為處理VXLAN項目網絡的接口的IP地址。
已知限制
目前不支持將路由器從僅分布式,僅HA或傳統方式遷移到分布式HA。 路由器必須創建為分布式HA。 也不支持反向。 您不能將分布式HA路由器重新配置為僅分布式,僅HA或傳統方式。
在某些情況下,l2pop和分布式HA路由器不以期望的方式交互。 這些影響HA的路由器和l2pop的情況是相同的。
理想化的流量走向
最理想的流量走向是:
- 網絡節點提供外部流量的訪問,不管vm有沒有浮動IP
- 計算節點外部接口為了安全限制外部訪問,只提供不同 vpc 之間的訪問
但是好像目前 openstack 分布式路由無法做到