標籤:

OpenStack虛機網卡的創建過程

Neutron 系列文章 Neutron Topic Tree:

OpenStack最基本和常用的操作就是啟動虛機。虛機啟動的過程中涉及很多內容,其中非常重要的一個環節就是創建並綁定虛機的虛擬網卡。虛機的創建和管理是Nova的任務,虛機網路的創建和管理是Neutron的任務,而虛機網卡,作為連接虛機和虛機網路的橋樑,其創建和管理則同時涉及了Nova和Neutron。這次介紹一下,OpenStack中虛機的網卡的創建過程。雖然本文的介紹將基於OpenVSwitch,但是你可以發現,很少有特殊於OpenVSwitch的地方,所以其他的二層機制(例如:Linux Bridge)過程都是類似的。

註:本文的所有分析都是基於OpenStack 17年上半年的代碼(Pike版本),因此本文只反應OpenStack在那個時間點的行為。

先假設我們有一個典型的基於OpenVSwitch的OpenStack環境,服務的分布如下。

Neutron L2 Agent上線

首先是所有的服務上線,看neutron-openvswitch-agent的啟動。

  • OpenVSwitch agent 啟動,註冊一個定時程序:neutron.plugins.ml2.drivers.openvswitch.agent.ovs_neutron_agent.OVSNeutronAgent.__init__
  • 在定時程序內部,通過RPC向Neutron Server定時上報自己的狀態:neutron.plugins.ml2.drivers.openvswitch.agent.ovs_neutron_agent.OVSNeutronAgent._report_state
  • 在Neutron Server,對應的RPC處理方法中,Neutron Server將Agent上報的狀態寫入自己的DB:neutron.db.agents_db.AgentExtRpcCallback.report_state

到此為止,Neutron Server知道了Neutron OpenVSwitch Agent的狀態及相關信息,這一步的示意圖如下所示。

設想有這麼一個場景,如果同時有N個計算節點,由於電源問題,這些計算節點同時斷電重啟。那麼當這些計算節點上的OpenVSwitch Agent恢復之後,由於啟動時間比較集中,它們會在一個相對集中的時間點,定時向Neutron Server上報自己的狀態。這涉及到Neutron Server處理RPC請求,寫DB,還有一些邏輯處理。所以當N足夠大時,會周期性的給Neutron Server帶來高負荷。這是實際應用和優化需要注意的一個地方。

創建一個虛機,OpenStack創建邏輯埠(port)

接下來通過調用Nova的REST API創建一個虛機,並且nova scheduler將虛機分布到了計算節點。Nova計算節點上的nova-compute進程會:

  • 調用Neutron REST API創建埠(port):nova.network.neutronv2.api.API.allocate_for_instance
    • 這裡創建埠只是邏輯驗證,Neutron Server會在自己的DB裡面創建一個相應的,基本為空的埠
  • 根據Nova掌握的信息,更新埠:nova.network.neutronv2.api.API._update_ports_for_instance
    • 這裡nova向Neutron傳遞的埠信息包括(列舉一部分):
      • device_id: 虛機的uuid
      • device_owner: 由compute+虛機所在的Nova Availability Zone組成的字元串,例如「compute: nova」
      • dns_name: 虛機的hostname, 通常為虛機name
      • binding:host_id: nova-compute所在的host id,可以是hostname,也可以是IP地址
      • binding:profile: 一些額外的信息,例如SRIOV信息

Neutron Server在收到這些信息之後,主要處理流程如下:

  • nova-compute調用Neutron Server更新埠,請求在這裡處理:neutron.plugins.ml2.plugin.Ml2Plugin.update_port
  • 之後處理port bind:neutron.plugins.ml2.plugin.Ml2Plugin._bind_port
  • 調用到Neutron ML2的Mechanism Manger做port bind:neutron.plugins.ml2.manager.MechanismManager._bind_port_level
  • 再調用到Neutron ML2的OpenVSwitch Mechanism Driver做實際的port bind:neutron.plugins.ml2.drivers.mech_agent.AgentMechanismDriverBase.bind_port
    • 雖然這是個通用類,但是OVS Mechanism Driver繼承自這個類。
    • 在這個方法裡面,會檢查在指定的host上有沒有相應的L2 Agent,所以這一步依賴之前一步的Neutron OpenVSwitch Agent狀態上報
    • 這裡的host信息來自於nova-compute傳遞過來的binding:host_id
  • 將OVS對應的vif_type和vif_details兩個屬性傳遞給port:neutron.plugins.ml2.drivers.mech_agent.SimpleAgentMechanismDriverBase.try_to_bind_segment_for_agent
  • OVS的vif_type和vif_details在OVS Mechanism Driver的初始化函數裡面定義:neutron.plugins.ml2.drivers.openvswitch.mech_driver.mech_openvswitch.OpenvswitchMechanismDriver.__init__
    • 這裡,定義了OVS對應的vif_type是「ovs」,而vif_details包含了一些輔助信息
    • vif_details裡面包含了一個欄位OVS_HYBRID_PLUG,如果這個欄位為True,則最後虛機的網卡和br-int之間會有一個Linux Bridge來應用iptables規則。如果你了解過OpenStack底層OpenVSwitch網卡連接方式,那麼你一定見過下面這張圖,其中淺紫色的qbrXXX,就是因為這個欄位為True才會在後面的步驟被創建。

這部分Neutron的行為都是在ML2中完成,如果你對其中一些概念不清楚,可以參考我之前介紹的ML2架構。這部分除了更新Neutron自身的數據之外,比較重要的就是將vif_type和vif_details作為port的一部分數據,返回給nova-compute。到此為止,虛機的網卡還沒有創建,所有的操作都還只是在邏輯層面,只有資料庫的數據發生了變化。並且,在Neutron的資料庫中,port的狀態現在是Down。但是,Nova和Neutron都知道了接下來要創建的網卡的具體信息,這一步的實際意義在於兩個相對獨立的項目之間的數據同步。現在,OpenStack整體示意圖如下所示:

nova-compute創建虛擬網卡

雖然說Neutron是OpenStack裡面的網路服務項目,但是OpenStack裡面的虛機網卡,卻是由Nova創建的。nova-compute在從Neutron Server拿到了埠的信息之後(通過update port的返回數據):

  • 調用相應的虛擬化Driver,繼續創建虛機:nova.compute.manager.ComputeManager._build_and_run_instance
  • 在Driver內部,創建網路相關內容:nova.virt.libvirt.driver.LibvirtDriver.spawn
  • 在Driver內部,通過調用os-vif庫,創建虛機網卡。由於nova-compute現在已經知道了虛機網卡的所有信息,適用於虛機的網卡被創建出來:nova.virt.libvirt.driver.LibvirtDriver.plug_vifs

至此,虛機的虛擬網卡真正的創建出來了。但是,在Neutron的資料庫中,port的狀態現在是Down。到此為止,OpenStack的整體示意圖如下所示:

Neutron檢測虛擬網卡狀態並更新port狀態

虛機的虛擬網卡被插入到OVS網橋上,對於Neutron來說,接下來就是接管這個網卡。

  • Neutron OpenVSwitch Agent進程中會監聽OVS網橋的狀態:neutron.plugins.ml2.drivers.openvswitch.agent.ovs_neutron_agent.OVSNeutronAgent.rpc_loop
  • 當發現有新增的虛擬網卡時,先從Neutron Server獲取詳細的網卡信息:neutron.plugins.ml2.drivers.openvswitch.agent.ovs_neutron_agent.OVSNeutronAgent.treat_devices_added_or_updated
    • nova-compute在創建虛擬網卡的時候,已經將Neutron port id和一些其他信息寫入到OVS port/interface中,因此Neutron從新增的虛擬網卡就能知道對應的port是那個,下圖是截取的OVS數據,裡面的iface-id就是Neutron port對應的ID

  • Neutron OpenVSwitch Agent本地更新完虛擬網卡之後,再通過RPC通知Neutron Server埠上線:neutron.plugins.ml2.drivers.openvswitch.agent.ovs_neutron_agent.OVSNeutronAgent._bind_devices

至此,Neutron已經接管了虛擬網卡,並且在Neutron的資料庫中,port的狀態現在是Active。Neutron從這個時候開始正式接管虛機網路。OpenStack整體示意圖如下所示:

總結

所以,簡單來說,在OpenStack中,首先需要各個服務上線;之後Nova會創建邏輯網卡,但是Nova只知道虛機所在的host;Neutron會根據所在的host,判斷出相應的網路虛擬化機制,例如ovs,linuxbridge,Neutron會把這些信息回傳給Nova;Nova拿到這些信息,調用相應的方法創建虛擬網卡,並接入到虛機;Neutron會監聽網橋上埠的變化,發現有上線的埠,與自己本身的數據進行匹配,匹配到了之後接管這個虛擬網卡。對於Neutron來說,它不關心虛擬網卡接的是虛機還是容器還是別的什麼,它只能看到虛擬網卡


推薦閱讀:

十分鐘讓你了解OpenStack的前世今生----OpenStack的黃金時代
openstack入門的書該看什麼,求推薦?
2017 OpenStack Summit Day 1 | 開放雲平台在持續實踐中穩步前行
T2Cloud帶你360度玩轉2017OpenStack Summit
openstack未來發展前景怎樣?

TAG:OpenStack |