從 K8S 的 Cloud Provider 到 CCM 的演進之路

  • 2019 年 12 月 6 日
  • 筆記

| 為 | 容 | 器 | 技 | 術 | 而 | 生 |

作者:毛宏斌 / 百度高級研發工程師 編輯:小君君

Kubernetes 是一個雲原生平台,但為了讓 Kubernetes 能夠更好地運行在公有雲平台上,能夠靈活地使用、管理雲上其他的基礎資源和基礎服務,雲廠商需要實現自己的適配器。本文詳細解讀了 Kubernetes 從 Cloud Provider 到 Cloud Controller Mananger(CCM) 的演變過程及其實現細節,希望有助於大家更好地在公有雲平台上構建基於 Kubernetes 的容器服務。

Cloud Provider 背景概要

基於 Kubernetes 的容器雲

容器雲最主要的功能是幫助用戶把所有的應用以容器的形式在集群中跑起來。目前很多的容器雲平台通過 Docker 及 Kubernetes 等技術給應用提供運行平台,從而實現運維自動化、快速部署應用、彈性伸縮和動態調整應用環境資源,提高研發運營效率。

Cloud Provider 與雲廠商

為了更好地讓 Kubernetes 在公有雲平台上運行,並且提供容器雲服務,雲廠商需要實現自己的 Cloud Provider,即實現:

cloudprovider.Interface(https://github.com/kubernetes/kubernetes/blob/master/pkg/cloudprovider/cloud.go)。

它是 Kubernetes 中開放給雲廠商的通用介面,便於 Kubernetes 自動管理和利用雲服務商提供的資源,這些資源包括虛擬機資源、負載均衡服務、彈性公網 IP、存儲服務等。

如下圖所示,Kubernetes 核心庫內置了很多主流雲廠商的實現,包括 AWS、GCE、Azure:

Cloud Provider 的重構之路

近幾年來, Kubernetes 逐漸成為在私有雲、公有雲和混合雲環境中大規模部署容器化應用的事實標準,以至於越來越多的雲廠商加入了進來,而 Cloud Provider 的實現也越來越多。

作為在 Kubernetes 核心庫中的程式碼,這必將影響其快速更新和迭代。 所以產生了把 Cloud Provider 移出 Kubernetes 核心庫並進行重構的提案(Refactor Cloud Provider out of Kubernetes Core)。

在 Kubernetes v1.6,引入了 Cloud Controller Manager(CCM),目的就是最終替代 Cloud Provider。截止到最新的 Kubernetes v1.11,還是處於 beta 階段。

Cloud Provider 解析

Cloud Provider 的作用

在 Kubernetes 中有三個組件對 Cloud Provider 有依賴,分別是:

  • kube-controller-manager
  • kubelet
  • kube-apiserver

這三個組件對 Cloud Provider 的依賴部分會最終編譯進相應的二進位中,詳細的依賴關係圖如下所示:

kube-controller-manager 對於 Cloud Provider 的依賴

kube-controller-manager 對 Cloud Provider 的依賴分布在四個 Controller 中。

  • Node Controller:Node Controller 使用 Cloud Provider 來檢查 Node 是否已經在雲上被刪除了。如果 Cloud Provider 返回有 Node 被刪除,那麼 Node Controller 立馬就會把此 Node 從 Kubernetes 中刪除。
  • Route Controller:用來配置 Node 的路由。Kubernetes 容器網路基本原則 [每個 Pod 都擁有一個獨立的 IP 地址(IP per Pod),而且假定所有的 Pod 都在一個可以直接連通的、扁平的網路空間中。而在雲上,Node 的基礎設施是由雲廠商提供的,所以 Route Controller 需要調用 Cloud Provider 來配置雲上的 Node 的底層路由。]
  • Service Controller:Service Controller 不光維護了當前可用 Node 的列表,而且它同時負責創建、刪除、更新類型是 LoadBalancer 的 Service、使用雲廠商額外提供的負載均衡服務、彈性公網 IP 等。
  • PersistentVolumeLabel Controller:PersistentVolumeLabel Controller 使用 Cloud Provider 來創建、刪除、掛載、卸載 Node 上的卷,這是因為卷也是雲廠商額外提供的雲存儲服務。

kubelet 對於 Cloud Provider 的依賴

kubelet 中的 Node Status 使用 Cloud Provider 來獲得 Node 的資訊。包括:

  • nodename:運行 kubelet 的節點名字
  • InstanceID, ProviderID, ExternalID, Zone Info(在初始化 kubelet 的時候需要)
  • 周期性同步的 Node 的 IP

kube-apiserver 對於 Cloud Provider 的依賴

kube-apiserver 使用 Cloud Provider 來給所有 Node 派發 SSH Keys。

Cloud Provider 的設計

雲廠商在實現自己的 Cloud Provider 時只需要實現 cloudprovider.Interface 即可,如下:

在此重點闡述兩個比較重要的介面 LoadBalancer() 與 Routes()。

LoadBalancer() 的介面設計

LoadBalancer() 介面用來為 kube-controller-manager 的 Service Controller 服務,介面說明如下:

Routes() 的介面設計

Routes() 介面用來為 kube-controller-manager 的 Route Controller 服務,介面說明如下:

Cloud Provider 的演變之路

從 Kubernetes v1.6 開始,Kubernetes 的編譯產物中多了一個二進位:cloud-controller manager,它就是用來替代 Cloud Provider 。

因為原先的 Cloud Provider 與 Mater 中的組件 kube-controller-manager、kube-apiserver 以及 Node 中的組件 kubelet 耦合很緊密,所以這三個組件也需要進行重構。

kube-controller-manager 的重構策略

kube-controller-manager 中有四個 controller 與 Cloud Provider 相關,相應的重構策略如下:

  • Route Controller
  • 移入 CCM,並在相應的 controller loop 中運行。
  • Service Controller
  • 移入 CCM,並在相應的 controller loop 中運行。
  • PersistentVolumeLabel Controller
  • 移入 CCM,並在相應的 controller loop 中運行。
  • Node Controller
  • 在 CCM 中增加新 controller:Cloud Node Controller。
  • Cloud Node Controller 除了實現原來 Node Controller 的功能外,增加新功能:
    • CIDR 的管理
    • 監控節點的狀態
    • 節點 Pod 的驅逐策略

kube-apiserver 的重構策略

對於 kube-apiserver 使用 Cloud Provider 的兩個功能:

  • 分發 SSH Keys
  • 移入 CCM
  • 對於 PV 的 Admission Controller
  • 在 kubelet 中實現

kubelet的重構策略

kubelet 需要增加一個新功能:在 CCM 還未初始化 kubelet 所在節點時,需標記此節點類似「 NotReady 」的狀態,防止 scheduler 調度 Pod 到此節點時產生一系列錯誤。此功能通過給節點加上如下 Taints 並在 CCM 初始化後刪去此 Taints 來實現:

Cloud Controller Manager 解析

Cloud Controller Manager 架構

按照上述方法進行重構後,新的模組 Cloud Controller Manager 將作為一個新的組件直接部署在集群內,如下圖所示:

CCM 組件內各小模組的功能與原先 Cloud Provider 的差不多(見第二部分對 Cloud Provider 的解析)。

對於雲廠商來說,需要:

  • 實現 cloudprovider.Interface 介面的功能,這部分在 Cloud Provider 中已經都實現,直接遷移便可。
  • 實現自己的 Cloud Controller Manager,並在部署 Kubernetes 時,把 CCM 按要求部署在集群內(部署時的注意事項及部署參考實踐見第五部分)。

Cloud Controller Manager 實現舉例

Cloud Controller Manager 實現舉例如下:

Cloud Controller Manager 的部署

總體要求

  • 雲廠商提供給 CCM 的 API 需要有認證鑒權機制,防止惡意行為的發生;
  • 因為 CCM 運行在集群內,所以需要 RBAC 規則去跟 kube-apiserver 進行通訊;
  • 為了提高 CCM 的可用,可選擇主功能。

K8S 相關組件的啟動配置變化

將 Cloud Provider 改為 CCM 後,相關組件啟動的配置需要修改。

kube-controller-manager 啟動配置變化

不指定 cloud-provider。

kube-apiserver 啟動配置變化

  • 不指定 cloud-provider
  • 在 admission-control 中刪去 PersistentVolumeLabel
  • admission-control 中增加 Initializers
  • runtime-config 中增加 admissionregistration.k8s.io/v1alpha1

kubelet 啟動配置變化

指定 cloud-provider=external,在 kubelet 被調度之前需要被 CCM 初始化。(Node 會被打上 Taints:node.cloudprovider.kubernetes.io/uninitialized=true:NoSchedule)

啟動 CCM 舉例

啟用 initializers 並添加 InitializerConifguration

CCM 為了給 PV 打標籤需要:

  • 啟用 initializers (https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#enable-initializers-alpha-feature)
  • 添加 InitializerConifguration:persistent-volume-label-initializer-config.yaml 如下:

創建 CCM 的 RBAC

啟動 CCM

可以通過 DaemonSet 或者 Deployment 的方式啟動 CCM:

參考文獻:

1.https://kubernetes.io/docs/tasks/administer-cluster/running-cloud-controller/

2.https://github.com/kubernetes/community/blob/master/contributors/design-proposals/cloud-provider/cloud-provider-refactoring.md

3.https://kubernetes.io/docs/concepts/cluster-administration/cloud-providers/

作者簡介:

毛宏斌,百度高級研發工程師,從事百度雲容器引擎。

歡迎投稿

如果你對 Kubernetes 技術有深入解讀,如果你對行業潮流有獨到的見解,如果你只是單純的有話要說,趕緊發郵件到 [email protected] 來投稿吧。也許你與行業 KOL 只差這一封郵件……

郵件請附:

  • ‍姓名、電話或微訊號、郵箱
  • 100 字左右的個人簡介
  • 可附個人技術部落格或 GitHub 主頁‍