vivo大規模 Kubernetes 叢集自動化運維實踐

語言: CN / TW / HK

作者:vivo 網際網路伺服器團隊-Zhang Rong

一、背景

隨著vivo業務遷移到K8s的增長,我們需要將K8s部署到多個數據中心。如何高效、可靠的在資料中心管理多個大規模的K8s叢集是我們面臨的關鍵挑戰。kubernetes的節點需要對OS、Docker、etcd、K8s、CNI和網路外掛的安裝和配置,維護這些依賴關係繁瑣又容易出錯。

以前叢集的部署和擴縮容主要通過ansible編排任務,黑屏化操作、配置叢集的inventory和vars執行ansible playbook。叢集運維的主要困難點如下:

  • 需要人工黑屏化叢集運維操作,存在操作失誤和叢集配置差異。
  • 部署指令碼工具沒有具體的版本控制,不利於叢集的升級和配置變更。
  • 部署指令碼上線需要花費大量的時間驗證,沒有具體的測試用例和CI驗證。
  • ansible任務沒有拆分為模組化安裝,應該化整為零。具體到K8s、etcd、addons的等角色的模組化管理,可以單獨執行ansible任務。
  • 主要是通過二進位制部署,需要自己維護一套叢集管理體系。部署流程繁瑣,效率較低。
  • 元件的引數管理比較混亂,通過命令列指定引數。K8s的元件最多有100以上的引數配置。每個大版本的迭代都在變化。

本文將分享我們開發的Kubernetes-Operator,採用K8s的宣告式API設計,可以讓叢集管理員和Kubernetes-Operator的CR資源進行互動,以簡化、降低任務風險性。只需要一個叢集管理員就可以維護成千上萬個K8s節點。

二、叢集部署實踐

2.1 叢集部署介紹

主要基於ansible定義的OS、Docker、etcd、k8s和addons等叢集部署任務。

主要流程如下:

  1. Bootstrap OS
  2. Preinstall step
  3. Install Docker
  4. Install etcd
  5. Install Kubernetes Master
  6. Install Kubernetes node
  7. Configure network plugin
  8. Install Addons
  9. Postinstall setup

上面看到是叢集一鍵部署關鍵流程。當在多個數據中心部署完K8s集群后,比如叢集元件的安全漏洞、新功能的上線、元件的升級等對線上叢集進行變更時,需要小心謹慎的去處理。我們做到了化整為零,對單個模組去處理。避免全量的去執行ansible指令碼,增加維護的難度。針對如Docker、etcd、K8s、network-plugin和addons的模組化管理和運維,需提供單獨的ansible指令碼入口,更加精細的運維操作,覆蓋到叢集大部分的生命週期管理。同時kubernetes-operator的api設計的時候可以方便選擇對應操作yml去執行操作。

叢集部署優化操作如下:

(1)K8s的元件引數管理通過ConmponentConfig[1]提供的API去標識配置檔案。

  • 【可維護性】當元件引數超過50個以上時配置變得難以管理。
  • 【可升級性】對於升級,版本化配置的引數更容易管理。因為社群一個大版本的引數沒有變化。
  • 【可程式設計性】可以對元件(JSON/YAML)物件的模板進行修補。如果你啟用動態kubelet配置選項,修改引數會自動生效,不需要重啟服務。
  • 【可配置性】許多型別的配置不能表示為key-value形式。

(2)計劃切換到kubeadm部署

  • 使用kubeadm對K8s叢集的生命週期管理,減少自身維護叢集的成本。
  • 使用kubeadm的證書管理,如證書上傳到secret裡減少證書在主機拷貝的時間消耗和重新生成證書功能等。
  • 使用kubeadm的kubeconfig生成admin kubeconfig檔案。
  • kubeadm其它功能如image管理、配置中心upload-config、自動給控制節點打標籤和汙點等。
  • 安裝coredns和kube-proxy addons。

(3)ansible使用規範

  • 使用ansible自帶模組處理部署邏輯。
  • 避免使用hostvars。
  • 避免使用delegate_to。
  • 啟用–limit 模式。
  • 等等。

2.2 CI 矩陣測試

部署出來的叢集,需要進行大量的場景測試和模擬。保證線上環境變更的可靠性和穩定性。

CI矩陣部分測試案例如下。

(1)語法測試:

  • ansible-lint
  • shellcheck
  • yamllint
  • syntax-check
  • pep8

(2)叢集部署測試:

  • 部署叢集
  • 擴縮容控制節點、計算節點、etcd
  • 升級叢集
  • etcd、Docker、K8s和addons引數變更等

(3)效能和功能測試:

  • 檢查kube-apiserver是否正常工作
  • 檢查節點之間網路是否正常
  • 檢查計算節點是否正常
  • K8s e2e測試
  • K8s conformance 測試
  • 其他測試

這裡利用了GitLab、gitlab-runner[2]、ansible和kubevirt[3]等開源軟體構建了CI流程。

詳細的部署步驟如下:

  1. 在K8s叢集部署gitlab-runner,並對接GitLab倉庫。
  2. 在K8s叢集部署Containerized-Data-Importer (CDI)[4]元件,用於建立pvc的儲存虛擬機器的映像檔案。
  3. 在K8s叢集部署kubevirt,用於建立虛擬機器。
  4. 在程式碼倉庫編寫gitlab-ci.yaml[5], 規劃叢集測試矩陣。

圖片

如上圖所示,當開發人員在GitLab提交PR時會觸發一系列操作。這裡主要展示了建立虛擬機器和叢集部署。其實在我們的叢集還部署了語法檢查和效能測試gitlab-runner,通過這些gitlab-runner建立CI的job去執行CI流程。

具體CI流程如下:

  1. 開發人員提交PR。
  2. 觸發CI自動進行ansible語法檢查。
  3. 執行ansible指令碼去建立namespace,pvc和kubevirt的虛擬機器模板,最終虛擬機器在K8s上執行。這裡主要用到ansible的K8s模組[6]去管理這些資源的建立和銷燬。
  4. 呼叫ansible指令碼去部署K8s叢集。
  5. 叢集部署完進行功能驗證和效能測試等。
  6. 銷燬kubevirt、pvc等資源。即刪除虛擬機器,釋放資源。

圖片

如上圖所示,當開發人員提交多個PR時,會在K8s叢集中建立多個job,每個job都會執行上述的CI測試,互相不會產生影響。這種主要使用kubevirt的能力,實現了K8s on K8s的架構。

kubevirt主要能力如下:

  • 提供標準的K8s API,通過ansible的K8s模組就可以管理這些資源的生命週期。
  • 複用了K8s的排程能力,對資源進行了管控。
  • 複用了K8s的網路能力,以namespace隔離,每個叢集網路互相不影響。

三、Kubernetes-Operator 實踐

3.1 Operator 介紹

Operator是一種用於特定應用的控制器,可以擴充套件 K8s API的功能,來代表K8s的使用者建立、配置和管理複雜應用的例項。基於K8s的資源和控制器概念構建,又涵蓋了特定領域或應用本身的知識。用於實現其所管理的應用生命週期的自動化。

總結 Operator功能如下:

  1. kubernetes controller
  2. 部署或者管理一個應用,如資料庫、etcd等
  3. 使用者自定義的應用生命週期管理
  • 部署
  • 升級
  • 擴縮容
  • 備份
  • 自我修復
  • 等等

3.2 Kubernetes-Operator CR 介紹

圖片

kubernetes-operator的使用很多自定義的CR資源和控制器,這裡簡單的介紹功能和作用。

【ClusterDeployment】: 管理員配置的唯一的CR,其中MachineSet、Machine和Cluster它的子資源或者關聯資源。ClusterDeployment是所有的配置引數入口,定義瞭如etcd、K8s、lb、叢集版本、網路和addons等所有配置。

【MachineSet】:叢集角色的集合包括控制節點、計算節點和etcd的配置和執行狀態。

【Machine】:每臺機器的具體資訊,包括所屬的角色、節點本身資訊和執行的狀態。

【Cluster】:和ClusterDeployment對應,它的status定義為subresource,減少

clusterDeployment的觸發壓力。主要用於儲存ansible執行器執行指令碼的狀態。

【ansible執行器】:主要包括K8s自身的job、configMap、Secret和自研的job控制器。其中job主要用來執行ansible的指令碼,因為K8s的job的狀態有成功和失敗,這樣job 控制器很好觀察到ansible執行的成功或者失敗,同時也可以通過job對應pod日誌去檢視ansible的執行詳細流程。configmap主要用於儲存ansible執行時依賴的inventory和變數,掛在到job上。secret主要儲存登陸主機的金鑰,也是掛載到job上。

【擴充套件控制器】:主要用於擴充套件叢集管理的功能的附加控制器,在部署kubernetes-operator我們做了定製,可以選擇自己需要的擴充套件控制器。比如addons控制器主要負責addon外掛的安裝和管理。clusterinstall主要生成ansible執行器。remoteMachineSet用於多叢集管理,同步元資料叢集和業務叢集的machine狀態。還有其它的如對接公有云、dns、lb等控制器。

3.3 Kubernetes-Operator 架構

圖片

vivo的應用分佈在資料中心的多個K8s叢集上,提供了具有集中式多雲管理、統一排程、高可用性、故障恢復等關鍵特性。主要搭建了一個元資料叢集的pass平臺去管理多個業務K8s叢集。在眾多關鍵元件中,其中kubernetes-operator就部署在元資料叢集中,同時單獨運行了machine控制器去管理物理資源。

下面舉例部分場景如下:

場景一:

當大量應用遷移到kubernets上,管理員評估需要擴容叢集。首先需要審批物理資源並通過pass平臺生成對應machine的CR資源,此時的物理機處於備機池裡,machine CR的狀態為空閒狀態。當管理員建立ClusterDeploment時所屬的MachineSet會去關聯空閒狀態的machine,拿到空閒的machine資源,我們就可以觀測到當前需要操作機器的IP地址生成對應的inventory和變數,並建立configmap並掛載給job。執行擴容的ansible指令碼,如果job成功執行完會去更新machine的狀態為deployed。同時跨叢集同步node的控制器會檢查當前的擴容的node是否為ready,如果為ready,會更新當前的machine為Ready狀態,才完成整個擴容流程。

場景二:

當其中一個業務叢集出現故障,無法提供服務,觸發故障恢復流程,走統一資源排程。同時業務的策略是分配在多個業務叢集,同時配置了一個備用叢集,並沒有在備用叢集上分配例項,備用叢集並不實際存在。

有如下2種情況:

  1. 其它的業務叢集可以承載故障叢集的業務,kubernetes-operator不需要執行任何操作。

  2. 如果其他業務叢集不能承載故障叢集的業務。容器平臺開始預估資源,呼叫kubernetes-operator建立叢集,即建立clusterDeployment從備機池裡選擇物理機器,觀測到當前需要操作機器的IP地址生成對應的inventory和變數,建立configmap並掛載給job。執行叢集安裝的ansible指令碼, 叢集正常部署完成後開始業務的遷移。

3.4 Kubernetes-Operator 執行流程

圖片

  1. 叢集管理員或者容器平臺觸發建立ClusterDeployment的CR,去定義當前叢集的操作。
  2. ClusterDeployment控制器感知到變化進入控制器。
  3. 開始建立machineSet和關聯machine 資源。
  4. ClusterInstall 控制器感知ClusterDeployment和Machineset的變化,開始統計machine資源,建立configmap和job,引數指定操作的ansible yml入口,執行擴縮容、升級和安裝等操作。
  5. 排程器感知到job建立的pod資源,進行排程。
  6. 排程器呼叫K8s客戶端更新pod的binding資源。
  7. kubelet感知到pod的排程結果,建立pod開始執行ansible playbook。
  8. job controller感知job的執行狀態,更新ClusterDeployment狀態。一般策略下job controller會去清理configmap和job資源。
  9. NodeHealthy感知K8s的node是否為ready,並同步machine的狀態。
  10. addons 控制器感知叢集是否ready,如果為ready去執行相關的addons外掛的安裝和升級。

四、總結

vivo大規模的K8s叢集運維實踐中,從底層的叢集部署工具的優化,到大量的CI矩陣測試保證了我們線上叢集運維的安全和穩定性。採用了K8s託管K8s的方式來自動化管理叢集(K8s as a service),當operator檢測當前的叢集狀態,判斷是否與目標一致,出現不一致時,operator會發起具體的操作流程,驅動整個叢集達到目標狀態。

當前vivo的應用主要分佈在自建的資料中心的多個K8s叢集中,隨著應用的不斷的增長和複雜的業務場景,需要提供跨自建機房和雲的多個K8s叢集去執行原雲生的應用程式。就需要Kubernetes-Operator提供對接公有云基礎設施、apiserver的負載均衡、網路、dns和Cloud Provider 等。需要後續不斷完善,降低K8s叢集的運維難度。