Kubernetes 集群升級(jí)指南:從理論到實(shí)踐
作者 | 高相林(禪鳴)
導(dǎo)讀:集群升級(jí)是 Kubernetes?集群生命周期中最為重要的一環(huán),也是眾多使用者最為謹(jǐn)慎對(duì)待的操作之一。為了更好地理解集群升級(jí)這件事情的內(nèi)涵外延,我們首先會(huì)對(duì)集群升級(jí)的必要性和難點(diǎn)進(jìn)行闡述;隨后會(huì)對(duì)集群升級(jí)前必須要做的前置檢查進(jìn)行逐一講解;接下來(lái)會(huì)對(duì)兩種常見(jiàn)的升級(jí)方式進(jìn)行展開(kāi)介紹;最后對(duì)集群升級(jí)的三個(gè)步驟進(jìn)行講解,幫助讀者從理論走入實(shí)踐。

升級(jí)的必要性&難點(diǎn)
在 Kubernetes 領(lǐng)域,得益于活躍的開(kāi)源社區(qū),Kubernetes 的迭代速度較快,目前保持在每個(gè)季度發(fā)行一個(gè)新版本的節(jié)奏。新版本的 Kubernetes 有著更為先進(jìn)的新特性、更加全面的安全加固和漏洞修復(fù)。前一段時(shí)間社區(qū)剛剛完成了 1.19 版本的正式發(fā)布。
對(duì)于發(fā)展如此快速的開(kāi)源項(xiàng)目,跟上社區(qū)的步伐就顯得更為重要,而集群升級(jí)能力就是幫助我們跟上社區(qū)步伐的不二選擇。我們可以從以下兩個(gè)方面對(duì)集群升級(jí)的必要性進(jìn)行說(shuō)明:
對(duì)于 Kubernetes 集群的使用者:更新的 Kubernetes 版本意味著更新的 feature,更加全面的安全補(bǔ)丁,和諸多的 bugfix。我們可以通過(guò)集群升級(jí)功能充分享受活躍的 Kubernetes 開(kāi)源社區(qū)帶來(lái)的發(fā)展紅利;
對(duì)于 Kubernetes 集群的運(yùn)維者:通過(guò)集群升級(jí)功能可以拉齊所管理的集群版本,減少集群版本的碎片化,從而減少 Kubernetes 版本碎片化帶來(lái)的管理成本和維護(hù)成本。
講完了集群升級(jí)的必要性,我們來(lái)詳細(xì)看一下集群升級(jí)的難點(diǎn)。
目前多數(shù) Kubernetes 使用者對(duì)集群升級(jí)這件事持有著非常保守的態(tài)度,害怕集群在升級(jí)的過(guò)程中出現(xiàn)不可預(yù)期的情況,也有使用者將集群升級(jí)稱之為“給飛行中的飛機(jī)換引擎”。那么,使用者對(duì)于升級(jí)的保守態(tài)度主要來(lái)源于什么原因呢?我認(rèn)為有以下幾點(diǎn):
經(jīng)過(guò)長(zhǎng)時(shí)間的運(yùn)行后,Kubernetes 集群已經(jīng)累計(jì)了復(fù)雜的運(yùn)行時(shí)狀態(tài);
Kubernetes 集群運(yùn)維者會(huì)根據(jù)集群承載的不同業(yè)務(wù),對(duì)集群進(jìn)行不同的配置,從而導(dǎo)致每個(gè)集群都有自己的差異化配置,可能會(huì)造成“千集群千面”;
對(duì)于云上運(yùn)行的 Kubernetes 集群來(lái)說(shuō),其使用了大量的云計(jì)算底層資源。眾多的底層云資源就會(huì)帶來(lái)眾多的不確定性因素。
“千集群千面”的情況的存在,導(dǎo)致了集群升級(jí)需要以一套邏輯完成各種不同情況集群的升級(jí)工作,這也正是集群升級(jí)的困難之處。

升級(jí)預(yù)檢
正如我們前面所說(shuō),給正在對(duì)外提供服務(wù)的 Kubernetes 集群升級(jí),就好比是“給飛行中的飛機(jī)換引擎”。因?yàn)榧荷?jí)面臨著眾多難點(diǎn),也使得眾多的 Kubernetes 集群維護(hù)者對(duì)集群升級(jí)這件事情比較緊張。
我們可以通過(guò)詳細(xì)的升級(jí)預(yù)檢,來(lái)消除集群升級(jí)的不確定性。對(duì)于上面列舉的集群升級(jí)的難點(diǎn),我們也可以分別進(jìn)行詳細(xì)的升級(jí)預(yù)檢,對(duì)癥下藥,將難點(diǎn)逐一擊破。升級(jí)預(yù)檢主要可以分為三個(gè)方面:
核心組件健康檢查
節(jié)點(diǎn)配置檢查
云資源檢查
1. 核心組件健康檢查
說(shuō)到核心組件健康檢查,就不得不剖析一下集群的健康對(duì)于集群升級(jí)的重要性。一個(gè)不健康的集群很可能會(huì)在升級(jí)中出現(xiàn)各種異常的問(wèn)題,就算僥幸完成了升級(jí),各種問(wèn)題也會(huì)在后續(xù)使用中逐漸凸顯出來(lái)。
有人會(huì)說(shuō),我的集群看起來(lái)挺健康的,但是升級(jí)之后就出現(xiàn)問(wèn)題了。一般來(lái)說(shuō),之所以會(huì)發(fā)生這種情況,是因?yàn)樵诩涸谏?jí)之前,這個(gè)問(wèn)題已經(jīng)存在了,只不過(guò)是在經(jīng)歷了集群升級(jí)之后才顯現(xiàn)出來(lái)。
在了解了核心組件健康檢查的必要性之后,我們來(lái)看一下都需要對(duì)那些組件進(jìn)行檢查:
網(wǎng)絡(luò)組件:需要確保網(wǎng)絡(luò)組件版本和需要升級(jí)到的目標(biāo) Kubernetes 版本兼容;
apiservice:需要確保集群內(nèi)的 apiservice 都可用;
節(jié)點(diǎn):需要確定節(jié)點(diǎn)全部健康。
2. 節(jié)點(diǎn)配置檢查
節(jié)點(diǎn)作為承載 Kubernetes 的底層元計(jì)算資源,不僅運(yùn)行著 Kubelet、Docker 等重要的系統(tǒng)進(jìn)程,也充當(dāng)著集群和底層硬件交互接口的角色。
確保節(jié)點(diǎn)的健康性和配置的正確性是確保整個(gè)集群健康性重要的一環(huán)。下面就對(duì)所需的檢查項(xiàng)進(jìn)行講解。
操作系統(tǒng)配置:需要確定基礎(chǔ)的系統(tǒng)組件(yum、systemd 和 ntp 等系統(tǒng)服務(wù)是否正常)和內(nèi)核參數(shù)是否配置合理;
kubelet:需要確定 kubelet 的進(jìn)程健康、配置正確;
Docker:需要確定 Docker 的進(jìn)程健康、配置正確。
3. 云資源檢查
運(yùn)行在云上的 Kubernetes 集群依賴著眾多云資源,一旦集群所依賴的云資源不健康或者配置錯(cuò)誤,就會(huì)影響到整個(gè)集群的正常運(yùn)行。我們主要對(duì)下列云資源的狀態(tài)和配置進(jìn)行預(yù)檢:
apiserver 所使用的 SLB:需要確定實(shí)例的健康狀態(tài)和端口配置(轉(zhuǎn)發(fā)配置和訪問(wèn)控制配置等);
集群所使用的 VPC 和 VSwitch:需要確定實(shí)例的健康狀況;
集群內(nèi)的 ECS 實(shí)例:需要確定其健康狀況和網(wǎng)絡(luò)配置。

兩種常見(jiàn)的升級(jí)方式
在軟件升級(jí)領(lǐng)域,有兩種主流的軟件升級(jí)方式,即原地升級(jí)和替換升級(jí)。這兩種升級(jí)方式同樣適用于 Kubernetes 集群,它們采用了不同軟件升級(jí)思路,但也都存在著各自的利弊。下面我們來(lái)對(duì)這兩種集群升級(jí)方式進(jìn)行逐一講解。
1. 原地升級(jí)
原地升級(jí)是一種精細(xì)化的、對(duì)這個(gè)那個(gè)集群改動(dòng)量相對(duì)較小的一種升級(jí)方式。在升級(jí)容器的 worker 節(jié)點(diǎn)時(shí),該升級(jí)方式會(huì)通過(guò)在 ECS 上原地替換 Kubernetes 組件的方式(主要為 kubelet 和其相關(guān)組件),完成整個(gè)集群的升級(jí)工作。阿里云容器服務(wù) Kubernetes 為客戶提供的集群升級(jí)就是基于這種方式的。
以將 Kubernetes 的版本從 1.14 升級(jí)到 1.16 為例。首先我們會(huì)對(duì) ECS A 上的原本為 1.14 的 Kubelet 及其配置升級(jí)為 1.16,在完成節(jié)點(diǎn) ECS A 上的組件升級(jí)之后,該節(jié)點(diǎn)也就被成功的升級(jí)到了 1.16。然后我們?cè)賹?duì) ECS B 進(jìn)行相同的操作,將其升級(jí)為 1.16,從而完成整個(gè)集群的升級(jí)工作。
在這個(gè)過(guò)程中節(jié)點(diǎn)保持運(yùn)行,ECS 的相關(guān)配置也不會(huì)被修改。如圖所示:

1)優(yōu)點(diǎn)
原地升級(jí)通過(guò)原地替換 kubelet 組件的方式對(duì)節(jié)點(diǎn)進(jìn)行版本升級(jí),從而保證了節(jié)點(diǎn)上的 Pod 不會(huì)因?yàn)榧荷?jí)而重建,確保了業(yè)務(wù)的連貫性;
該種升級(jí)方式不會(huì)對(duì)底層 ECS 本身進(jìn)行修改和替換,保證了依賴特定節(jié)點(diǎn)調(diào)度的業(yè)務(wù)可以正常運(yùn)行,也對(duì) ECS 的包年包月客戶更加友好。
2)缺點(diǎn)
原地升級(jí)方式需要在節(jié)點(diǎn)上進(jìn)行一系列升級(jí)操作,才能完成整個(gè)節(jié)點(diǎn)的升級(jí)工作,這就導(dǎo)致整個(gè)升級(jí)過(guò)程不夠原子化,可能會(huì)在中間的某一步驟失敗,從而導(dǎo)致該節(jié)點(diǎn)升級(jí)失?。?/span>
原地升級(jí)的另一個(gè)缺點(diǎn)是需要預(yù)留一定量的資源,只有在資源足夠的情況下升級(jí)程序才能在 ECS 上完成對(duì)節(jié)點(diǎn)的升級(jí)。
2. 替換升級(jí)
替換升級(jí)又稱輪轉(zhuǎn)升級(jí),相對(duì)于原地升級(jí),替換升級(jí)是一種更加粗狂和原子化的升級(jí)方式。替換升級(jí)會(huì)逐個(gè)將舊版本的節(jié)點(diǎn)從集群中移除,并用新版本全新的節(jié)點(diǎn)來(lái)替換,從而完成整個(gè) Kubernetes 集群的升級(jí)工作。
同樣以將 Kubernetes 的版本從 1.14 升級(jí)到 1.16 為例。使用替代輪轉(zhuǎn)方式的情況下,我們會(huì)將集群中 1.14 版本的節(jié)點(diǎn)依次進(jìn)行排水并從集群中移除,并直接加入 1.16 版本的節(jié)點(diǎn)。即將 1.14 節(jié)點(diǎn)的 ECS A 從節(jié)點(diǎn)剔除,并將 1.16 節(jié)點(diǎn)的 ECS C 加入集群,再將 ECS B 從集群中刪除,最后將 ECS D 加入到集群中。
這樣就完成了所有節(jié)點(diǎn)的輪轉(zhuǎn)工作,整個(gè)集群就也就升級(jí)到 1.16 了。如圖所示:

1)優(yōu)點(diǎn)
替代升級(jí)通過(guò)將舊版本的節(jié)點(diǎn)替換為新版本的節(jié)點(diǎn)從而完成集群升級(jí)。這個(gè)替換的過(guò)程相較于原地升級(jí)更為原子化,也不存在那么復(fù)雜的中間狀態(tài),所以也不需要在升級(jí)之前進(jìn)行太多的前置檢查。相對(duì)應(yīng)地,升級(jí)過(guò)程中可能會(huì)出現(xiàn)的各種稀奇古怪的問(wèn)題也會(huì)減少很多。
2)缺點(diǎn)
替代升級(jí)將集群內(nèi)的節(jié)點(diǎn)全部進(jìn)行替換和重置,所有節(jié)點(diǎn)都會(huì)經(jīng)歷排水的過(guò)程,這就會(huì)使集群內(nèi)的 pod 進(jìn)行大量遷移重建,對(duì)于 pod 重建容忍度比較低的業(yè)務(wù)、只有單副本的應(yīng)用、stateful set 等相關(guān)應(yīng)用不夠友好,可能會(huì)因此發(fā)生不可用或者故障;
所有的節(jié)點(diǎn)經(jīng)歷重置,儲(chǔ)存在節(jié)點(diǎn)本地磁盤上的數(shù)據(jù)都會(huì)丟失;
這種升級(jí)方式可能會(huì)帶來(lái)宿主機(jī) IP 變化等問(wèn)題,對(duì)包年包月用戶也不夠友好。

集群升級(jí)三部曲
一個(gè) Kubernetes 集群主要由負(fù)責(zé)集群管控的 master,執(zhí)行工作負(fù)載的 worker 和眾多功能性的系統(tǒng)組件組成。對(duì)一個(gè) Kubernetes 集群升級(jí),也就是對(duì)集群中的這三個(gè)部分進(jìn)行分別升級(jí)。
故集群升級(jí)的三部曲為:
滾動(dòng)升級(jí) master
分批升級(jí) worker
系統(tǒng)組件升級(jí)(主要為 CoreDNS,kube-proxy 等核心組件)

下面我們來(lái)對(duì)集群升級(jí)三部曲進(jìn)行詳細(xì)的講解。
1. 滾動(dòng)升級(jí)?master
master 作為集群的大腦,承擔(dān)了與使用者交互、任務(wù)調(diào)度和各種功能性的任務(wù)處理。集群 master 的部署方式也比較多樣,可以通過(guò) static pod 進(jìn)行部署,可以通過(guò)本地進(jìn)程進(jìn)行部署,也可以通過(guò) Kubernetes on Kubernetes 的方式在另一個(gè)集群內(nèi)通過(guò) pod 的方式部署。
總而言之,無(wú)論 master 為哪種部署方式,想要升級(jí) master 主要就是對(duì) master 中的三大件進(jìn)行版本升級(jí),主要包括:
升級(jí) kube-apiserver
升級(jí) kube-controller-manager
升級(jí) kube-scheduler
需要注意,為了保證 Kubernetes apiserver 的可用性不中斷,master 中的 kube-apiserver 最少需要有兩個(gè),這樣才可以實(shí)現(xiàn)滾動(dòng)升級(jí),從而保證 apiserver 不會(huì)出現(xiàn) downtime。
2. 分批升級(jí) worker
在完成 master 的升級(jí)工作之后,我們才可以開(kāi)始對(duì) worker 進(jìn)行升級(jí)。Worker 升級(jí)主要是對(duì)節(jié)點(diǎn)上的 kubelet 及其依賴組件(如 cni 等)進(jìn)行升級(jí)。為了保證集群中 worker 不會(huì)同時(shí)發(fā)生大批量的 kubelet 重啟,所以我們需要對(duì) worker 節(jié)點(diǎn)進(jìn)行分批升級(jí)。
需要注意,我們必須要先升級(jí) master,再升級(jí) worker。因?yàn)楦甙姹镜?kubelet 在連接低版本的 master 時(shí),很可能會(huì)出現(xiàn)不兼容的情況,從而導(dǎo)致節(jié)點(diǎn) not ready。對(duì)于低版本的 kubelet 連接高版本的 apiserver,開(kāi)源社區(qū)保證了 apiserver 對(duì)于 kubelet 兩個(gè)版本的向后兼容性,即 1.14 的 kubelet 可以連接到 1.16 的 apiserver,而不會(huì)發(fā)生兼容性問(wèn)題。
3. 核心系統(tǒng)組件升級(jí)
為了保證集群中各個(gè)組件的兼容性,我們需要在升級(jí)集群的同時(shí)對(duì)集群中的核心系統(tǒng)組件進(jìn)行同步升級(jí),主要包括:
Dns 組件:根據(jù)社區(qū)的版本兼容矩陣,將 CoreDNS 的版本升級(jí)為與集群版本相對(duì)應(yīng)的版本;
社區(qū)的版本兼容矩陣:https://github.com/coredns/deployment/blob/master/kubernetes/CoreDNS-k8s_version.md
網(wǎng)絡(luò)轉(zhuǎn)發(fā)組件:Kube-proxy 的版本是跟隨 Kubernetes 的版本進(jìn)行演進(jìn)的,所有我們需要將 kube-proxy 的版本升級(jí)到與 Kubernetes 版本相同的版本。
K8S進(jìn)階訓(xùn)練營(yíng),點(diǎn)擊下方圖片了解詳情

