做者 | 李響、張磊php
從 2019 年初開始,阿里巴巴雲原生應用平臺團隊開始逐步在整個阿里經濟體內,基於標準應用定義與交付模型進行應用管理產品與項目統一架構升級的技術工做。nginx
事實上,早在 2018 年底,當 Kubernetes 項目正式成爲阿里巴巴的應用基礎設施底盤以後,阿里內部以及阿里雲產品線在應用管理領域的碎片化問題就開始日漸凸顯出來。git
尤爲是在雲原生生態突飛猛進的今天,阿里巴巴與阿里雲的應用管理產品架構(包括阿里內部 PaaS 和雲上 PaaS 產品),如何以最佳姿態擁抱雲原生生態、如何以最高效的技術手段藉助生態突飛猛進的能力構建出更強大的 PaaS 服務,而不是重複造輪子甚至和生態「背道而馳」,很快就成爲了阿里團隊亟待解決的重要技術難題。github
但棘手的是,這個問題並非簡單把 PaaS 遷移或者集成到 Kubernetes 上來就可以解決的:PaaS 與 Kubernetes 之間,歷來就沒有存在這樣一條清晰的分界線,但是 Kubernetes 自己又並非面向最終用戶設計的。web
如何既讓全公司的研發和運維充分享受雲原生技術體系革新帶來的專一力與生產力提高,又可以讓現有 PaaS 體系無縫遷移、接入到 Kubernetes 大底盤當中,還要讓新的 PaaS 體系把 Kubernetes 技術與生態的能力和價值最大程度的發揮出來,而不是互相「屏蔽」甚至「打架」?這個「既要、又要、還要」的高標準要求,纔是解決上述 「Kubernetes vs PaaS」 難題的關鍵所在。數據庫
在 2019 年 10 月,阿里巴巴宣佈聯合微軟共同推出開放應用模型項目(Open Application Model - OAM),正是阿里進行自身應用管理體系標準化與統一架構升級過程當中,逐步演進出來的一項關鍵技術。apache
所謂「應用模型」,實際上是一個專門用來對雲原生應用自己和它所需運維能力進行定義與描述的標準開源規範。因此對於 Kubernetes 來講,OAM 便是一個標準的「應用定義」項目(類比已經再也不活躍的 Kubernetes Application CRD 項目),同時也是一個專一於封裝、組織和管理 Kubernetes 中各類「運維能力」、以及鏈接「運維能力」與「應用」的平臺層項目。而經過同時提供「定義應用」和「組織管理應用的運維能力」這兩大核心功能,OAM 項目天然成爲了阿里巴巴進行統一應用架構升級和構建下一代 PaaS/Serverless 過程當中「當仁不讓」的關鍵路徑。api
此外,OAM 模型並不負責應用和能力的具體實現,從而確保了它們都是由 Kubernetes 自己直接提供的 API 原語和控制器實現。因此, OAM 也成爲了當前阿里構建 Kubernetes 原生 PaaS 的一項主要手段。安全
在 OAM 中,一個應用程序包含三個核心理念:網絡
阿里巴巴在 OAM 這個項目中融入了大量互聯網規模場景中管理 Kubernetes 集羣和公共雲產品方面的實際經驗,特別是阿里從原先不可勝數的內部應用 CRD 轉向基於 OAM 的標準應用定義過程當中的諸多收穫。做爲工程師,咱們從過去的失敗和錯誤中吸收教訓,不斷開拓創新、發展壯大。
在本文中,咱們將會詳細分享 OAM 項目背後的動機和推進力,但願可以幫助更多人更好地瞭解這個項目。
<br />咱們是阿里巴巴的「基礎設施運維人員」,或者說 Kubernetes 團隊。具體來講,咱們負責開發、安裝和維護各類 Kubernetes 級別的功能。具體工做包括但不限於維護大規模的 K8s 集羣、實現控制器/Operator,以及開發各類 K8s 插件。在公司內部,咱們一般被稱爲「平臺團隊(Platform Builder)」。
不過,爲了與兄弟團隊區分,即那些在咱們之上基於 K8s 構建的 PaaS 工程人員區分,咱們在本文中將自稱爲「基礎設施運維人員(Infra Operator)」。過去幾年裏,咱們已經過 Kubernetes 取得了巨大成功,並在使用過程當中經過出現的問題獲取了寶貴的經驗教訓。
<br />毫無疑問,咱們爲阿里巴巴電商業務維護着世界上最大、最複雜的 Kubernetes 集羣,這些集羣:
同時,咱們還協助支持着阿里雲的 Kubernetes 服務(ACK),該服務相似於面向外部客戶的其餘公有云 Kubernetes 產品,其中包含大量集羣(約 1 萬個),不過一般均爲小型或中型的集羣。咱們的內部和外部客戶在工做負載管理方面的需求和用例很是多樣化。
與其餘互聯網公司相似,阿里巴巴的技術棧由基礎設施運維人員、應用運維人員和業務研發人員合做完成。業務研發和應用運維人員的角色能夠歸納以下:
以代碼形式傳遞業務價值。大多數業務研發都對基礎設施或 K8s 不甚瞭解,他們與 PaaS 和 CI 流水線交互以管理其應用程序。業務研發人員的生產效率對公司而言價值巨大。
爲業務研發人員提供有關集羣容量、穩定性和性能的專業知識,幫助業務研發人員大規模配置、部署和運行應用程序(例如,更新、擴展、恢復)。請注意,儘管應用運維人員對 K8s 的 API 和功能具備必定了解,但他們並不直接在 K8s 上工做。在大多數狀況下,他們利用 PaaS 系統爲業務研發人員提供基礎 K8s 功能。在這種狀況下,許多應用運維人員實際上也是 PaaS 工程人員。
總之,像咱們這樣的基礎設施運維人員爲應用運維人員提供服務,他們隨之爲業務研發人員提供服務。
綜上所述,這三方顯然擁有不一樣的專業知識,但他們卻須要協調一致以確保順利工做。這在 Kubernetes 的世界裏可能很難實現!
咱們將在下面的章節中介紹不一樣參與方的痛點,但簡而言之,咱們面臨的根本問題是不一樣參與方之間缺少一種標準化的方法來進行高效而準確的交互。這會致使低效的應用程序管理流程,甚至致使運行失敗。
而標準應用模型正是咱們解決此問題的關鍵方法。
Kubernetes 具備高度的可擴展性,使得基礎設施運維人員可以爲所欲爲地構建本身的運維功能。但 Kubernetes 巨大的靈活性也是一把雙刃劍:這些功能的用戶(即應用運維人員)會遇到一些棘手的問題。
舉例來講,在阿里巴巴,咱們開發了 CronHPA CRD 以根據 CRON 表達式擴展應用程序。當應用程序的水平擴展策略但願在白天和晚上有所不一樣時,這很是有用。CronHPA 是一種可選功能,僅在集羣中按需部署。
CronHPA 的 yaml 示例以下所示:
apiVersion: 「app.alibaba.com/v1」 kind: CronHPA metadata: name: cron-scaler spec: timezone: America/Los_Angeles schedule: - cron: ‘0 0 6 * * ?’ minReplicas: 20 maxReplicas: 25 - cron: ‘0 0 19 * * ?’ minReplicas: 1 maxReplicas: 9 template: spec: scaleTargetRef: apiVersion: apps/v1 name: php-apache metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 50
這是一個典型的 Kubernetes 自定義資源(CRD),能夠直接安裝使用。
可是,當咱們把這些功能交付出去,應用運維人員開始使用諸如 CronHPA 等自定義插件時,他們很快就遇到麻煩了:
應用運維人員常常抱怨這些插件功能的使用方法(也就是 spec) 分佈的很是隨意。它有時位於 CRD 中,有時位於 ConfigMap 中,有時又位於某個隨機位置的配置文件中。此外,他們還感到很是困惑:爲何 K8s 中不少插件(例如,CNI 和 CSI 插件)的 CRD 並非對應的能力(例如:網絡功能和存儲功能)描述,而只是那些插件自己的安裝說明?
應用運維人員對某項運維能力是否已在集羣中準備就緒毫無把握,尤爲是當該能力是新開發的插件提供時更是如此。基礎設施運維人員和應用運維人員之間須要進行多輪溝通,才能澄清這些問題。
除上述可發現性問題外,還有一個與可管理性相關的額外難題。
K8s 集羣中的運維能力之間的關係能夠歸納爲如下三類:
正交和可組合能力相對安全。然而,互相沖突的功能可能致使意外/不可預測的行爲。
這裏的問題在於, Kubernetes 很難事先向應用運維人員發送衝突警告。所以,他們可能會對同一應用程序使用彼此衝突的兩個運維能力。而當實際發生衝突時,解決衝突會產生高昂的成本,在極端狀況下,這些衝突會致使災難性的故障。固然,在管理平臺能力時,應用運維人員顯然不但願面臨「頭頂懸着達摩克里斯之劍」的狀況,所以但願找到一種更好的方法來提早避免衝突狀況。
應用運維人員如何發現和管理可能相互衝突的運維能力?換而言之,做爲基礎設施運維人員,咱們可否爲應用運維人員構建可發現且易管理的運維能力呢?
在 OAM 中,咱們經過「運維特徵(Trait)」來描述和構建具有可發現性和可管理性的平臺層能力。
這些平臺層能力實質上是應用程序的運維特徵,而這正是 OAM 中「Trait」這個名稱的來歷。
在阿里的 K8s 集羣中,大多數 Trait 都由基礎設施運維人員定義,並使用 Kubernetes 中的自定義控制器實現,例如:
請注意, Trait 並不等同於 K8s 插件。好比:一個集羣可具備多個網絡相關 Trait ,如「動態 QoS Trait 」、「帶寬控制 Trait 」和「流量鏡像 Trait 」,這些 Trait 均由一個 CNI 插件提供。
實際上, Trait 安裝在 K8s 集羣中,並供應用運維人員使用。將能力做爲 Trait 呈現時,應用運維人員使用簡單的 kubectl get 命令便可發現當前集羣支持的運維能力:
$ kubectl get traitDefinition NAME AGE cron-scaler 19m auto-scaler 19m
上面的示例顯示此集羣支持兩種 「scaler」 能力。用戶能夠將須要基於 CRON 的擴展策略的應用程序部署到該集羣。
Trait 提供給定運維能力的結構化描述。
這使應用運維人員經過簡單的 kubectl describe 命令便可輕鬆準確地理解特定能力,而沒必要深刻研究其 CRD 或文檔。能力描述包括「此 Trait 適用於何種工做負載」和「它的使用方式」等。
例如,kubectl describe traitDefinition cron-scaler:
apiVersion: core.oam.dev/v1alpha2 kind: TraitDefinition metadata: name: cron-scaler spec: appliesTo: - core.oam.dev/v1alpha1.ContainerizedWorkload definitionRef: name: cronhpas.app.alibaba.com
請注意,在 OAM 中, Trait 經過 definitionRef 引用 CRD 來描述其用法,同時也與 K8s 的 CRD 解耦。
Trait 採用了規範與實現分離的設計,一樣一個 Trait 的 spec,能夠被不一樣平臺不一樣環境徹底基於不一樣的技術來實現。經過引用的方式,實現層既能夠對接到一個已有實現的 CRD,也能夠對接到一個統一描述的中間層,底下可插拔的對接不一樣的具體實現。考慮到 K8s 中的一個特定的能力好比 Ingress 可能有多達幾十種實現,這種規範與實現分離的思想會很是有用。Trait 提供了統一的描述,可幫助應用運維人員準確理解和使用能力。
應用運維人員經過使用 ApplicationConfiguration(將在下一部分中詳細介紹),對應用程序配置一個或多個已安裝的 Trait 。ApplicationConfiguration 控制器將處理 Trait 衝突(若是有)。
咱們以此示例 ApplicationConfiguration 爲例:
apiVersion: core.oam.dev/v1alpha2 kind: ApplicationConfiguration metadata: name: failed-example spec: components: - name: nginx-replicated-v1 traits: - trait: apiVersion: core.oam.dev/v1alpha2 kind: AutoScaler spec: minimum: 1 maximum: 9 - trait: apiVersion: app.alibabacloud.com/v1 kind: CronHPA spec: timezone: "America/Los_Angeles" schedule: "0 0 6 * * ?" cpu: 50 ...
在 OAM 中,ApplicationConfiguration 控制器必須保證這些 Trait 之間的兼容性,若是不能知足要求,應用的部署就會馬上失敗。因此,當運維人員將上述 YAML 提交給 Kubernetes 時,因爲「Trait 衝突」,OAM 控制器將會報告部署失敗。這就使得應用運維人員可以提早知道有運維能力衝突,而不是在部署失敗後大驚失色。
總的來講,咱們團隊不提倡提供冗長的維護規範和運維指南(它們根本沒法防止應用運維人員出錯),咱們傾向因而使用 OAM Trait 來對外暴露基於 Kubernetes 的可發現和可管理的運維能力。這使咱們的應用運維人員可以「快速失敗」,並滿懷信心地組合運維能力來構建無衝突的應用運維解決方案,這就像玩「樂高積木」同樣簡單。
Kubernetes 的 API 對象並不關心本身的使用者究竟是運維仍是研發。這意味着任何人均可能對一個 Kubernetes API 對象中的任何字段負責。這也稱爲「all-in-one」的 API,它使得新手很容易上手。
可是,當具備不一樣關注點的多個團隊必須在同一個 Kubernetes 集羣上展開協做時,特別是當應用運維人員和業務研發人員須要在相同 API 對象上展開協做時,all-in-one API 缺點就會凸顯出來。
讓咱們先來看一個簡單的 Deployment YAML 文件:
kind: Deployment apiVersion: extensions/v1beta1 metadata: name: nginx-deployment spec: replicas: 3 selector: matchLabels: deploy: example template: metadata: labels: deploy: example spec: containers: - name: nginx image: nginx:1.7.9 securityContext: allowPrivilegeEscalation: false
在咱們的集羣中,應用運維人員與業務研發人員須要面對面開會來填寫這個 yaml 文件。這種合做既耗時又複雜,但咱們別無選擇。緣由何在?
顯而易見,這裏最直接的方法是讓業務研發人員本身填寫 Deployment yaml。可是,業務研發人員可能會發現 Deployment 裏的某些字段與他們的關注點沒有絲毫關聯。例如:
有多少業務研發人員知道 allowPrivilegeEscalation 是什麼意思?
事實上,不多有業務研發人員知道,在生產環境裏,這個字段務必要設置爲 false (默認是 true),才能確保應用程序在宿主機中具備合理的權限。在實踐中,這個字段只能應用運維人員配置。而現實是,一旦把整個 Deployment 暴露給業務研發填寫,這些字段最終就會淪爲「猜謎遊戲」,甚至徹底被業務研發人員忽視。
若是你瞭解 K8s 的話,就必定會發現 K8s 中有大量的 API 字段很難說清楚究竟是應該由研發仍是運維來填寫。
例如,當業務研發人員設置 Deployment 的 replicas:3 時,他會假設該數字在應用程序生命週期中固定不變。
可是,大多數業務研發人員並不知道 Kubernetes 的 HPA 控制器能夠接管該字段,並可能會根據 Pod 負載改變 replicas 的值。這種由系統自動化流程帶來的變動很容易致使問題:這意味着當業務研發人員想要更改副本數時,他對 replicas 的修改可能根本不會生效。
在此種狀況下,一個 Kubernetes 的 YAML 文件就不能表示工做負載的最終狀態,從業務研發人員角度而言,這很是使人困惑。咱們曾嘗試使用 fieldManager 來處理此問題,但 fieldManager 進行衝突解決的過程仍頗具挑戰性,由於咱們很難弄清這些衝突方的修改目的。
如上所示,當使用 K8s API 時,業務研發人員和運維人員的關注點會不可避免地被混在一塊兒。這使得多個參與方可能很難基於同一個 API 對象展開協做。
此外,咱們也發現,阿里內部的不少應用程序管理系統(如 PaaS)並不肯意暴露 K8s 的所有能力,顯然他們並不但願向業務研發人員暴露更多的 Kubernetes 概念。
對於上述問題,最簡單的解決方案是在業務研發人員和運維人員之間劃一條「明確的界限」。例如,咱們能夠僅容許業務研發人員設置 Deployment yaml 的一部分字段(這正是阿里不少 PaaS 曾經採用的辦法)。可是,這種「割裂研發與運維」的解決方案可能並不奏效。
在不少狀況下,業務研發人員都但願運維人員聽取他們的一些關於運維的「意見」。
例如,假定業務研發人員爲應用程序定義了 10 個參數,而後他們發現應用運維人員可能會覆蓋這些參數以適配不一樣的運行環境的差別。那麼問題來了:業務研發如何才能作到僅容許運維人員修改其中特定的 5 個參數?
實際上,若是採用「割裂研發與運維」應用管理流程,要傳達業務研發人員的運維意見將變得難上加難。這樣相似的例子有許多,業務研發人員可能但願表述不少關於他們的應用程序的信息:
上述全部這些請求都是合理的,由於只有業務研發人員纔是最瞭解應用程序的那我的。這就提出了一個咱們亟待解決的重要問題:咱們的 Kubernetes 可否既爲業務研發和運維人員提供單獨的 API,同時又容許業務研發人員有效傳達本身對運維的訴求?
在 OAM 中,咱們從邏輯上對 K8s 的 API 對象進行了拆分,而且作到了既使得業務研發人員可以填寫屬於本身的那些字段,同時又能有條理地向運維人員傳達訴求。
定義你的應用程序,而不是僅僅描述它。
<br />在 OAM 中,Component(組件) 就是一個徹底面向業務研發人員設計的、用於定義應用程序而沒必要考慮其運維詳細信息的載體。一個應用程序包含一個或多個 Component 。例如,一個網站應用能夠由一個 Java web 組件和一個數據庫組件組成。
如下是業務研發人員爲 Nginx 部署定義的 Component 示例:
OAM 中的 Component 包含兩個部分:
在 Component 中,workload 字段能夠直接向運維人員傳達業務研發人員關於如何運行其應用程序的說明。同時,OAM 圍繞容器應用定義了一種核心工做負載 ContainerizedWorkload,涵蓋了雲原生應用程序的典型模式。
與此同時,OAM 能夠經過定義擴展工做負載來自由聲明用戶本身的工做負載類型。在阿里巴巴,咱們在很大程度上依賴於擴展工做負載來使業務研發人員定義阿里雲服務 Component ,例如,阿里雲函數計算 Component 等。
請注意,在上面的示例中,業務研發人員再也不須要設置副本數;由於這並非他所關注的字段:他選擇讓 HPA 或應用運維人員徹底控制副本數的值。
整體來講,Component 容許業務研發人員使用本身的方式定義應用程序的聲明式描述,但同時也爲他/她提供了隨時向運維人員準確傳達意見或信息的能力。這些信息包括對運維的訴求,例如,「如何運行此應用程序」和「可重寫參數」。
最終,經過引用 Component 名稱並對它綁定 Trait ,運維人員就可使用 ApplicationConfiguration 來實例化應用程序。
使用 Component 和 ApplicationConfiguration 的示例協做工做流:
這個 app-config.yaml 文件的內容以下所示:
apiVersion: core.oam.dev/v1alpha1 kind: ApplicationConfiguration metadata: name: my-awesome-app spec: components: - componentName: nginx parameterValues: - name: connections value: 4096 traits: - trait: apiVersion: core.oam.dev/v1alpha2 kind: AutoScaler spec: minimum: 1 maximum: 9 - trait: apiVersion: app.aliaba.com/v1 kind: SecurityPolicy spec: allowPrivilegeEscalation: false
咱們來重點說明以上 ApplicationConfiguration YAML 中的一些詳細信息:
parameterValues —— 供運維人員使用,用於將 connections 值重寫爲 4096,在該組件中,該值最初爲 1024。請注意,運維人員必須填寫整數 4096,而不是字符串 "4096",由於此字段的 schema 已在 Component 中明肯定義;
Trait AutoScaler —— 供運維人員使用,用於將 autoscaler Trait (如 HPA)綁定給 Component 。所以,其副本數將徹底由 autoscaler 控制;
Trait SecurityPolicy —— 供運維人員使用,用於將安全策略規則應用於 Component。請注意,運維人員還能夠修改 Trait 列表以綁定更多 Trait。例如,「Canary Deployment Trait 」意味着這個應用程序在後期升級過程當中遵循金絲雀發佈策略。
實質上,ApplicationConfiguration 的主要功能,就是讓應用運維人員(或系統)瞭解和使用業務研發人員傳達的信息,而後自由的爲 Component 組合綁定不一樣的運維能力以相應實現其最終的運維目的。
綜上所述,咱們使用 OAM 的主要目標是解決應用程序管理中的如下問題:
因此說,對於阿里巴巴來講,OAM 實際上是阿里巴巴 Kubernetes 團隊提出的一種 Application CRD 規範,從而使得全部參與者能夠採用結構化的標準方法來定義應用程序及其運維能力。
阿里巴巴開發 OAM 的另外一個強大動力,則是在混合雲和多環境中進行軟件分發與交付。隨着 Google Anthos 和 Microsoft Arc 的出現,咱們已然看到 Kubernetes 正成爲新的 Android,而且雲原生生態系統的價值正迅速轉移到應用層的趨勢。咱們將在之後討論這一主題。
本文中的實際使用案例由阿里雲原生團隊和螞蟻金服共同提供。
目前,OAM 規範和模型實際已解決許多現有問題,但它的路程纔剛剛開始。例如,咱們正在研究使用 OAM 處理組件依賴關係、在 OAM 中集成 Dapr 工做負載等。
咱們期待在 OAM 規範及其 K8s 實現方面與社區展開協做。OAM 是一箇中立的開源項目,其全部貢獻者都應遵循非營利性基金會的 CLA。
目前,阿里巴巴團隊正在上游貢獻和維護這套技術,若是你們有什麼問題或者反饋,也很是歡迎與咱們在上游或者釘釘聯繫。
參與方式:
做者簡介 **李響,阿里雲資深技術專家。**他在阿里巴巴從事集羣管理系統工做,並協助推進阿里巴巴集團內的 Kubernetes 採用。在效力於阿里巴巴以前,李響曾是 CoreOS Kubernetes 上游團隊的負責人。他仍是 etcd 和 Kubernetes Operator 的建立者。
**張磊,阿里雲高級技術專家。**他是 Kubernetes 項目的維護者之一。張磊目前在阿里的 Kubernetes 團隊工做,其工做領域包括 Kubernetes 和雲原生應用管理系統。
雲原生應用平臺誠邀 Kubernetes / Serverless / PaaS / 應用交付領域專家( P6-P8 )加盟:
簡歷馬上回復,2~3 周出結果,簡歷投遞:jianbo.sjb AT alibaba-inc.com。
「阿里巴巴雲原生關注微服務、Serverless、容器、Service Mesh 等技術領域、聚焦雲原生流行技術趨勢、雲原生大規模的落地實踐,作最懂雲原生開發者的技術圈。」