Slide 1

Slide 1 text

設計Kubernetes Controller與CRD的實踐 - 以網路為例 黃宇強 Date Huang @ COSCUP 2023/07/29 @ Kubernetes Community Day Taiwan 2023

Slide 2

Slide 2 text

About Me ● 黃宇強 Date Huang ● [email protected] ● EZIO Maintainer

Slide 3

Slide 3 text

Agenda ● 試著設計一個Kubernetes Network Controller ○ 以補足Bridge CNI的需求為範例 ○ 做CRDs的分析與設計 ● 比較一下其他網路實現的差異 ○ Nmstate.io ● 順便比較一下其他種類Kubernetes Controller常見的設計與做法 ○ Kubevirt

Slide 4

Slide 4 text

情境 ● Bridge CNI還需要部份的手動設定,才能讓整個Bridge Network 可以正常運作 ○ 例如說,需要手動建立Bridge,然後手動設定一個對外的介 面讓網路通行 ● 你可能會有多種的網路型態都用Bridge CNI來實現 ○ 例如說VLAN Bridge、VXLAN Overlay Network等等 ● 這邊我們用Kubernetes + Kubevirt做VM Cluster來探討網路需求

Slide 5

Slide 5 text

最開始 ● 首先我們思考,Bridge需要一個名稱 ● 需要對外的一個或多個網路介面,可能需要鏈路聚合(Bonding) ○ 也可以上面都套一層Bonding,讓一個或多個網路介面統一 成一個Bonding介面 ● 因為每個節點都要設定此網路配置,所以Controller必須要是 DaemonSet跑在全部節點上面

Slide 6

Slide 6 text

最開始 apiVersion: kvnet.kojuro.date/v1alpha1 kind: Bridge metadata: name: br0 spec: vlanFiltering: true uplink: mode: active-backup nics: - eth0 - eth1 Node1 Bridge Controller eth0 eth1 bond0 br0 Node2 Bridge Controller eth0 eth1 bond0 br0 Node3 Bridge Controller eth0 eth1 bond0 br0

Slide 7

Slide 7 text

最開始 apiVersion: kvnet.kojuro.date/v1alpha1 kind: Bridge metadata: name: br0 spec: vlanFiltering: true uplink: mode: active-backup nics: - eth0 - eth1 Node1 Bridge Controller eth0 eth1 bond0 br0 Node2 Bridge Controller eth0 eth1 bond0 br0 Node3 Bridge Controller eth0 eth1 bond0 br0 Watch Configure

Slide 8

Slide 8 text

使用者體驗 ● 使用者能設定的情況比較單一,只有同質性叢集能使用 ○ 因為全部節點共享一份設定 ○ 兩個以上的元件放在同一個設定檔,必須同時設定 ■ Bridge & Bonding & Ethernet ● 設定上簡易 ○ 因為只要一份設定,就設定全部的項目

Slide 9

Slide 9 text

拆出每個節點 ● 因為不同節點可能會有不同設定,所以要把Bridge CRD做一層拆 解 ○ 例如說Group A只有br0,或是Group B只有br1等等的 ○ 或是Group A跟Group B都要br0,但是對外的網路介面名稱 不同 ● 並使用Node Selector來選擇節點 ○ 透過Label來選擇特定的節點 ○ 例如說:kubernetes.io/arch: amd64

Slide 10

Slide 10 text

拆出每個節點 ● 因為不同設定可能會設定相同的Bridge名稱,所以需要多一個欄 位來設定Bridge Name,不能直接使用CRD Name的欄位 ● 但是因為Reconcile機制,如果更改Bridge Name欄位,Controller 不會知道舊的名稱,所以無法清除舊的資源 ○ 可以選擇,禁止更改Bridge Name ○ 或是再次拆解成兩個CRD,做關聯處理 ○ 或是不勉強一定都要在Controller內完成,透過其他軟體偕 同處理

Slide 11

Slide 11 text

Operator-SDK Reconcile Example func (r *MemcachedReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { _ = context.Background() ... // Lookup the Memcached instance for this reconcile request memcached := &cachev1alpha1.Memcached{} err := r.Get(ctx, req.NamespacedName, memcached) ... }

Slide 12

Slide 12 text

拆出每個節點 ● 重新設計資料結構成兩個部分 ● BridgeConfig ○ 負責選擇節點,並新增/更新/移除Bridge CR ○ 紀錄Bridge的樣板 ○ 角色類似於DaemonSet ● Bridge ○ 實際上執行新增/更新/移除Linux上的bridge ○ 實際紀錄Bridge的屬性跟設定 ○ 角色類似於Pod

Slide 13

Slide 13 text

拆出每個節點 apiVersion: kvnet.kojuro.date/v1alpha1 kind: BridgeConfig metadata: name: br0-group-a spec: nodeSelector: matchLabels: kvnet.kojuro.date/group: GroupA bridgeName: br0 template: spec: vlanFiltering: true uplink: mode: active-backup nics: - eth0 apiVersion: kvnet.kojuro.date/v1alpha1 kind: Bridge metadata: labels: bridgeconfig: br0-group-a name: node1.br0 spec: vlanFiltering: true uplink: mode: active-backup nics: - eth0 --- apiVersion: kvnet.kojuro.date/v1alpha1 kind: Bridge metadata: labels: bridgeconfig: br0-group-a name: node2.br0 spec: vlanFiltering: true uplink: mode: active-backup nics: - eth0 Create Bridge Spec from Template

Slide 14

Slide 14 text

Node1 Bridge Controller eth0 eth1 bond0 br0 Node2 Bridge Controller eth0 eth1 bond0 br0 Node3 Bridge Controller eth0 eth1 BridgeConfig Con BridgeConfig br0-group-a Bridge node1.br0 Bridge node2.br0 Check Create 2 Bridges

Slide 15

Slide 15 text

Node1 Bridge Controller eth0 eth1 bond0 br0 Node2 Bridge Controller eth0 eth1 bond0 br0 Node3 Bridge Controller eth0 eth1 BridgeConfig Con BridgeConfig br0-group-a Bridge node1.br0 Bridge node2.br0 Get Bridge for Node1 Create

Slide 16

Slide 16 text

如果改Bridge Name ● BridgeConfig會新增新的Bridge ● 同時用Label Selector把所有關聯自己的Bridge取出 ● 如果非當下BridgeName,就可以認定是舊的版本,進而刪除 Bridge ● Bridge Controller也因為刪除Bridge,所以將舊的Linux Bridge從 系統上移除

Slide 17

Slide 17 text

把Uplink從Bridge中獨立出來 ● Bridge跟Uplink兩個都可以獨立使用,並不一定互相依賴彼此 ○ Bridge也可以跟VXLAN同時使用,而不需要Uplink ○ Uplink可以獨立使用,作為VXLAN的隧道端點 ● BridgeConfig跟Bridge應該只負責Linux Bridge相關的設定 ● Uplink也可能根據不同節點有不同設定

Slide 18

Slide 18 text

設計UplinkConfig & Uplink ● UplinkConfig ○ 負責選擇節點,並新增/更新/移除Uplink CR ○ 紀錄Uplink的樣板 ● Uplink ○ 實際上執行新增/更新/移除Linux上的Bond ○ 實際紀錄Bonding的屬性跟設定 ● BridgeConfig & Bridge也需要移除跟Uplink相關的欄位

Slide 19

Slide 19 text

修正BridgeConfig & Bridge apiVersion: kvnet.kojuro.date/v1alpha1 kind: BridgeConfig metadata: name: br0-group-a spec: nodeSelector: matchLabels: kvnet.kojuro.date/group: GroupA bridgeName: br0 template: spec: vlanFiltering: true apiVersion: kvnet.kojuro.date/v1alpha1 kind: Bridge metadata: labels: bridgeconfig: br0-group-a name: node1.br0 spec: vlanFiltering: true --- apiVersion: kvnet.kojuro.date/v1alpha1 kind: Bridge metadata: labels: bridgeconfig: br0-group-a name: node2.br0 spec: vlanFiltering: true

Slide 20

Slide 20 text

UplinkConfig & Uplink apiVersion: kvnet.kojuro.date/v1alpha1 kind: UplinkConfig metadata: name: bond0-group-a spec: nodeSelector: matchLabels: kvnet.kojuro.date/group: GroupA bondName: bond0 template: spec: master: br0 mode: active-backup nics: - eth0 apiVersion: kvnet.kojuro.date/v1alpha1 kind: Uplink metadata: labels: uplinkconfig: bond0-group-a name: node1.bond0 spec: master: br0 mode: active-backup nics: - eth0 --- apiVersion: kvnet.kojuro.date/v1alpha1 kind: Uplink metadata: labels: uplinkconfig: bond0-group-a name: node2.bond0 spec: master: br0 mode: active-backup nics: - eth0

Slide 21

Slide 21 text

Node1 Bridge Controller eth0 eth1 bond0 br0 Node2 Bridge Controller eth0 eth1 bond0 br0 Node3 Bridge Controller eth0 eth1 BridgeConfig Ctl BridgeConfig br0-group-a Bridge node1.br0 Bridge node2.br0 Uplink Controller UplinkConfig Ctl UplinkConfig bond0-group-a Uplink node1.bond0 Uplink node2.bond0 Uplink Controller Uplink Controller

Slide 22

Slide 22 text

使用者體驗 ● 我們回頭分析一下使用者體驗 ● 使用者可以做更多形式且彈性的設定 ○ 因為設定都是獨立存在 ● 使用者如果希望提供給Kubevirt VM使用的網路,需要: ○ 新增BridgeConfig ○ 新增UplinkConfig ● 使用者設定方面變的比較複雜一些 ○ 這時可以考慮提供WebUI Wizard或是CLI等等的方式,引導 使用者作出完整設定

Slide 23

Slide 23 text

設計模式 ● 在這個設計模式下,擴充VXLAN的設計基本上也可以參照Uplink 設計出來 ● 檢視CRDs欄位的設計 ○ 將CRDs內的欄位關聯拆解 ○ 避免多個Controller需要監看與覆寫同一CRD ● 需考量Kubernetes Controller的觸發模式與Reconcile執行方式 ○ 例如說:不能在Reconcile裡面sleep等待,會直接卡住整個 workqueue流程

Slide 24

Slide 24 text

VXLAN apiVersion: kvnet.kojuro.date/v1alpha1 kind: VxlanConfig metadata: name: vxlan-group-a spec: nodeSelector: matchLabels: kvnet.kojuro.date/group: GroupA Vxlaname: vxlan10 template: spec: vxlanId: 10 master: vxbr10 apiVersion: kvnet.kojuro.date/v1alpha1 kind: Vxlan metadata: labels: vxlanconfig: vxlan-group-a name: node1.vxlan10 spec: vxlanId: 10 master: vxbr10 --- apiVersion: kvnet.kojuro.date/v1alpha1 kind: Vxlan metadata: labels: vxlanconfig: vxlan-group-a name: node2.vxlan10 spec: vxlanId: 10 master: vxbr10

Slide 25

Slide 25 text

設計模式 ● 相較最初版的設計: ○ 可以針對不同節點做不同設定 ○ 每個獨立元件分離,皆可獨立使用 ○ 新增元件的複雜度下降 ○ 每一個CRD與Controller的責任範圍就限縮在該元件本身, 程式碼複雜度會下降,除錯也會相對容易

Slide 26

Slide 26 text

未來設計模式 ● 其實還需要做更多的拆分 ○ 例如說:Uplink中的slaves其實應該拆分成NetDevice,然後 NetDevice有master指向Uplink,讓NetDevice同時可以做 SR-IOV相關的設定等等的 ● 基於CNI的實現跟執行方式,其實會有很多時候會對某些資源失 去控制,所以需要額外做處理 ○ 例如說:Bridge CNI建立Veth Pair之後,Controller沒有機會 得知Veth名稱來做未來的修改等等的

Slide 27

Slide 27 text

程式碼參考 ● 透過上述的設計模式,可以實作出容易維護與新增功能的網路控 制器,使用上也無須外部程式碼的協助 ● 可以參考demo專案kvnet ○ https://github.com/tjjh89017/kvnet ● 註:kvnet還有部分實作未完成

Slide 28

Slide 28 text

比較一下其他設計

Slide 29

Slide 29 text

比較一下Nmstate.io差異 ● 分析Nmstate.io提供的Kubernetes網路設定 ● 也同樣提供NodeSelector來選擇特定幾個節點 ● 直接依賴NetworkManager(NM)來管理所有網路狀態 ● 一份設定檔案可以設定多個網路介面

Slide 30

Slide 30 text

Nmstate.io Example apiVersion: nmstate.io/v1 kind: NodeNetworkConfigurationPolicy metadata: name: detach-bridge-port-and-restore-eth spec: desiredState: interfaces: - name: br1 type: linux-bridge state: absent - name: eth1 type: ethernet state: up ipv4: dhcp: true enabled: true

Slide 31

Slide 31 text

分析Nmstate.io ● 直接依賴NetworkManager(NM)來管理所有網路狀態 ○ 對Nmstate.io Controller來說,只負責推送目前期望的設定 給NetworkManager,由NM來負責新增移除設定 ○ 剩下的部分,Nmstate.io Controller一律不管 ● 一份設定檔案可以設定多個網路介面 ○ 因為先前狀態與目前狀態之間的差異,全部由 NetworkManager以及Nmstatectl管理,所以不需要透過 CRDs來儲存或是管理相關需要清理的狀態 ○ 所以一份設定檔並不會造成問題

Slide 32

Slide 32 text

Nmstate.io Code ● Reconcile ○ https://github.com/nmstate/kubernetes-nmstate/blob/8293b460d92f2944c76c62287354e545 80ae0485/controllers/handler/nodenetworkconfigurationpolicy_controller.go#L226 ● Push Network Config to NetworkManager ○ https://github.com/nmstate/kubernetes-nmstate/blob/8293b460d92f2944c76c62287354e545 80ae0485/pkg/client/client.go#L152

Slide 33

Slide 33 text

分析Kubevirt ● 最主要由virt-handler作為Controller,來監看CRDs的更改 ● 通知並透過virt-launcher來維護VM狀態 ○ 從libvirt API中取得現在VM設備狀態,取得CRDs的設定內 容,確認可熱插拔的部分進行比較,並執行熱插拔 ○ https://github.com/kubevirt/kubevirt/blob/690d37d220c0 4fa40ebafc00c33d1e78cc1b3983/pkg/virt-launcher/virtw rap/manager.go#L961

Slide 34

Slide 34 text

Kubernetes Controller主流做法 ● Config-based Controller ○ Nmstate.io ○ Kubevirt ● All on Kuberbetes Controller ○ 我開頭的範例設計 kvnet ○ Kube-ovn

Slide 35

Slide 35 text

Kubernetes Controller主流做法 ● Config-based Controller ○ 權責分離,只負責推設定,其他部分由外部軟體負責處置 ○ 分開維護,也比較容易抓錯誤的落點 ○ 需要確保SSOT原則 ● All on Kuberbetes Controller ○ 把CRDs當作一種資料庫來處理,可能需要部份正規化 ○ 所有項目依賴Controller Reconcile機制 ○ 複雜度相對較高

Slide 36

Slide 36 text

結論 ● 比較推薦Config-based Controller的設計模式 ● 元件之間關聯簡單 ● CRDs設計相對也容易 ● 比較容易除錯 ● 不會受限於Reconcile的機制

Slide 37

Slide 37 text

Q&A ● Any Questions?

Slide 38

Slide 38 text

Ref ● https://github.com/nmstate/kubernetes-nmstate/blob/main/pkg/client/client.go#L152 ● The Kubernetes NMState project ● KubeVirt 源码阅读(二):virt-handler 源码解读 ● Controller reconcile function | Kube by Example