Kubernetes 升級 FAQ

smalltown
Starbugs Weekly 星巴哥技術專欄
12 min readApr 10, 2022

Background

Kubernete 遵守著主要版號 N-2 的支援原則 (也就是說最新的三個主要版本才可以收到 Security 和 Bug 修補更新),然後再加上差不多每隔 15 週會發布新版本的週期,在這樣的前提條件之下,從 K8s 1.19 開始之後每一個版本可以獲得將近 14 的月的技術支援,可以從下圖觀察到近期版本的支援週期

https://endoflife.date/kubernetes

接著讓我們來看看 Ubuntu 這個傳統專案的技術支援週期,以 LTS 版本來說的話,可以獲得將近 10 年的技術支援,所以在使用 K8s 的時候就必須意會到一年至少要做一次升級是避免不了的,不然哪一天遇到有什麼安全或是功能上有問題時,將無法獲得更新可以安裝使用

https://endoflife.date/ubuntu

老實說,這樣的速度有點累人 🥲 尤其是 K8s 的版本更新也不是只要 K8s 本身更新就好,最近幾版更新牽涉到的東西也都不少,自己一開始滿好奇其他公司真的都有辦法跟上至少一年一次的更新嗎?這時候打開 AKS, GKE, EKS 的支援版本頁面,可以發現 GKE 在版本 1.19 支援到 2022/06,EKS 現在還有支援 1.18,所以答案就是業界其實跟不太上這一年一次的更新速度 😂 但相對頻繁的更新還是躲不掉的,所以想要透過這篇文章把自己在更新 K8s 的一些步驟還有經驗給記錄下來

General

那麼在升級之前會有什麼前置作業需要做呢?

🛠️ Read CHANGELOG Carefully

首先要拜讀 Kubernetes 官方社群於每一個版本的 “更新文件”,例如這次想要從 K8s 1.21 升級到 1.23,就把 1.22 和 1.23 的 CHANGELOG 開起來研究看看,找出其中有哪一些變更會影響到自己組織內所使用的 K8s Cluster

🛠️ Communication & Schedule

因為管理和使用 K8s Cluster 的不一定會是同一群人,例如 SRE 負責架設和管理 K8s Cluster,而部署應用服務於其上的為後端/前端工程師,因此根據變更文件找出會影響的範圍之後,假如有需要其他團隊或是部門作出相對應的修改,那麼就是要開始溝通如何安排人力資源和排定時程了

🛠️ Production & Non-Production K8s Cluster

再來是手頭上一定需要至少有兩個/群 K8s Cluster,分別是 Production 與 Non-Production 環境,因為升級的時候一定要先在 Non-Production 環境跑過一段時間才有信心在 Production 環境去進行升級;即使 CHANGELOG 看得很詳細了,該修改的東西也都改了,但升級後會遇到什麼樣的問題,還是要實際試試看才會知道,要是直接在 Production 環境就進行升級的話,搞不好會造成線上服務受到影響,接下來就 K8s 升級可能會遇到的一些問題做更近一步且深入的討論,例如…

👉 升級時怎麼妥切地處理 Deprecated API?

👉 怎麼應對即將在 K8s 1.24 被移除的 Dockershim?

👉 cgroups v2 真的已經可以使用了嗎?

Deprecated API

大家在管理 K8s Manifest 的時候應該都有發現有一個參數叫做 apiVersion ,因為 K8s 的 API 一直都在不斷地更新,所以舊的 API 就會慢慢的被棄用,最後被刪除掉,以 K8s 1.22 來說就有一拖拉庫的 API 要被刪除掉 (Reference),遇到這個情況時要升級要怎麼辦呢?

🛠️ Exist K8s Resource

根據官方文件Issue 可以發現有不少已經存在於 K8s 內的資源不需要為了升級而去做改動,因為升級完後,K8s 會自己去做向下相容,例如我本來使用 extensions/v1beta1 或是 networking.k8s.io/v1beta1 apiVersion 所建立的 Ingress,在升級到 K8s 1.22 以後也還是會好好的活著

🛠️ K8s Resource Manager

不過當初協助建立 K8s 資源的角色在升級完過後,假如還想要對該 K8s 資源進行新增/修改/刪除的話,就會遇到問題了,底下繼續以 Ingress 為例來討論:

👉 Kubernetes Manifest

假設當初是用靜態的 K8s Manifest 去將此 Ingress 建立起來的,例如使用 Helm Chart,當想要使用同樣的 Helm Chart 去對 Ingress 做新增/修改/刪除時就可能會遇到問題,解決辦法就是將 Helm Chart 內使用到的 apiVersion 修改成新的版本 networking.k8s.io/v1,或是使用底下這種可以根據不同的 K8s 版本去自動決定 apiVersion 的方式 (Reference)

{{/* Get Ingress API Version */}}
{{- define "kube-prometheus-stack.ingress.apiVersion" -}}
{{- if and (.Capabilities.APIVersions.Has "networking.k8s.io/v1") (semverCompare ">= 1.19-0" (include "kube-prometheus-stack.kubeVersion" .)) -}}
{{- print "networking.k8s.io/v1" -}}
{{- else if .Capabilities.APIVersions.Has "networking.k8s.io/v1beta1" -}}
{{- print "networking.k8s.io/v1beta1" -}}
{{- else -}}
{{- print "extensions/v1beta1" -}}
{{- end -}}
{{- end -}}

👉 Controller or Operator

假設 Ingress 是由 Controller 或是 Operator 所負責管理的話,那就要確保他們已經有支援新版的 apiVersion,然後去研究是否有需要升級該 Controller 或是 Operator,當使用靜態的 K8s Manifest 來建立 K8s 資源,遇到支援的 apiVersion 是錯誤的情況之下,可以很直覺地馬上就發現,但當使用 Controller 或是 Operator 來管理 K8s 資源時,就要去看看 Log 或是測試看看有沒有正常在運作

🛠️ How to Find Deprecated API

通常部署在 K8s Cluster 裡面的東西有一大堆,有些時候升級 K8s 版本會有 API 即將要 Deprecated 有些版本卻沒有,要怎麼很快速地知道目前在 K8s Cluster 內的資源在升級到某個 K8s 版本後,有使用到即將 Deprecated 的 API 版本呢?這時候要推薦一個開源工具 Kube No Trouble (kubent) 給大家,安裝完之後,只要在命令提示列輸入 kubent,就可以從輸出畫面中得知哪一些 K8s 資源需要特別去關照,不會像是在大海撈針一般

$./kubent
6:25PM INF >>> Kube No Trouble `kubent` <<<
6:25PM INF Initializing collectors and retrieving data
6:25PM INF Retrieved 103 resources from collector name=Cluster
6:25PM INF Retrieved 132 resources from collector name="Helm v2"
6:25PM INF Retrieved 0 resources from collector name="Helm v3"
6:25PM INF Loaded ruleset name=deprecated-1-16.rego
6:25PM INF Loaded ruleset name=deprecated-1-20.rego
__________________________________________________________________________________________
>>> 1.16 Deprecated APIs <<<
------------------------------------------------------------------------------------------
KIND NAMESPACE NAME API_VERSION
Deployment default nginx-deployment-old apps/v1beta1
Deployment kube-system event-exporter-v0.2.5 apps/v1beta1
Deployment kube-system k8s-snapshots extensions/v1beta1
Deployment kube-system kube-dns extensions/v1beta1
__________________________________________________________________________________________
>>> 1.20 Deprecated APIs <<<
------------------------------------------------------------------------------------------
KIND NAMESPACE NAME API_VERSION
Ingress default test-ingress extensions/v1beta1

Dockershim Removal

大家應該或多少有而聞 K8s 1.24 即將把 Dockershim 完全給移除掉,而在 1.24 即將推出的當下,官方又特地發了篇文章來跟大家提醒這件事情,自己在一兩年前有稍微研究過,結論就是…假如不是負責管理 Self-Hosted K8s Cluster 的人,應該是不太需要在意這件事情,但要是組織內需要自己架設 K8s Cluster 的話,那麼在升級到 K8s 1.24 前就要戒慎恐懼(Reference)

🛠️ Current Container Runtime

首先要做的當然是先確定目前使用的是哪一種 Container Runtime,要是查詢結果為 Dockershim 的話,那就要在升級到 1.24 之前將其更換成其他的 Container Runtime

~$ kubectl get nodes -o wide# For dockershim
NAME STATUS VERSION CONTAINER-RUNTIME
node-1 Ready v1.16.15 docker://19.3.1
...
# For containerd
NAME STATUS VERSION CONTAINER-RUNTIME
node-1 Ready v1.19.6 containerd://1.4.1
...

🛠️ Other Container Runtime

👉 假如想要直接棄用 Docker Engine 的話,可以把 K8s Node 的 Docker Engine 給停用或是直接移除掉,然後安裝 containerd, CRI-O 等其他 Container Runtime (Reference)

👉 或是使用 cri-dockerd 來取代掉 dockershim,然後繼續使用 Docker Engine (Reference)

自己目前則是會先停留在 1.23 繼續使用 Dockershim 一陣子,以時間換取空間去研究 containerd + gVisor 的可行性與穩定性,等到完成後才會升級到 1.24 跟 Dockershim 說掰掰,到時候再把心得寫成另外一篇文章分享出來

cgroups v1 to v2

在先前的文章有提到過 cgroups v2 的諸多優點,那麼在 K8s 的哪一個版本可以開始使用 cgroups v2 呢? 理論上是 K8s 1.19 (Reference),但實際上自己建議可以再緩一緩,自己在文章中也有提到有遇到小問題,後來實際再多深入研究之後,發現問題是出在 cAdvisor 的身上

cAdvisor 目前內嵌在 kubelet 當中,他是用來讓使用者知道 Container 資源使用狀況的工具,而從它的 Release Page 可以發現有不少關於 cgroups v2 的 Bug Fix,目前最新的 K8s 1.23.5 使用到的 cAdvisor 版本是 0.43 (Reference),而 cAdvisor 0.43 與 cgroups v2 間還是有點問題的 (Reference);看來要到 K8s 1.24 才會更新到 cAdvisor 0.44 (Reference),有鑒於這些問題都還沒有好好的被解決掉且被多一點的人測試過,所以自己建議先緩一緩,等幾個月後 K8s 1.24 被多一點使用 cgroups v2 的人幫忙測試過沒問題再來談要把 cgroups v1 切換到 v2 也不遲

Conclusion

這篇文章自己會再繼續一直更新下去💪 因為會需要把自己升級到 1.24 將 Dockershim 移除後的心得寫上來,還有究竟哪一個 K8s 穩定版本可以與 cgroups v2 完美地搭配使用,緊接著是 Rootless Container 的實現,還有遠望的 Rootless Kubernetes;可以預期在若干時間後,這篇文章會變成沒有價值的廢文,但可以很肯定的是…依照 K8s 這麼樣的更新速度,應該沒那麼快 🤣

--

--

smalltown
Starbugs Weekly 星巴哥技術專欄

原來只是一介草 QA,但開始研究自動化維運雲端服務後,便一頭栽進 DevOps 的世界裏,熱愛鑽研各種可以提升雲端服務品質及增進團隊開發效率的開源技術