如何爲雲原生應用帶來穩定高效的部署能力?

簡介:5 月 28 日,咱們發起了第 3 期 SIG Cloud-Provider-Alibaba 網研會直播。本文聚集了這次直播完整視頻回顧及資料下載,並整理了直播過程當中收集的問題和解答,但願可以對你們有所幫助~node

頭圖.png

做者 | 酒祝  阿里雲技術專家、墨封  阿里雲開發工程師git

直播完整視頻回顧:https://www.bilibili.com/video/BV1mK4y1t7WS/github

關注「阿里巴巴雲原生」公衆號,後臺回覆 「528」 便可下載 PPTapi

5 月 28 日,咱們發起了第 3 期 SIG Cloud-Provider-Alibaba 網研會直播。本次直播主要介紹了阿里經濟體大規模應用上雲過程當中遇到的核心部署問題、採起的對應解決方案,以及這些方案沉澱爲通用化能力輸出開源後,如何幫助阿里雲上的用戶提高應用部署發佈的效率與穩定性。網絡

本文聚集了這次直播完整視頻回顧及資料下載,並整理了直播過程當中收集的問題和解答,但願可以對你們有所幫助~架構

講師圖片.jpg

前言

隨着近年來 Kubernetes 逐漸成爲事實標準和大量應用的雲原生化,咱們每每發現 Kubernetes 的原生 workload 對大規模化應用的支持並不十分「友好」。如何在 Kubernetes 上爲應用提供更加完善、高效、靈活的部署發佈能力,成爲了咱們探索的目標。app

本文將會介紹在阿里經濟體全面接入雲原生的過程當中,咱們在應用部署方面所作的改進優化、實現功能更加完備的加強版 workload、並將其開源到社區,使得如今每一位 Kubernetes 開發者和阿里雲上的用戶都能很便捷地使用上阿里巴巴內部雲原生應用所統一使用的部署發佈能力。less

阿里應用場景與原生 workloads

阿里巴巴容器化道路的起步在國內外都是比較領先的。容器這個技術概念雖然出現得很早,但一直到 2013 年 Docker 產品出現後才逐漸爲人所熟知。而阿里巴巴早在 2011 年就開始發展了基於 LXC 的容器技術,通過了幾代的系統演進,現在阿里巴巴有着超過百萬的容器體量,這個規模在世界範圍內都是頂尖的。運維

隨着雲技術發展和雲原生應用的興起,咱們近兩年間逐步將過去的容器遷到了基於 Kubernetes 的雲原生環境中。而在這其中,咱們遇到了很多應用部署方面的問題。首先對於應用開發者來講,他們對遷移到雲原生環境的指望是:ide

  • 面向豐富業務場景的策略功能
  • 極致的部署發佈效率
  • 運行時的穩定性和容錯能力

阿里的應用場景很是複雜,基於 Kubernetes 之上生長着不少不一樣的 PaaS 二層,好比服務於電商業務的運維中臺、規模化運維、中間件、Serverless、函數計算等,而每一個平臺都對部署、發佈要求各有不一樣。

咱們再來看一下 Kubernete 原生所提供的兩種經常使用 workload 的能力:

1.png

簡單來講,Deployment 和 StatefulSet 在一些小規模的場景下是能夠 work 的;但到了阿里巴巴這種應用和容器的規模下,若是全量使用原生 workload 則是徹底不現實的。目前阿里內部容器集羣上的應用數量超過十萬、容器數量達到百萬,有部分重點核心應用甚至單個應用下就有上萬的容器。再結合上圖的問題,咱們會發現不只針對單個應用的發佈功能不足,並且當發佈高峯期大量應用同時在升級時,超大規模的 Pod 重建也成爲一種「災難」。

阿里自研的擴展 workloads

針對原生 workload 遠遠沒法知足應用場景的問題,咱們從各類複雜的業務場景中抽象出共通的應用部署需求,據此開發了多種擴展 workload。在這些 workload 中咱們作了大幅的加強和改進,但同時也會嚴格保證功能的通用化、不容許將業務邏輯耦合進來。

這裏咱們重點介紹一下 CloneSet 與 Advanced StatefulSet。在阿里內部雲原生環境下,幾乎全量的電商相關應用都統一採用 CloneSet 作部署發佈,而中間件等有狀態應用則使用了 Advanced StatefulSet 管理。

2.png

Advanced StatefulSet 顧名思義,是原生 StatefulSet 的加強版,默認行爲與原生徹底一致,在此以外提供了原地升級、並行發佈(最大不可用)、發佈暫停等功能。而 CloneSet 則對標原生 Deployment,主要服務於無狀態應用,提供了最爲全面豐富的部署發佈策略。

原地升級

CloneSet、Advanced StatefulSet 均支持指定 Pod 升級方式:

  1. ReCreate:重建 Pod 升級,和原生 Deployment/StatefulSet 一致;
  2. InPlaceIfPossible:若是隻修改 image 和 metadata 中的 labels/annotations 等字段,則觸發 Pod 原地升級;若是修改了其餘 template spec 中的字段,則退化到 Pod 重建升級;
  3. InPlaceOnly:只容許修改 image 和 metadata 中的 labels/annotations 等字段,只會使用原地升級。

所謂原地升級,就是在升級 template 模板的時候,workload 不會把原 Pod 刪除、新建,而是直接在原 Pod 對象上更新對應的 image 等數據。

3.png

如上圖所示,在原地升級的時候 CloneSet 只會更新 Pod spec 中對應容器的 image,然後 kubelet 看到 Pod 中這個容器的定義發生了變化,則會把對應的容器停掉、拉取新的鏡像、並使用新鏡像建立啓動容器。另外能夠看到在過程當中,這個 Pod 的 sandbox 容器以及其餘本次未升級的容器還一直處於正常運行狀態,只有須要升級的容器會受到影響。

原地升級給咱們帶來的好處實在太多了:

  • 首先就是發佈效率大大提高了,根據非徹底統計數據,在阿里環境下原地升級至少比徹底重建升級提高了 80% 以上的發佈速度:不只省去了調度、分配網絡、分配遠程盤的耗時,連拉取新鏡像的時候都得益於 node 上已有舊鏡像、只須要拉取較少的增量 layer);
  • IP 不變、升級過程 Pod 網絡不斷,除本次升級外的其餘容器保持正常運行;
  • Volume 不變,徹底複用原容器的掛載設備;
  • 保障了集羣肯定性,使排布拓撲能經過大促驗證。

後續咱們將會有專文講解阿里在 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。當開始發佈後:

  1. 先擴出來 1 個新版本的 Pod,5 個存量 Pod 保持不動;
  2. 新 Pod ready 後,逐步把舊版本 Pod 作原地升級;
  3. 直到剩餘 3 箇舊版本 Pod 時,由於知足了 partition 終態,會把新版本 Pod 再刪除 1 個;
  4. 此時 Pod 總數仍然爲 5,其中 3 箇舊版本、1 個新版本。

若是咱們接下來把 partition 調整爲 0,則 CloneSet 仍是會先擴出 1 個額外的新版 Pod,隨後逐漸將全部 Pod 升級到新版,最終再次刪除一個 Pod,達到 5 個副本全量升級的終態。

發佈順序可配置

對於原生的 Deployment 和 StatefulSet,用戶是沒法配置發佈順序的。Deployment 下的 Pod 發佈順序徹底依賴於它修改 ReplicaSet 後的擴縮順序,而 StatefulSet 則嚴格按照 order 的反序來作一一升級。

但在 CloneSet 和 Advanced StatefulSet 中,咱們增長了發佈順序的可配置能力,使用戶能夠定製本身的發佈順序。目前能夠經過如下兩種發佈優先級和一種發佈打散策略來定義順序:

  • 優先級(1):按給定 label key,在發佈時根據 Pod labels 中這個 key 對應的 value 值做爲權重:
apiVersion: apps.kruise.io/v1alpha1
kind: CloneSet
spec:
  # ...
  updateStrategy:
    priorityStrategy:
      orderPriority:
        - orderedKey: some-label-key
  • 優先級(2):按 selector 匹配計算權重,發佈時根據 Pod 對多個 weight selector 的匹配狀況計算權重總和:
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
  • 打散:將匹配 key-value 的 Pod 打散到不一樣批次中發佈:
apiVersion: apps.kruise.io/v1alpha1
kind: CloneSet
spec:
  # ...
  updateStrategy:
    scatterStrategy:
    - key: some-label-key
      value: foo

可能有同窗會問爲何要配置發佈順序呢?好比 zookeeper 這類應用在發佈時,須要先把全部非主節點升級,最後再升級主節點,這樣才能保證在整個發佈過程當中只會發生一次切主。這時用戶就能夠經過流程打標、或者寫一個 operator 自動爲 zookeeper 的 Pod 打上節點職責的標籤,然後配置非主節點的發佈權重較大,使得發佈時可以儘可能減小切主的次數。

sidecar 容器管理

輕量化容器也是阿里巴巴在雲原生階段的一次重大改革,過去阿里的容器絕大多數都是以「富容器」的方式運行的,所謂「富容器」即在一個容器中既運行業務、也跑着各類各樣的插件和守護進程。而在雲原生時代,咱們在逐漸把原先「富容器」中的旁路插件拆分到獨立的 sidecar 容器中,使主容器逐漸迴歸業務自身。

這裏對於拆分的好處就不贅述了,咱們來看下另外一個問題,就是拆分以後這些 sidecar 容器如何作管理呢?最直觀的方式是在每一個應用的 workload 中顯示去定義 Pod 中須要的 sidecar,但這樣帶來的問題不少:

  1. 當應用和 workload 數量衆多時,咱們很難統一的 sidecar 增減管理;
  2. 應用開發者不知道(甚至也不關心)本身的應用須要配置哪些 sidecar 容器;
  3. 當 sidecar 鏡像須要升級時,要把全部應用的 workload 所有升級一遍,很不現實。

所以,咱們設計了 SidecarSet,將 sidecar 容器的定義與應用 workload 解耦。應用開發者們再也不須要再關心本身的 workload 中須要寫哪些 sidecar 容器,而經過原地升級, sidecar 維護者們也能夠自主地管理和升級 sidecar 容器。

4.png

開放能力應用

到了這裏,你們是否是對阿里巴巴的應用部署模式有了一個基本的瞭解呢?其實上述的能力都已經開源到了社區,咱們的項目就叫作OpenKruise,目前它已經提供了 5 種擴展 workload:

  • CloneSet:提供了更加高效、肯定可控的應用管理和部署能力,支持優雅原地升級、指定刪除、發佈順序可配置、並行/灰度發佈等豐富的策略,能夠知足更多樣化的應用場景;
  • Advanced StatefulSet:基於原生StatefulSet之上的加強版本,默認行爲與原生徹底一致,在此以外提供了原地升級、並行發佈(最大不可用)、發佈暫停等功能;
  • SidecarSet:對 sidecar 容器作統一管理,在知足 selector 條件的 Pod 中注入指定的 sidecar 容器;
  • UnitedDeployment:經過多個 subset workload 將應用部署到多個可用區;
  • BroadcastJob:配置一個 job,在集羣中全部知足條件的 Node 上都跑一個 Pod 任務。

此外,咱們還有更多的擴展能力還在開源的路上!近期,咱們會將內部的 Advanced DaemonSet 開放到 OpenKruise 中,它在原生 DaemonSet 的 maxUnavailable 之上,額外提供瞭如分批、selector 等發佈策略,分批的功能使 DaemonSet 在發佈的時候可以只升級其中部分 Pod,而 selector 更是容許發佈的時候指定先在符合某些標籤的 node 上升級,這爲咱們在大規模集羣中升級 DaemonSet 帶來了灰度能力和穩定性的保障。

然後續,咱們還計劃將阿里巴巴內部擴展的 HPA、調度插件等通用化能力開放出來,讓每一位 Kubernetes 開發者和阿里雲上的用戶都能很便捷地使用上阿里內部開發應用的雲原生加強能力。

最後,咱們也歡迎每一位雲原生愛好者來共同參與 OpenKruise 的建設。與其餘一些開源項目不一樣,OpenKruise 並非阿里內部代碼的復刻;偏偏相反,OpenKruise Github 倉庫是阿里內部代碼庫的 upstream。所以,每一行你貢獻的代碼,都將運行在阿里內部的全部 Kubernetes 集羣中、都將共同支撐了阿里巴巴全球頂尖規模的應用場景!

Q & A

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 等),控制灰度進程。

相關文章
相關標籤/搜索