K8s 集羣節點在線率達到 99.9% 以上,擴容效率提高 50%,咱們作了這 3 個深度改造

點擊下載《不同的 雙11 技術:阿里巴巴經濟體雲原生實踐》git

file

本文節選自《不同的 雙11 技術:阿里巴巴經濟體雲原生實踐》一書,點擊上方圖片便可下載!github

做者 | 張振(守辰)阿里云云原生應用平臺高級技術專家數據庫

導讀:2019 年阿里巴巴核心系統 100% 以雲原生方式上雲,完美地支撐了 雙11 大促。此次上雲的姿式很不通常,不只是擁抱了 Kubernetes,並且還以擁抱 Kubernetes 爲契機進行了一系列對運維體系的深度改造。api

Kubernetes 做爲雲原生的最佳實踐,已經成爲了事實上的容器編排引擎標準,Kubernetes 在阿里巴巴集團落地主要經歷了四個階段:緩存

  • 研發和探索:2017 年下半年阿里巴巴集團開始嘗試使用 Kubernetes api 來改造內部自研平臺,並開始了對應用交付鏈路的改造,以適配 Kubernetes;
  • 初步灰度:  2018 年下半年阿里巴巴集團和螞蟻金服共同投入 Kubernetes 技術生態的研發,力求經過 Kubernetes 替換內部自研平臺,實現了小規模的驗證,支撐了當年部分 雙11 的流量;
  • 雲化灰度:  2019 年初阿里巴巴經濟體開始進行全面上雲改造,阿里巴巴集團經過從新設計 Kubernetes 落地方案,適配雲化環境,改造落後運維習慣,在 618 前完成了雲化機房的小規模驗證;
  • 規模化落地:2019 年 618 以後,阿里巴巴集團內部開始全面推進 Kubernetes 落地,在大促以前完成了所有核心應用運行在 Kubernetes 的目標,並完美支撐了 雙11 大考。

在這幾年的實踐中,一個問題始終縈繞在各個架構師的頭腦中: 在阿里巴巴這麼大致量、這麼複雜的業務下, 遺留了大量傳統的運維習慣以及支撐這些習慣的運維體系,落地 Kubernetes 到底要堅持什麼?要妥協什麼?要改變什麼?服務器

本文將分享阿里巴巴這幾年對於這些問題的思考。答案很明顯:擁抱 Kubernetes 自己並非目的,而是經過擁抱 Kubernetes 撬動業務的雲原生改造,經過 Kubernetes 的能力,治理傳統運維體系下的沉痾頑疾,釋放雲彈性的能力,爲業務的應用交付解綁提速。微信

在阿里巴巴的 Kubernetes 落地實踐中,關注了下面幾個關鍵的雲原生改造:架構

面向終態改造

在阿里巴巴傳統的運維體系下,應用的變動都是 PaaS 經過建立操做工單,發起工做流,繼而對容器平臺發起一個個的變動來完成的。併發

當應用發佈時, PaaS 會從數據庫中查到應用全部相關的容器,並針對每一個容器,向容器平臺發起修改容器鏡像的變動。每個變動實際上也是一個工做流,涉及到鏡像的拉取、舊容器的中止和新容器的建立。工做流中一旦發生錯誤或者超時,都須要 PaaS 進行重試。通常而言,爲了保證工單及時的完成,重試僅會執行幾回,幾回重試失敗後,只能依靠人工處理。less

當應用縮容時,PaaS 會根據運維人員的輸入,指定容器列表進行刪除,一旦其中有容器由於宿主機異常的狀況下刪除失敗或者超時,PaaS 只能反覆重試,爲了保證工單的結束,在重試必定次數後只能認爲容器刪除成功。若是宿主機後續恢復正常,被「刪除」的容器頗有可能依然運行着。

傳統的面向過程的容器變動一直存在以下問題沒法解決:

  • 單個變動失敗沒法保證最終成功

例如,一旦容器鏡像變動失敗,PaaS 沒法保證容器鏡像的最終一致;一旦刪除容器失敗,
也沒法保證容器最後真的被刪除乾淨。兩個例子都須要經過巡檢來處理不一致的容器。而巡檢任務由於執行較少,其正確性和及時性都很難保證;

  • 多個變動會發生衝突

例如應用的發佈和應用的擴容過程須要加鎖,不然會出現新擴的容器鏡像未更新的狀況。而一旦對變動進行加鎖,變動的效率又會大幅降低。

Kubernetes 的能力提供瞭解決這個問題的機會。Kubernetes 的 workload 提供了聲明式的 API 來修改應用的實例數和版本,workload 的控制器能夠監聽 pod 的實際狀況,保證應用 pod 的實例數量和版本符合終態,避免了併發擴容和發佈的衝突問題。Kubernetes 的 kubelet 會依據 pod 的 spec,反覆嘗試啓動 pod,直到 pod 符合 spec 描述的終態。重試由容器平臺內部實現,再也不和應用的工單狀態綁定。

自愈能力改造

在阿里巴巴傳統的運維體系下,容器平臺僅生產資源,應用的啓動以及服務發現是在容器啓動後由 PaaS 系統來執行的,這種分層的方法給了 PaaS 系統最大的自由,也在容器化後促進了阿里巴巴第一波容器生態的繁榮。可是這種方式有一個嚴重的問題,即:
容器平臺沒法獨立地去觸發容器的擴縮容,須要和一個個 PaaS 來作複雜的聯動,上層 PaaS 也須要作不少重複的工做。這妨礙了容器平臺在宿主機發生故障、重啓、容器中進程發生異常、卡住時的高效自愈修復,也讓彈性擴縮容變得很是複雜。

在 Kubernetes 中經過容器的命令以及生命週期鉤子,能夠將 PaaS 啓動應用以及檢查應用啓動狀態的流程內置在了 pod 中;另外,經過建立 service 對象,能夠將容器和對應的服務發現機制關聯起來,從而實現容器、應用、服務生命週期的統一。容器平臺再也不僅僅生產資源,而是交付能夠直接爲業務使用的服務。這極大地簡化了上雲以後故障自愈以及自動彈性擴縮容能力的建設,
真正地發揮了雲的彈性能力。

另外,在宿主機發生故障的狀況下,PaaS 傳統上須要先對應用進行擴容,而後才刪除宿主機上的容器。然而在大規模的集羣下,咱們發現每每會卡在應用擴容這步。應用資源額度可能不夠,集羣內知足應用調度限制的空閒資源也可能不夠,沒法擴容就沒法對宿主機上的容器進行驅逐,進而也沒法對異常的宿主機進行送修,長此以往,整個集羣很容易就陷入故障機器一大堆,想修修不了、想騰騰不動的困境之中。

在 Kubernetes 中對於故障機的處理要「簡單和粗暴」得多,再也不要求對應用先擴容,而是直接把故障機上的容器進行刪除,刪除後才由負載控制器進行擴容。這種方案乍一聽簡直膽大妄爲,落地 Kubernetes 的時候不少 PaaS 的同窗都很是排斥這種方法,認爲這會嚴重影響業務的穩定性。事實上,絕大多數核心的業務應用都維護着必定的冗餘容量,以便全局的流量切換或者應對突發的業務流量,臨時刪除必定量的容器根本不會形成業務的容量不足。

咱們所面臨的關鍵問題是如何肯定業務的可用容量,固然這是個更難的問題,但對於自愈的場景徹底不須要準確的容量評估,只須要一個能夠推進自愈運轉的悲觀估計就能夠。在 Kubernetes 中能夠經過 PodDisruptionBudget 來定量地描述對應用的可遷移量,例如能夠設置對應用進行驅逐的併發數量或者比例。這個值能夠參考發佈時的每批數量佔比來設置。假如應用發佈通常分 10 批,那麼能夠設置 PodDisruptionBudget 中的 maxUnavailable 爲 10%(對於比例,若是應用只有 10 個之內的實例,Kubernetes 仍是認爲能夠驅逐 1 個實例)。萬一應用真的一個實例都不容許驅逐呢?那麼對不起,這樣的應用是須要改造以後才能享受上雲的收益的。通常應用能夠經過改造自身架構,或者經過 operator 來自動化應用的運維操做,從而容許實例的遷移。<

不可變基礎設施改造

Docker 的出現提供了一種統一的應用交付形式,經過把應用的二進制、配置、依賴統一在構建過程當中打到了鏡像中,
經過使用新的鏡像建立容器,並刪除掉舊容器就完成了應用的變動。Docker 在交付應用時和傳統基於軟件包或者腳本的交付方式有一個重大區別,就是強制了容器的不可變,想要變動容器只能經過新建立容器來完成,而每一個新容器都是從應用同一個鏡像建立而來,確保了一致性,從而避免了配置漂移,或者雪花服務器的問題。

Kubernetes 進一步強化了不可變基礎設施的理念,在默認的滾動升級過程當中不但不會變動容器,並且還不會變動pod。每次發佈,都是經過建立新的 pod,並刪除舊的 pod 來完成,這不只保證了應用的鏡像統一,還保證了數據卷、資源規格以及系統參數配置都是和應用模板的 spec 保持一致。

另外,很多應用都有比較複雜的結構,一個應用實例可能同時包含多個團隊獨立開發的組件。 好比一個應用可能包括了業務相關的應用程序服務器,也包括了基礎設施團隊開發的日誌採集進程,甚至還包括了第三方的中間件組件。這些進程、組件若是想要獨立發佈就不能放在一個應用鏡像中,爲此 Kubernetes 提供了多容器 pod 的能力,能夠在一個 pod 中編排多個容器,想要發佈單個組件,只須要修改對應容器的鏡像便可。

不過,阿里巴巴傳統的容器形態是富容器,即應用程序服務器,以及日誌採集進程等相關的組件都部署在一個大的系統容器中,這形成了日誌採集等組件的資源消耗沒法單獨限制,也沒法方便地進行獨立升級。所以,在阿里巴巴此次上雲中,開始把系統容器中除業務應用外的其餘組件都拆分到獨立的 sidecar 容器,咱們稱之爲輕量化容器改造。改造後,一個 pod 內會包括一個運行業務的主容器、一個運行着各類基礎設施 agent 的運維容器,以及服務網格等的sidecar容器。輕量化容器以後, 業務的主容器就能以比較低的開銷運行業務服務,從而更方便進行 serverless 的相關改造。

不過,Kubernetes 默認的滾動升級過程過於僵硬地執行了不可變基礎設施的理念,致使對多容器 pod 的能力支持有嚴重的缺失。雖然能夠在一個 pod 中編排多個容器,但若是要發佈 pod 中的一個容器,在實際執行發佈時,不只會重建待發布的容器,還會把整個 pod 都刪除,然後重調度、再重建。這意味着假如要升級基礎設施的日誌採集組件,會致使其餘組件,特別是業務的應用服務器被一塊兒刪除重啓,從而干擾到正常的業務運行。所以,多個組件的變動依然沒有解耦。

對業務而言,假如 pod 中有本地緩存的組件,而每次業務的發佈都會重啓緩存進程,這會致使業務發佈期間緩存的命中率大幅降低,影響性能甚至用戶的體驗;另外,若是基礎設施、中間件等團隊的組件升級都和業務的組件升級綁定在一塊兒,這會給技術的迭代更新帶來巨大的阻礙。假設負責中間件的團隊推出了新的 service mesh 版本, 而爲了升級 mesh 還須要央求一個個業務發佈才能更新 mesh 組件,那麼中間件的技術升級就會大大減速。

所以,相比 pod 層次的不可變,咱們認爲堅持容器級別的不可變原則,更能發揮 Kubernetes 多容器 pod 的技術優點。爲此,咱們建設了支持應用發佈時只原地修改 pod 中部分容器的能力,特別地建設了支持容器原地升級的工做負載控制器,並替換 Kubernetes 默認的 deployment 和 statefulset 控制器做爲內部的主要工做負載。

另外,還建設了支持跨應用進行 sidecar 容器升級的 sidecarset, 方便進行基礎設施以及中間件組件的升級。此外,經過支持原地升級還帶來了集羣分佈肯定性、加速鏡像下載等的額外優點。這部分能力,咱們已經經過 OpenKruise 項目開源出來。OpenKruise 中的 Kruise 是 cruise的諧音,'K' for Kubernetes, 寓意 Kubernetes 上應用的自動巡航,滿載着阿里巴巴多年應用部署管理經驗和阿里巴巴經濟體雲原生化歷程的最佳實踐。目前,OpenKruise 正在計劃發佈更多的 Controller 來覆蓋更多的場景和功能,好比豐富的發佈策略、金絲雀發佈、藍綠髮布、分批發布等等。

總結

今年咱們實現了 Kubernetes 的規模化落地,經受了 雙11 大促真實場景的考驗。像阿里巴巴這樣有着大量存量應用的場景,落地 K8s 並無捷徑,咱們經受住了快速規模化落地的誘惑,沒有選擇兼容和妥協落後的運維習慣,而是選擇深蹲打好基礎、選擇深挖雲原生價值。接下來,咱們將繼續推進更多應用的雲原生改造,特別是有狀態應用的改造,讓有狀態應用的部署和運維更加高效;另外,還將推進整個應用交付鏈路的雲原生改造,讓應用交付更加高效和標準化。

file

本書亮點

  • 雙11 超大規模 K8s 集羣實踐中,遇到的問題及解決方法詳述
  • 雲原生化最佳組合:Kubernetes+容器+神龍,實現核心系統 100% 上雲的技術細節
  • 雙 11 Service Mesh 超大規模落地解決方案

「 阿里巴巴雲原生微信公衆號(ID:Alicloudnative)關注微服務、Serverless、容器、Service Mesh等技術領域、聚焦雲原生流行技術趨勢、雲原生大規模的落地實踐,作最懂雲原生開發者的技術公衆號。」

更多相關信息,關注「阿里巴巴雲原生」

相關文章
相關標籤/搜索