1. 程式人生 > >Octavia 建立 loadbalancer 的實現與分析

Octavia 建立 loadbalancer 的實現與分析

目錄

文章目錄

從 Octavia API 看起

通過 CLI 建立一個 loadbalancer

(octavia_env) [[email protected] ~]# openstack loadbalancer create --vip-subnet-id 122056f4-0fad-4ab2-bdf9-9b0942d0b213 --name lb1 --debug

在這裡插入圖片描述

Create LB 的 Octavia API UML 圖

在這裡插入圖片描述

其中 2. _validate_vip_request_object 的細節如下 UML 圖

在這裡插入圖片描述

通過 上述 UML 圖可以看出當 octavia-api service 接收到 create loadbalancer 請求後主要處理了下列幾件事情:

  1. 驗證請求使用者的身份。
  2. 驗證請求 VIP 及其相關物件(e.g. port, subnet, network, )是否可用,可以通過 config secition [networking] 來配置 Allow/disallow 的網路物件。
  3. 檢查請求 Project 的 LB 相關 Quota,可以通過 config section [quotas] 來配置預設 Quota。
  4. 準備建立 loadbalancer 資料庫記錄的資料結構。
  5. 建立 loadbalancer 和 vip 的資料庫記錄。
  6. 呼叫 Amphora driver(default lb provider)建立 VIP 對應的 port,並將 Port、VIP、LB 三者的資料庫記錄關聯起來。
  7. 以圖的方式建立 loadbalancer 下屬的 Listeners 和 Pools。
  8. 準備傳遞給 Amphora driver 實際用於 create_loadbalancer_flow 的資料結構。
  9. 非同步呼叫 octavia-cw service 執行 create_loadbalancer_flow。

其中有幾點值得我們額外的注意:

  • 通過 networking 和 quota 使用者可以限制 LBaaS 的資源範圍,e.g. loadbalancer 的個數、listener 的個數 etc… 甚至可以規定使用的 VIP 列表和 VIP 只能在規定的 network/subnet 中建立。

  • 雖然 CLI 並沒有給出類似 --listeners or --pools 的選項讓使用者傳遞 loadbalancer 下屬 Listeners 和 Pools 的 body 屬性,但實際上 POST /v2.0/lbaas/loadbalancers 的檢視函式時可以處理這兩個引數的。所以在 UI 設定的時候可以完成 CLI 不支援的一次性建立 loadbalancer、listener 及 pool 的操作。

  • 建立 loadbalancer 時,如果 VIP 的 port 不存在,那麼 octavia-api 會呼叫 neutronclient 建立,命名規則為 lb-<load_balancer.id>,所以你會在 VIP 的 network/subnet 中看見類似的 Port。

Octavia Controller Worker

在這裡插入圖片描述

這是一個典型的 taskflow 外層封裝,從 get flow、prepare flow store、get flow engine 到最後的 run flow。其中最核心的步驟是 3. self._lb_flows.get_create_load_balancer_flow,想要知道建立 loadbalancer 都做了些什麼事情,就要看看這個 Flow 裡面都有哪些 Task。

在這裡插入圖片描述

這裡我們主要關注為 loadbalancer 準備 Amphora 和 Amphora 的 Networking Setup。

為 loadbalancer 準備 Amphora 的 UML 如下:

在這裡插入圖片描述

為 loadbalancer 準備 Amphora 的過程中有幾點值得我們注意:

  • 如果配置 [controller_worker] loadbalancer_topology = ACTIVE_STANDBY 時,可以結合 [nova] enable_anti_affinity = True 反親和性進一步提高 loadbalancer 的高可用性。
  • 為 loadbalancer 準備 Amphora 並非每次都是通過 create amphora 來實現的,flow 會先檢查是否存在可以對映到 loadbalancer 的 Amphora instance,如果存在就直接對映給 loadbalancer 使用。如果不存在才會啟動建立 Amphora instance 的任務流,這裡需要配合 housekeeping 機制來完成。housekeeping 會根據配置 [house_keeping] spare_amphora_pool_size=2 來準備 spare Amphora instance pool,加速 loadbalancer 的建立流程。
  • 建立 Amphora 使用的是 graph flow(圖流),圖流的特性就是開發者可以自定義條件來控制任務的流向,amp_for_lb_flow.link 就是設定判斷條件的語句,這裡的判斷條件設定為了:如果為 loadbalancer mapping Amphora instance 成功就直接修改資料庫中相關物件的隱射關係,如果 mapping 失敗則先建立 Amphora instance 之後再修改資料庫中相關物件的隱射關係。

為 loadbalancer 的 Amphora 準備 networking 的 UML 如下:

在這裡插入圖片描述

從 UML 可以見 Amphora 的 Networking 主要的工作是為 Amphora 的 Keepalived 設定 VIP,過程中會涉及到大量的 octavia-cw service 與 amphora agent 的通訊。後面我們再繼續深入看看關鍵的 Task 中都做什麼什麼事情。

再繼續看看當 listeners 引數被傳入時的 flow 是怎麼樣的:

在這裡插入圖片描述

建立 Listener 實際上就是更新了 Amphora 內 HAProxy 的配置資訊,所以可見上述最重要的 Task 就是 amphora_driver_task.ListenersUpdate

自此整個 create loadbalancer 的 flow 就都看完了,接下來我們繼續深入到一些關鍵的 Task 裡,看看都做了什麼事情。

database_tasks.MapLoadbalancerToAmphora

為 loadbalancer 建立 amphora 時首先會嘗試 Maps and assigns a load balancer to an amphora in the database,如果 mapping SUCCESS 則會 return amphora uuid 否則為 None。graph flow 型別的 amp_for_lb_flow 就是通過這個 return 來作為任務流向控制判斷條件的。

if None:
    create_amp
else:
    map_lb_to_amp

compute_tasks.CertComputeCreate & ComputeCreate

Task CertComputeCreate & ComputeCreate 都是建立一個 amphora instance,通過配置項 [controller_worker] amphora_driver 進行選擇。當 amphora_driver = amphora_haproxy_rest_driver 時使用 CertComputeCreate,octavia-cw service 與 amphora-agent 之間通過 HTTPS 進行安全通訊;當 amphora_driver = amphora_noop_driver 時使用後者,但 amphora_noop_driver 一般被用作測試,可以忽略不計。

            compute_id = self.compute.build(
                name="amphora-" + amphora_id,
                amphora_flavor=CONF.controller_worker.amp_flavor_id,
                image_id=CONF.controller_worker.amp_image_id,
                image_tag=CONF.controller_worker.amp_image_tag,
                image_owner=CONF.controller_worker.amp_image_owner_id,
                key_name=key_name,
                sec_groups=CONF.controller_worker.amp_secgroup_list,
                network_ids=network_ids,
                port_ids=[port.id for port in ports],
                config_drive_files=config_drive_files,
                user_data=user_data,
                server_group_id=server_group_id)

這裡呼叫了 novaclient 的封裝來建立 amphora instance,其中 image、flavor、sec_groups、keypair 均在配置 [controller_worker] 中定義了。需要注意的是 config_drive_files 和 user_data 兩個形參就是為了 amphora instance 啟動時為 amphora-agent 注入證書的引數項,應用了 Nova Store metadata on a configuration drive 機制。

config_drive_files = {
            '/etc/octavia/certs/server.pem': server_pem,
            '/etc/octavia/certs/client_ca.pem': ca}

network_tasks.AllocateVIP

Task AllocateVIP 實際呼叫了 octavia.network.drivers.neutron.allowed_address_pairs:AllowedAddressPairsDriver.allocate_vip method,return 的是一個建立了 Port、VIP 和 LB 三者關係的 data_models.Vip 物件。該 method 在 octavia-api 已經被呼叫過一次了,所以到此時 VIP 的 Port 一般都已經存在了,只需要返回一個 data object 即可。然後在通過 Task UpdateAmphoraVIPData 落庫持久化。

network_tasks.PlugVIP

Task PlugVIP 是實際為 Amphora instance(s) 設定 VIP 的。

在這裡插入圖片描述

在 PlugVIP 的過程中需要注意幾點:

  • 在建立 Listener 時都會 update VIP port 的 security_group_rules,因為 Listener 是依附於 VIP 的,所以 Listener 監聽的協議埠都應該在 VIP 的安全組上開啟,並且關閉不必要的埠。
  • PlugVIP 會輪詢檢查所有 loadbalancer.amphora 是否具有 VIP 對應的 Port,如果沒有則會創建出來,設定 VIP 再掛載到 Amphora instance 上。

NOTE:VIP 是 Act/Stby topo Amphora 的虛擬 IP。

最後

至此 Octavia 建立 loadbalancer 的流程就分析分完了,總的來說一圖頂千言,還是希望通過 UML 圖來描述主要流程再輔以文字說明關鍵點的方式來進行介紹。