您好,登錄后才能下訂單哦!
作者 | 酒祝 阿里云技術專家、墨封 阿里云開發工程師
直播完整視頻回顧: https://www.bilibili.com/video/BV1mK4y1t7WS/
關注“阿里巴巴云原生”公眾號,后臺回復 “528” 即可下載 PPT
5 月 28 日,我們發起了第 3 期 SIG Cloud-Provider-Alibaba 網研會直播。本次直播主要介紹了阿里經濟體大規模應用上云過程中遇到的核心部署問題、采取的對應解決方案,以及這些方案沉淀為通用化能力輸出開源后,如何幫助阿里云上的用戶提升應用部署發布的效率與穩定性。
本文匯集了此次直播完整視頻回顧及資料下載,并整理了直播過程中收集的問題和解答,希望能夠對大家有所幫助~
隨著近年來 Kubernetes 逐漸成為事實標準和大量應用的云原生化,我們往往發現 Kubernetes 的原生 workload 對大規模化應用的支持并不十分“友好”。如何在 Kubernetes 上為應用提供更加完善、高效、靈活的部署發布能力,成為了我們探索的目標。
本文將會介紹在阿里經濟體全面接入云原生的過程中,我們在應用部署方面所做的改進優化、實現功能更加完備的增強版 workload、并將其開源到社區,使得現在每一位 Kubernetes 開發者和阿里云上的用戶都能很便捷地使用上阿里巴巴內部云原生應用所統一使用的部署發布能力。
阿里巴巴容器化道路的起步在國內外都是比較領先的。容器這個技術概念雖然出現得很早,但一直到 2013 年 Docker 產品出現后才逐漸為人所熟知。而阿里巴巴早在 2011 年就開始發展了基于 LXC 的容器技術,經過了幾代的系統演進,如今阿里巴巴有著超過百萬的容器體量,這個規模在世界范圍內都是頂尖的。
隨著云技術發展和云原生應用的興起,我們近兩年間逐步將過去的容器遷到了基于 Kubernetes 的云原生環境中。而在這其中,我們遇到了不少應用部署方面的問題。首先對于應用開發者來說,他們對遷移到云原生環境的期望是:
阿里的應用場景非常復雜,基于 Kubernetes 之上生長著很多不同的 PaaS 二層,比如服務于電商業務的運維中臺、規模化運維、中間件、Serverless、函數計算等,而每個平臺都對部署、發布要求各有不同。
我們再來看一下 Kubernete 原生所提供的兩種常用 workload 的能力:
簡單來說,Deployment 和 StatefulSet 在一些小規模的場景下是可以 work 的;但到了阿里巴巴這種應用和容器的規模下,如果全量使用原生 workload 則是完全不現實的。目前阿里內部容器集群上的應用數量超過十萬、容器數量達到百萬,有部分重點核心應用甚至單個應用下就有上萬的容器。再結合上圖的問題,我們會發現不僅針對單個應用的發布功能不足,而且當發布高峰期大量應用同時在升級時,超大規模的 Pod 重建也成為一種“災難”。
針對原生 workload 遠遠無法滿足應用場景的問題,我們從各種復雜的業務場景中抽象出共通的應用部署需求,據此開發了多種擴展 workload。在這些 workload 中我們做了大幅的增強和改進,但同時也會嚴格保證功能的通用化、不允許將業務邏輯耦合進來。
這里我們重點介紹一下 CloneSet 與 Advanced StatefulSet。在阿里內部云原生環境下,幾乎全量的電商相關應用都統一采用 CloneSet 做部署發布,而中間件等有狀態應用則使用了 Advanced StatefulSet 管理。
Advanced StatefulSet 顧名思義,是原生 StatefulSet 的增強版,默認行為與原生完全一致,在此之外提供了原地升級、并行發布(最大不可用)、發布暫停等功能。而 CloneSet 則對標原生 Deployment,主要服務于無狀態應用,提供了最為全面豐富的部署發布策略。
CloneSet、Advanced StatefulSet 均支持指定 Pod 升級方式:
所謂原地升級,就是在升級 template 模板的時候,workload 不會把原 Pod 刪除、新建,而是直接在原 Pod 對象上更新對應的 image 等數據。
如上圖所示,在原地升級的時候 CloneSet 只會更新 Pod spec 中對應容器的 image,而后 kubelet 看到 Pod 中這個容器的定義發生了變化,則會把對應的容器停掉、拉取新的鏡像、并使用新鏡像創建啟動容器。另外可以看到在過程中,這個 Pod 的 sandbox 容器以及其他本次未升級的容器還一直處于正常運行狀態,只有需要升級的容器會受到影響。
原地升級給我們帶來的好處實在太多了:
后續我們將會有專文講解阿里在 Kubernetes 之上做的原地升級,意義非常重大。如果沒有了原地升級,阿里巴巴內部超大規模的應用場景幾乎是無法在原生 Kubernetes 環境上完美落地的,我們也鼓勵每一位 Kubernetes 用戶都應該“體驗”一下原地升級,它給我們帶來了不同于 Kubernetes 傳統發布模式的變革。
前一章我們提到了,目前 Deployment 支持 maxUnavailable/maxSurge 的流式升級,而 StatefulSet 支持 partition 的分批升級。但問題在于,Deployment 無法灰度分批,而 StatefulSet 則只能一個一個 Pod 串行發布,沒辦法并行的流式升級。
首先要說的是,我們將 maxUnavailable 引入了 Advanced StatefulSet。原生 StatefulSet 的 one by one 發布,大家其實可以理解為一個強制 maxUnavailable=1 的過程,而 Advanced StatefulSet 中如果我們配置了更大的 maxUnavailable,那么就支持并行發布更多的 Pod 了。
然后我們再來看一下 CloneSet,它支持原生 Deployment 和 StatefulSet 的全部發布策略,包括 maxUnavailable、maxSurge、partition。那么 CloneSet 是如何把它們結合在一起的呢?我們來看一個例子:
apiVersion: apps.kruise.io/v1alpha1
kind: CloneSet
# ...
spec:
replicas: 5 # Pod 總數為 5
updateStrategy:
type: InPlaceIfPossible
maxSurge: 20% # 多擴出來 5 * 20% = 1 個 Pod (rounding up)
maxUnavailable: 0 # 保證發布過程 5 - 0 = 5 個 Pod 可用
partition: 3 # 保留 3 個舊版本 Pod (只發布 5 - 3 = 2 個 Pod)
針對這個副本數為 5 的 CloneSet,如果我們修改了 template 中的 image,同時配置:maxSurge=20% maxUnavailable=0 partition=3。當開始發布后:
如果我們接下來把 partition 調整為 0,則 CloneSet 還是會先擴出 1 個額外的新版 Pod,隨后逐漸將所有 Pod 升級到新版,最終再次刪除一個 Pod,達到 5 個副本全量升級的終態。
對于原生的 Deployment 和 StatefulSet,用戶是無法配置發布順序的。Deployment 下的 Pod 發布順序完全依賴于它修改 ReplicaSet 后的擴縮順序,而 StatefulSet 則嚴格按照 order 的反序來做一一升級。
但在 CloneSet 和 Advanced StatefulSet 中,我們增加了發布順序的可配置能力,使用戶可以定制自己的發布順序。目前可以通過以下兩種發布優先級和一種發布打散策略來定義順序:
apiVersion: apps.kruise.io/v1alpha1
kind: CloneSet
spec:
# ...
updateStrategy:
priorityStrategy:
orderPriority:
- orderedKey: some-label-key
apiVersion: apps.kruise.io/v1alpha1
kind: CloneSet
spec:
# ...
updateStrategy:
priorityStrategy:
weightPriority:
- weight: 50
matchSelector:
matchLabels:
test-key: foo
- weight: 30
matchSelector:
matchLabels:
test-key: bar
apiVersion: apps.kruise.io/v1alpha1
kind: CloneSet
spec:
# ...
updateStrategy:
scatterStrategy:
- key: some-label-key
value: foo
可能有同學會問為什么要配置發布順序呢?比如 zookeeper 這類應用在發布時,需要先把所有非主節點升級,最后再升級主節點,這樣才能保證在整個發布過程中只會發生一次切主。這時用戶就可以通過流程打標、或者寫一個 operator 自動為 zookeeper 的 Pod 打上節點職責的標簽,而后配置非主節點的發布權重較大,使得發布時能夠盡量減少切主的次數。
輕量化容器也是阿里巴巴在云原生階段的一次重大改革,過去阿里的容器絕大多數都是以“富容器”的方式運行的,所謂“富容器”即在一個容器中既運行業務、也跑著各種各樣的插件和守護進程。而在云原生時代,我們在逐漸把原先“富容器”中的旁路插件拆分到獨立的 sidecar 容器中,使主容器逐漸回歸業務自身。
這里對于拆分的好處就不贅述了,我們來看下另一個問題,就是拆分之后這些 sidecar 容器如何做管理呢?最直觀的方式是在每個應用的 workload 中顯示去定義 Pod 中需要的 sidecar,但這樣帶來的問題很多:
因此,我們設計了 SidecarSet,將 sidecar 容器的定義與應用 workload 解耦。應用開發者們不再需要再關心自己的 workload 中需要寫哪些 sidecar 容器,而通過原地升級, sidecar 維護者們也可以自主地管理和升級 sidecar 容器。
到了這里,大家是不是對阿里巴巴的應用部署模式有了一個基本的了解呢?其實上述的能力都已經開源到了社區,我們的項目就叫做 OpenKruise,目前它已經提供了 5 種擴展 workload:
此外,我們還有更多的擴展能力還在開源的路上!近期,我們會將內部的 Advanced DaemonSet 開放到 OpenKruise 中,它在原生 DaemonSet 的 maxUnavailable 之上,額外提供了如分批、selector 等發布策略,分批的功能使 DaemonSet 在發布的時候能夠只升級其中部分 Pod,而 selector 更是允許發布的時候指定先在符合某些標簽的 node 上升級,這為我們在大規模集群中升級 DaemonSet 帶來了灰度能力和穩定性的保障。
而后續,我們還計劃將阿里巴巴內部擴展的 HPA、調度插件等通用化能力開放出來,讓每一位 Kubernetes 開發者和阿里云上的用戶都能很便捷地使用上阿里內部開發應用的云原生增強能力。
最后,我們也歡迎每一位云原生愛好者來共同參與 OpenKruise 的建設。與其他一些開源項目不同,OpenKruise 并不是阿里內部代碼的復刻;恰恰相反,OpenKruise Github 倉庫是阿里內部代碼庫的 upstream。因此,每一行你貢獻的代碼,都將運行在阿里內部的所有 Kubernetes 集群中、都將共同支撐了阿里巴巴全球頂尖規模的應用場景!
Q1:目前阿里最大規模的業務 pod 數量有多少,發布一次需要多少時間?
A1:這個只能透露數量目前最大規模的單個應用下數量是以萬為單位的,一次發布時間要看具體分批灰度的時長了。如果分批較多、觀察時間較長的話,可能是會持續一兩周的。
Q2:pod 的資源 request 和 limit 是怎么配置的?request 和 limit 是什么比例來配置?過多的 request 造成浪費,過少可能會導致熱點 node 負載超高。
A2:這個主要還是根據應用的需求來定的,目前大部分在線應用都是 1:1 的關系,部分離線和job 類型的會配置 request>limit。
Q3:kruise 升級問題,升級 kurise apiversion 版本的情況下,原有的版本的部署如何升級?
A3:目前 kruise 中資源的 apiVersion 還都是統一的。我們計劃在今年下半年將部分較為成熟的 workload 進行版本升級,用戶在自己的 K8s 集群內升級后,存量的舊版本資源會自動通過 conversion 升級到新版本。
Q4:OpenKruise 有提供 go-client 嗎?
A4:目前提供兩個方式:1. 引入 github.com/openkruise/kruise/pkg/client 包,下面有生成好的 clientset / informer / lister 等工具;2. 使用 controller-runtime 的用戶(包括 kubebuilder、operator-sdk),直接引入 github.com/openkruise/kruise-api 輕量化依賴,然后加到 scheme 里就能直接用了。
Q5:阿里 K8s 版本升級是如何做的?
A5:阿里集團內部使用 Kube-On-Kube 的架構進行大規模的 Kubernetes 集群管理,用一個元 K8s 集群管理成百上千個業務 K8s 集群。其中元集群版本較為穩定,業務集群會進行頻繁升級,業務集群的升級流程事實上就是對元集群中的 workloads(原生 workloads 以及 kruise workloads) 進行版本或配置升級,與正常情況我們對業務 workloads 的升級流程相似。
Q6:這個灰度之后,流量是怎么切的?
A6:在原地升級前,kruise 會先通過 readinessGate 將 Pod 置為 not-ready,此時 endpoint 等控制器會感知到并把 Pod 從端點摘掉。然后 kruise 更新 pod image 觸發容器重建,完成后再把 Pod 改為 ready。
Q7:daemonset 的分批是通過類似 deployment 的暫停功能實現的么?統計已經發布數量然后暫停,然后繼續,然后再暫停。
A7:總體過程上類似,升級過程中對新舊版本進行統計并判斷是否已達到指定終態。但相比 deployment,daemonset 需要處理比較復雜的邊界情況(例如初次發布時集群中并沒有指定的 Pod),具體細節可以持續關注我們即將開源的代碼。
Q8:多集群的發布頁面上怎么開始發布的?
A8:直播中演示的是一個 demo 的發布系統結合 Kruise Workloads 的例子,從交互上是通過用戶選擇對應的集群,點擊開始執行進行發布;從實現上實際是對新版本的 YAML 與集群中的 YAML 計算 diff 后 Patch 進集群,再操作 DaemonSet 的控制字段(partition / paused 等),控制灰度進程。
“ 阿里巴巴云原生關注微服務、Serverless、容器、Service Mesh 等技術領域、聚焦云原生流行技術趨勢、云原生大規模的落地實踐,做最懂云原生開發者的公眾號。”
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。