做者 | 孫健波(天元) 阿里巴巴技術專家python
本文整理自 11 月 21 日社羣分享,每個月 2 場高質量分享,點擊加入社羣。git
早在 2011 年,阿里巴巴內部便開始了應用容器化,當時最開始是基於 LXC 技術構建容器,而後逐漸切換到 Docker,自研了大規模編排調度系統。到了 2018 年,咱們團隊依託 K8s 體系開始推動「輕量級容器化」,同時投入了工程力量跟開源社區一塊兒解決了諸多規模與性能問題,從而逐步將過去「類虛擬機」的運維鏈路和阿里巴巴總體應用基礎設施架構升級到了雲原生技術棧。github
到了 2019 年,Kubernetes 基礎設施底盤在阿里巴巴經濟體中已經覆蓋了阿里巴巴方方面面的業務,規模化的接入了包括核心電商、物流、金融、外賣、搜索、計算、AI 等諸多頭部互聯網場景。這套技術底盤,也逐步成爲了阿里巴巴支撐 61八、雙11 等互聯網級大促的主力軍之一。數據庫
目前,阿里巴巴與螞蟻金服內部運行了數十個超大規模的 K8s 集羣,其中最大的集羣約 1 萬個機器節點,而其實這還不是能力上限。每一個集羣都會服務上萬個應用。在阿里雲 Kubernetes 服務(ACK)上,咱們還維護了上萬個用戶的 K8s 集羣,這個規模和其中的技術挑戰在全世界也是數一數二的。安全
在規模和性能等基礎設施領域問題逐步解決的同時,規模化鋪開 Kubernetes 的過程當中,咱們逐步發現這套體系裏其實還有不少意想不到的挑戰。這也是今天分享的主題。微信
第一個是 K8s 的 API 裏其實並無「應用」的概念架構
並且,Kubernetes API 的設計把研發、運維還有基礎設施關心的事情全都糅雜在一塊兒了。這致使研發以爲 K8s 太複雜,運維以爲 K8s 的能力很是凌亂、零散,很差管理,只有基礎設施團隊(也就是咱們團隊)以爲 Kubernetes 比較好用。可是基礎設施團隊也很難跟研發和運維解釋清楚 Kubernetes 的價值究竟是什麼。app
咱們來看個實際的例子。less
就拿上圖中的 replica 爲 3 來講,開發人員怎麼知道實例數應該配幾個呢?若是運維想要改replica,敢不敢改?能不能改?若是 replica 還能理解的話,那像 shareProcessNamespace 這種字段真是靈魂拷問了。 開發人員僅從字面意思知道這個可能跟容器進程共享有關,那麼配置了這個應用會有什麼影響呢?會不會有安全問題?運維
在阿里巴巴內部,不少 PaaS 平臺只容許開發填 Deployment 的極個別字段。爲何容許填的字段這麼少?是平臺能力不夠強嗎?其實不是的,本質緣由在於業務開發根本不想理解這衆多的字段。
因此這個 PaaS 平臺只容許用戶填個別字段,其實反卻是幫助業務開發人員避免了這些靈魂拷問。但反過來想,屏蔽掉大量字段真的就解決問題了嗎?這種狀況下,整個組織的基礎設施能力還如何演進?應用開發和應用運維人員的訴求又該怎麼傳遞給基礎設施呢?
實際上,歸根到底,Kubernetes 是一個 Platform for Platform 項目,它的設計是給基礎設施工程師用來構建其餘平臺用的(好比 PaaS 或者 Serverless),而不是直面研發和運維同窗的。從這個角度來看,Kubernetes 的 API,其實能夠類比於 Linux Kernel 的 System Call,這跟研發和運維真正要用的東西(Userspace 工具)徹底不是一個層次上的。你總不能讓原本寫 Java Web 的同窗天天直接調用着 Linux Kernel System Call,還給你點贊吧?
第二, K8s 實在是太靈活了,插件太多了,各類人員開發的 Controller 和 Operator 也很是多。
這種靈活性,讓咱們團隊開發各類能力很容易,但也使得對於應用運維來講, K8s 的這些能力管理變得很是困難。好比一個環境裏的不一樣運維能力,實際上有多是衝突的。
咱們來看一個例子,基礎設施團隊最近開發上線了一個新的插件,叫作 CronHPA,一個具體的 Spec 以下所示。
做爲基礎設施團隊,咱們以爲這種 K8s 插件很簡單, CRD 也很容易理解。就像這個 CronHPA 的功能,從早上六點開始到下午七點鐘這個實例最少有 20 個、最多有 25 個,到次日早上六點鐘最少 1 個、最多有 9 個,在每一個階段會根據 CPU 這個指標衡量調整實例數。
然而,就在咱們美滋滋的上線這個插件後不久,應用運維同窗就開始跟咱們抱怨了:
第三,也是阿里巴巴上雲以後咱們團隊特別痛的一個點。
咱們須要處理的應用的交付場景,除了公有云之外,還會有專有云、混合雲、IoT 等各類複雜的環境。各類各樣的雲服務在這種複雜場景下,連 API 都是不統一的,這個時候咱們就須要專門的交付團隊來進行彌補,一個一個的去對接、去交付應用。對他們來講這是一件很是痛苦的事情:「不是說好的 Docker 化了以後就能‘一次打包、隨處運行’了嗎?」說白了,K8s 如今並無一個統一的、平臺無關的應用描述能力。
在 2019 年,咱們團隊開始思考如何經過技術手段解決上述應用管理與交付相關的問題,到如今已經取得了必定的成果。
不過,在講解阿里巴巴如何解決上述問題的方案以前,有必要先介紹一下咱們推動全部這些方案的理論基礎。在這裏,咱們主要遵循的是 CNCF 倡導的「應用交付分層模型」,以下圖所示:
這個模型的基礎假設是:Kubernetes 自己並不提供完整的應用管理體系。換句話說,基於 K8s 的應用管理體系,不是一個開箱即用的功能,而是須要基礎設施團隊基於雲原生社區和生態本身構建出來的。這裏面就須要引入不少開源項目或者能力。
而上面這個模型的一個重要做用,就是可以把這些項目和能力以及它們的協做關係,很是清晰地分類和表達出來。
這些層次之間,經過相互之間的緊密協做,共同構建出一套高效、簡潔的應用管理與交付體系。在這些層次當中,目前阿里巴巴在今年 KubeCon 時已經宣佈開源了第三層的 OpenKruise 項目。最近,咱們則正在聯合微軟等更普遍的生態,和整個社區一塊兒推動第一層「應用定義」相關的工做。
其實,關於應用定義,不管是開源社區仍是在阿里巴巴內部,都已經作了很多嘗試,好比一開始我提到 Docker 解決了單機應用交付,它就經過 Docker 鏡像把單機應用定義的很好。
圍繞 Kubernetes 咱們也試過使用 Helm 以及 Application CRD 來定義應用。可是如今的雲原生應用,每每會依賴雲上的資源,像數據庫會依賴 RDS、訪問會依賴 SLB,Helm 和 Application CRD 只是單純地將 K8s 的 API 組合在一塊兒,沒法描述咱們對雲上面資源的依賴,當咱們用 CRD 來描述雲上資源依賴的時候,它實際上是 freestyle 的,沒有一個很好的規範和約束,不管是用戶、開發、運維仍是平臺資源提供方都沒有一個共識,天然也就沒法協做和複用。
另外一方面,它們既然是簡單的對 K8s API 的組合,那麼 K8s API 自己「不面向應用研發和運維設計」的問題就依然存在,這並不符合咱們所但願的「應用定義」應該走的方向。此外,像 Application CRD,它雖然是 K8s 社區的項目,可是卻明顯缺少社區活躍度,大多數修改都停留在一年前。
試了一圈,咱們發現「應用定義」這個東西,在整個雲原生社區裏實際上是缺失的。這也是爲何阿里巴巴內部有不少團隊開始嘗試設計了本身的「定義應用」。簡單地說,這個設計其實就是把應用自己的鏡像、啓動參數、依賴的雲資源等等所有描述起來,分門別類的進行放置,並經過一個模板,最終渲染出一個配置文件,文件裏有上千個字段,完整描述了一個應用定義的全部內容。這個配置文件大概長下面這個樣子:
除了基本的 Deployment 描述字段,這種 in-house 應用定義每每還會包含雲上資源的聲明,好比使用哪一種 ECS 套餐、如何續費、使用的是哪一種磁盤和規格等等一系列額外的描述。這些資源的定義是一大塊,而且上面的例子裏咱們已經儘可能精簡了;另外一大塊就是運維能力的描述,好比自動擴縮容、流量切換、灰度、監控等,涉及到一系列的規則。
然而,你也不難看到,這種定義方式最終全部的配置仍是會所有堆疊到一個文件裏,這跟 K8s API all-in-one 的問題是同樣的,甚至還更嚴重了。並且,這些應用定義最終也都成爲了黑盒,除了對應項目自己可使用,其餘系統基本沒法複用,天然就更沒法使得多方協做複用了。
吸收了這些教訓之後,咱們團隊決定從另外一個方向開始設計一個新的應用定義。
具體來講,相比於其餘「應用定義」給 K8s 作加法、作整合的思路,咱們認爲,真正良好的應用定義,應該給 K8s API 作「減法」。更準確的說,是咱們應該經過「作減法」,把開發者真正關心的 API 給暴露出來,把運維、平臺關心的 API 給封裝起來。
也就是說,既然 K8s API 爲了方便基礎設施工程師,已經選擇把各方的關注點混在了一塊兒。那麼,當基礎設施工程師想要基於 K8s 來服務更上層應用開發和運維人員時,其實應該考慮把這些關注點從新梳理出來,讓應用管理的各個參與方從新拿到屬於本身的 API 子集。
因此,咱們開始在 K8s API 的基礎上增長了一層很薄的抽象,從而把原始的 K8s API 按照現實中的協做邏輯進行合理的拆分和分類,而後分別暴露給研發和運維去使用。這裏的原則是:研發拿到的 API 必定是研發視角的、沒有任何基礎設施的概念在裏面;而運維拿到的 API,必定是對 K8s 能力的模塊化、聲明式的描述。這樣,在理想狀況下,運維(或者平臺)就可以對這些來自雙方的 API 對象進行組合,好比:應用 A + Autoscaler X,應用 B + Ingress Y。這樣組合完成後的描述對象,其實就能夠完整的來描述「應用」這個東西了。
在同社區進行交流和驗證中,咱們發現:上面的這個思路正好跟當時微軟 Brendan Burns (Kubernetes 項目創始人)和 Matt Butcher (Helm 項目創始人)團隊的思路不謀而合。因此咱們雙方在面對面交流了幾回以後,很快就決定共建這個項目並把它開源出來,跟整個社區生態一塊兒來推動這件很是具備意義的事情。
今年 10 月 17 號,阿里雲小邪和微軟雲 CTO Mark 共同對外宣佈了這個項目的開源,它的官方名字叫作 Open Application Model(OAM),同時咱們還宣佈了 OAM 對應的 K8s 實現——Rudr 項目。
具體來講,在設計 OAM 的時候,咱們但願這個應用定義應該解決傳統應用定義的三個問題:
在這個思路下,咱們最後設計出來的應用定義主要分爲三個大塊:
下面咱們經過實例來看下以上三個部分對應的 YAML 文件到底長什麼樣子?它們究竟怎麼玩兒?
備註:若是你想跟我同樣實際操做體驗這個流程,你只須要在 K8s 集羣裏裝上 Rudr 項目就能夠實操了。
首先咱們能夠看到,Component 定義的是開發關心的事情,沒有任何運維相關的概念。
它的 Spec 主要分爲兩大塊:
第一個參數塊是應用描述,包括 WorkloadType 字段,這個字段就是表達應用使用什麼 Workload 運行,在咱們設計裏有六種默認 Workload,分別是 Server、Worker、Job 以及他們對應的單例模式,Workload 也能夠擴展。Server 表明這是一個能夠自動伸縮的,而且有一個端口能夠訪問的模式。接下來就是容器的鏡像、啓動參數之類的,這部分包含完整的 OCI spec。
第二塊是 parameters 如何運行可擴展的參數,如環境變量和端口號。這一塊參數的特色是:它們雖然是開發定義的,可是都容許運維後續覆蓋。這裏的關鍵點是,關注點分離並不等於徹底割裂。因此,咱們設計了 parameters 列表,其實就是但願開發能告訴運維,哪些參數後續能夠被運維人員覆蓋掉。這樣的話就很好地聯動起來了,開發人員能夠向運維人員提出訴求,好比運維應該使用哪些參數、參數表明什麼意思。
像這樣一個 Component 能夠直接經過 kubectl 安裝到 K8s 中。
而後咱們能夠經過 kubectl 工具查看到已經安裝好的組件有哪些:
因此說,咱們當前的 K8s 集羣,支持兩種「應用組件」。須要指出的是,除了咱們內置支持的組件以外,開發本身能夠自由定義各類各樣的組件而後提交給咱們。Component Spec 裏的 Workload Type 是能夠隨意擴展的,就跟 K8s 的 CRD 機制同樣。
說完了開發能用的 API,咱們再來看運維用的 API 長什麼樣。
在設計應用的運維能力定義的過程當中,咱們重點關注的是運維能力怎麼發現和管理的問題。
爲此,咱們設計了一個叫作 Trait 的概念。所謂 Trait,也就是應用的「特徵」,其實就是一種運維能力的聲明式描述。咱們能經過命令行工具發現一個系統裏支持哪些 Traits(運維能力)。
這時候,運維要查看具體的運維能力該怎麼使用,是很是簡單的:
能夠看到,他能夠在 Trait 定義裏清晰的看到這個運維能力能夠做用於哪一種類型的 Workload,包括能填哪些參數?哪些必填?哪些選填?參數的做用描述是什麼? 你也能夠發現,OAM 體系裏面,Component 和 Trait 這些 API 都是 Schema,因此它們是整個對象的字段全集,也是瞭解這個對象描述的能力「到底能幹嘛?」的最佳途徑(反正基礎設施團隊的文檔寫的也不咋地)。
上面這些 Trait 也都是用過 kubectl apply 就能夠安裝到集羣當中的。
既然 Component 和 Trait 都是 Schema,那麼它們怎麼實例化成應用呢?
在 OAM 體系中,Application Configuration 是運維人員(或者系統自己也能夠)執行應用部署等動做的操做對象。在 Application Configuration 裏,運維人員能夠將 Trait 綁定到 Component 上執行。
在 Application Configuration YAML 裏面,運維能夠把 Component 和 Trait 組裝起來,從而獲得一個能夠部署的「應用」:
在這裏咱們能夠看到,運維實例化的應用裏面包含了一個叫 hellowworld-python-v1 的 Component,它有兩個參數:一個是環境變量 target,一個是port。須要注意的是,這兩個參數是運維人員覆蓋了原先 Component yaml 中開發定義的兩個可覆蓋變量。
同時,這個 Component 綁定了 2 個運維能力:一個是水平擴容,一個是 Ingress 域名訪問。
運維人員經過 kubectl 便可把這樣一個應用部署起來:
這時候在 K8s 裏面,你就能夠看到 OAM 插件會自動爲你建立出對應的 Deployment。
同時,這個應用須要的 Ingress 也被自動建立起來了:
這裏實際上是前面提到的 Rudr 插件在起做用,在拿到 OAM 的 Application Configuration 文件之後,識別出其中的 Component 和 Trait,將其映射到 K8s 上的資源並拉起,K8s 資源相應的生命週期都隨着 OAM 的配置去管理。固然,因爲 OAM 定義是平臺無關的,因此除了 K8s 自己的資源,Rudr 插件的實現中也會加入外部資源的拉起。
最終咱們能夠經過像樂高積木同樣組裝複用 OAM 的不一樣模塊,實例化出一個 OAM 的應用出來。更重要的是,這個 OAM 應用描述文件是徹底自包含的,也就是說經過 OAM YAML,做爲軟件分發商,咱們就能夠完整地跟蹤到一個軟件運行所須要的全部資源和依賴。
這就使得如今對於一個應用,你們只須要一份 OAM 的配置文件,就能夠快速、在不一樣運行環境上把應用隨時運行起來,把這種自包含的應用描述文件完整地交付到任何一個運行環境中。
這不只讓咱們前面提到的軟件交付難題獲得了很好的解決,也讓更多非 K8s 平臺好比 IoT、遊戲分發、混合環境軟件交付等場景,能享受到雲原生應用管理的暢快。
OAM 是一個徹底屬於社區的應用定義模型,咱們很是但願你們都能參與進來。
(釘釘掃碼加入交流羣)
咱們期待能與你們一塊兒共建這個全新的應用管理生態。
Q1:OAM spec 中目前尚未看到屬於 Infra Operator 的管理對象(補充:Component 是面向 App Developer,Traits 和 AppConfiguration 面向 App Operator,哪一個對象是面向 Infra Operator 的?)
A1:OAM 自己就是基礎設施運維手裏的武器,包括 Kubernetes、Terraform 等一系列平臺層的開源項目,基礎設施運維能夠經過這些開源項目構建 OAM 的實現(如 Rudr 基於 Kubernetes)。因此 OAM 的實現層就是基礎設施運維提供的,他們不須要額外的對象來使用 OAM。
Q2:OAM Controller和 admission controller 的分工標準是什麼?
A2:OAM 項目中的 admission controller 用於轉換和檢驗 spec,徹底等價於 K8s 中 admission controller。目前實現的功能包括轉換 [fromVariable(VAR)] 這種 spec 中的函數,檢驗 AppConfig、Component、Trait、Scope 等 CR 是否符合規範,是否合法等。OAM Controller,即目前的開源項目 Rudr,就是整個 OAM 的實現層,它負責解釋 OAM 的 spec 並轉換爲真實運行的資源,這裏的資源能夠是 K8s 原有的一些,也能夠是像阿里雲上的 RDS 這類雲資源。目前 Rudr 項目是 Rust 語言寫的,考慮到 K8s 生態大多數都是用 Go 語言寫的,咱們後續也會開源一個 Go 語言編寫的 OAM-Framework,用於快速實現像 Rrudr 這樣的 OAM 實現層。
Q3:計劃啥時候開源 Go 的 OAM-Framework 呀?
A3:咱們須要一點時間進一步打磨 OAM-Framework ,讓它適配你們的場景。可是應該很快就會跟你們見面。
Q4:阿里是如何下降 K8s 的複雜度來知足運維和研發一些共性訴求的?在 K8s 中的用戶 user 角色多是開發也多是運維。
A4:目前咱們遇到的大多數場景都能區分哪些是運維要關心的,哪些是研發要關心的。OAM 下降 K8s 複雜度的主要方法就是關注點分離,給 K8s 的 API 作減法,儘可能讓某一方能夠少關注一些內容。若是你有這樣一個沒法分割的場景,其實咱們也很感興趣,歡迎把 case 提出來一塊兒探討。另外一方面,咱們並非屏蔽掉 K8s,OAM Spec 預留了充足的擴展性,徹底能夠把K8s原有的能力提供給用戶。
Q5:我認爲 OAM 是基於 K8s 針對於不一樣應用上的抽象層,如今咱們有不少應用都是用 Helm 包包裝好的,若是切換成 OAM 的話,咱們須要注意哪些地方呢?
A5:其實咱們上半年一直在推廣 Helm 在國內的使用,包括提供了阿里巴巴的 Helm 鏡像站(https://developer.aliyun.com/hub)等,因此 OAM 跟 Helm 也是相輔相成的。簡單的說,OAM 其實就是 Helm 包裏面 template 文件夾裏面的內容。Helm 是 OAM 作參數渲染(template)和打包(chart)的工具。若是切換到 OAM,Helm 的使用方式不須要變,裏面的 spec 換成 OAM 的 spec 便可。
Q6:請問,Rudr 用起來了嗎,效果如何。Rudr 的架構有沒更豐富的資料?
A6:Rudr 一直是能夠用的,你們要是用不起來能夠提 issue,想要什麼方面的資料或者疑問也能夠提 issue,咱們也在完善文檔。目前相關的材料都在這裏:
https://github.com/oam-dev/ru...
Q7:咱們一直在用 Helm 打包咱們的應用,去作 gitops ,一個通用的 chart 對應不一樣的 values.yaml 作到了複用。聽了分享,很期待 OAM,固然還有 Openkruise。
A7:Openkruise 是開源的哈,你們能夠關注 https://github.com/openkruise... 咱們也一直在迭代。
Q8:OAM 有哪些公司在用?實際體驗反饋如何?
A8:OAM 剛剛發佈一個月左右,具體有哪些公司已經在使用咱們尚未來得及統計。阿里巴巴和微軟內部都已經在使用,而且都有對外的產品使用 OAM。就咱們接觸到的用戶來講,不管是社區的用戶仍是阿里巴巴內部,都對 OAM 的關注點分離等理念很是認同,也都在積極落地。
社羣分享文章整理
Vol 1 : 當 K8s 集羣達到萬級規模,阿里巴巴如何解決系統各組件性能問題?
Vol 2 : 超大規模商用 K8s 場景下,阿里巴巴如何動態解決容器資源的按需分配問題?
Vol 3 : 備戰雙 11!螞蟻金服萬級規模 K8s 集羣管理系統如何設計?
Vol 4 : 帶你上手一款下載超 10 萬次的 IEDA 插件
「 阿里巴巴雲原生微信公衆號(ID:Alicloudnative)關注微服務、Serverless、容器、Service Mesh等技術領域、聚焦雲原生流行技術趨勢、雲原生大規模的落地實踐,作最懂雲原生開發者的技術公衆號。」