摘要:叢集更新是Kubernetes叢集生命周期中最為重要的一環,也是也是衆多使用者最為謹慎對待的操作之一。為了更好地了解叢集更新這件事情的内涵外延,我們首先會對叢集更新的必要性和難點進行闡述。随後我們會對叢集更新前必須要做的前置檢查進行逐一講解。接下來我們會對兩種常見的更新方式進行展開介紹。最後我們對叢集更新的三個步驟進行講解,幫助讀者從理論走入實踐。
更新的必要性&難點
在 Kubernetes領域,得益于活躍的開源社群,Kubernetes 的疊代速度較快,目前保持在每個季度發行一個新版本的節奏。新版本的 Kubernetes 有着更為先進的新特性、更加全面的安全加強和漏洞修複。前一段時間社群剛剛完成了1.19版本的正式釋出。
那麼對于如此快速發展的開源項目,跟上社群的步伐就顯得更為重要。而叢集更新能力就是幫助我們跟上社群步伐的不二選擇。我們可以從以下兩個方面對叢集更新的必要性進行說明:
- 對于Kubernetes叢集的使用者。更新的Kubernetes版本意味着更新的feature,更加全面的安全更新檔,和諸多的bugfix。我們可以通過叢集更新功能充分享受活躍的Kubernetes開源社群帶來的發展紅利。
- 對于Kubernetes叢集的運維者。通過叢集更新功能可以拉齊所管理的叢集的版本,減少叢集版本的碎片化,進而減少Kubernetes版本碎片化帶來的管理成本和維護成本。
講完了叢集更新的必要性,我們來詳細看一下叢集更新的難點。目前多數Kubernetes使用者對叢集更新這件事持有者非常保守的态度,害怕叢集在更新的過程中出現不可預期的情況。也有使用者将叢集更新稱之為“給飛行中的飛機換引擎”。那麼,使用者對于更新的保守态度主要來源于什麼原因呢?我認為有以下幾點:
- 經過長時間的運作後,Kubernetes叢集已經累計了複雜的運作時狀态。
- Kubernetes叢集運維者會根據叢集承載的不同業務,對叢集進行不同的配置。進而導緻每個叢集都有自己的差異化配置,可能會造成“千叢集千面”。
- 對于雲上運作的Kubernetes叢集來說,其使用了大量的雲計算底層資源。衆多的底層雲資源就會帶來衆多的不确定性因素。
由于“千叢集千面”的情況的存在,就導緻了叢集更新需要以一套邏輯完成各種不同情況叢集的更新工作,這也正是叢集更新的困難之處。
更新預檢
正如我們前面所說的給正在對外提供服務的Kubernetes叢集更新,就好比是“給飛行中的飛機換引擎”。因為叢集更新面臨着衆多難點,也使得衆多的Kubernetes叢集維護者對叢集更新這件事情比較緊張。
我們可以通過詳細的更新預檢,來消除叢集更新的不确定性。感覺上面我們列舉的叢集更新的難點,我們也可以分别進行詳細的更新預檢,對症下藥,将難點逐一擊破。更新預檢主要可以分為三個方面:核心元件健康檢查、節點配置檢查和雲資源檢查。
核心元件健康檢查
說到核心元件健康檢查,就不得不剖析一下叢集的健康對于叢集更新的重要性。一個不健康的叢集很可能會在更新中出現各種異常的問題,就算僥幸完成了更新,各種問題也會在後續使用中逐漸凸顯出來。
也有的人會說,我的叢集看起來挺健康的,但是更新之後就出現問題了。一般來說,之是以會發生這種情況,是因為在叢集在更新之前,這個問題已經存在了,隻不過是在經曆了叢集更新之後才顯現出來。
在了解了核心元件健康檢查的必要性之後,我們來看一下都需要對那些元件進行檢查。
- 網絡元件:需要確定網絡元件版本和需要更新到的目标Kubernetes版本相容。
- apiservice:需要確定叢集内的apiservice都可用。
- 節點:需要确定節點全部健康。
節點配置檢查
節點作為承載Kubernetes的底層元計算資源,不僅運作着Kubelet、Docker等重要的系統程序,也充當着叢集和底層硬體互動接口的角色。
確定節點的健康性和配置的正确性是確定整個叢集健康性重要的一環。下面就對所需的檢查項進行講解。
- 作業系統配置:需要确定基礎的系統元件(yum、systemd和ntp等系統服務是否正常)和核心參數是否配置合理。
- kubelet:需要确定kubelet的程序健康、配置正确。
- Docker:需要确定Docker的程序健康、配置正确。
雲資源檢查
運作在雲上的Kubernetes叢集依賴着衆多雲資源,一旦叢集所依賴的雲資源不健康或者配置錯誤,就會影響到整個叢集的正常運作。我們主要需要對下列雲資源的狀态和配置進行預檢。
- apiserver所使用的SLB:需要确定執行個體的健康狀态和端口配置(轉發配置和通路控制配置等)。
- 叢集所使用的VPC和VSwitch:需要确實執行個體的健康狀況。
- 叢集内的ECS執行個體:需要确定其健康狀況和網絡配置。
兩種常見的更新方式
在軟體更新領域,有兩種主流的軟體更新方式,即原地更新和替換更新。這兩種更新方式同樣适用于 Kubernetes 叢集。這兩種叢集更新方式采用了不同軟體更新思路,這兩種更新方式也都存在着各自的利弊。下面我們來對這兩種叢集更新方式進行逐一講解。
原地更新
原地更新是一種精細化的、對這個那個叢集改動量相對較小的一種更新方式。在更新容器的的worker節點的時候,該更新方式會通過在 ECS 上原地替換 Kubernetes 元件的方式(主要為kubelet和其相關元件),完成整個叢集的更新工作。阿裡雲容器服務Kubernetes 為客戶提供的叢集更新就是基于這種方式的。
以将Kubernetes的版本從 1.14 更新到 1.16 為例。首先我們會對ECS A上的原本為 1.14 的Kubelet 及其配置更新為1.16,在完成節點ECS A 上的元件更新之後,該節點也就被成功的更新到了1.16。然後我們再對ECS B進行相同的操作,将其更新為1.16,進而完成整個叢集的更新工作。在這個過程中節點保持運作,ECS 的相關配置也不會被修改。如圖所示。
優點:
- 原地更新通過原地替換kubelet元件的方式對節點進行版本更新,進而保證了節點上的 Pod 不會因為叢集更新而重建,確定了業務的連貫性。
- 該種更新方式不會對底層 ECS 本身進行修改和替換,保證了依賴特定節點排程的業務可以正常運作,也對 ECS 的包年包月客戶更加友好。
缺點:
- 原地更新方式需要在節點上進行一系列更新操作,才能完成整個節點的更新工作。這就導緻整個更新過程不夠原子化,可能會在中間的某一步驟失敗,進而導緻該節點更新失敗。
- 原地更新的另一個缺點是需要預留一定量的資源,隻有在資源足夠的情況下更新程式才能在ECS 上完成對節點的更新。
替換更新
替換更新又稱輪轉更新,相對于原地更新,替換更新是一種更加粗狂和原子化的更新方式。替換更新會逐個将舊版本的節點從叢集中移除,并用新版本全新的節點來替換,進而完成整個Kubernetes 叢集的更新工作。
同樣以将Kubernetes的版本從 1.14 更新到 1.16 為例。使用替代輪轉方式的情況下,我們會将叢集中1.14 版本的節點依次進行排水并從叢集中移除,并直接加入 1.16 版本的節點。即将1.14節點的ECS A從節點剔除,并将1.16節點的ECS C加入叢集,再将ECS B從叢集中删除,最後将ECS D加入到叢集中。這樣就完成了所有節點的輪轉工作,整個叢集就也就更新到 1.16 了。如圖所示 。
替代更新通過将舊版本的節點替換為新版本的節點進而完成叢集更新。這個替換的過程相較于原地更新更為原子化,也不存在那麼複雜的中間狀态。是以也不需要在更新之前進行太多的前置檢查。相對應的,更新過程中可能會出現的各種稀奇古怪的問題也會減少很多。
•替代更新将叢集内的節點全部進行替換和重置,所有節點都會經曆排水的過程,這就會使叢集内的pod 進行大量的遷移重建。對于 pod 重建容忍度比較低的業務、隻有單副本的應用、stateful set等相關應用不夠友好,可能會是以發生不可用或者故障。
•所有的節點經曆重置,儲存在節點本地磁盤上的資料都會丢失。
•這種更新方式可能會帶來主控端IP變化等問題,對包年包月使用者也不夠友好。
叢集更新三部曲
一個 Kubernetes 叢集主要由負責叢集管控的 master,執行工作負載的worker和衆多功能性的系統元件組成。那麼對一個 Kubernetes 叢集更新,也就是對叢集中的這三個部分進行分别更新。故叢集更新的三部曲為:
- 滾動更新 master
- 分批更新 worker
- 系統組價更新(主要為CoreDNS,kube-proxy等核心元件)
下面我們來對叢集更新三部曲進行詳細的講解。
滾動更新 master:
master作為叢集的大腦,承擔了與使用者互動、任務排程和各種功能性的任務處理。叢集master的部署方式也比較多樣,可以通過static pod進行部署,可以通過本地程序進行部署,也可以通過Kubernetes on Kubernetes的方式在另一個叢集内通過pod的方式部署。總而言之,無論master為哪種部署方式,想要手機master就是主要就是對 master 中的三大件進行版本更新,主要包括:
- 更新 kube-apiserver
- 更新 kube-controller-manager
- 更新 kube-scheduler
需要注意,為了保證 Kubernetes apiserver 的可用性不中斷,master中的 kube-apiserver 最少需要有兩個,這樣才可以實作滾動更新,進而保證apiserver不會出現downtime。
分批更新 worker:
在完成master的更新工作之後,我們才可以開始對worker進行更新。Worker 更新主要是對節點上的kubelet 及其依賴元件(如cni 等)進行更新。為了保證叢集中worker 不會同時發生大批量的 kubelet 重新開機,是以我們需要對 worker節點進行分批更新。
需要注意,我們必須要先更新master,再更新worker。因為高版本的kubelet在連接配接低版本的master時,很可能會出現不相容的情況,進而導緻節點not ready。對于低版本的kubelet連接配接高版本的apiserver,開源社群保證了apiserver對于kubelet兩個版本的向後相容性。即1.14的kubelet可以連接配接到1.16的apiserver,而不會發生相容性問題。
核心系統元件:
為了保證叢集中各個元件的相容性,我們需要在更新叢集的同時對叢集中的核心系統元件進行同步更新,主要包括
- Dns 元件:根據社群的版本相容矩陣( https://github.com/coredns/deployment/blob/master/kubernetes/CoreDNS-k8s_version.md ),将 CoreDNS 的版本更新為與叢集版本相對應的版本。
- 網絡轉發元件:Kube-proxy的版本是跟随Kubernetes的版本進行演進的,所有我們需要将kube-proxy的版本更新到與Kubernetes版本相同的版本。