做者 | 孫健波(天元)阿里雲技術專家linux
導讀:OAM Spec 經歷了近 3 個月的迭代,v1alpha2 版本終於發佈啦!新版本在堅持 OAM Spec 平臺無關的基礎上,總體變得更 Kubernetes 友好化,很大程度上平衡了標準與可擴展性,更好的支持 CRD。若是你已經編寫了現成的 CRD Operator,能夠平滑的接入到 OAM 體系中,而且享受到 OAM 模型的紅利。git
目前 OAM 已經成爲了包括阿里、微軟、Upbond、諧雲等多家公司構建雲產品的核心架構。他們經過 OAM 構建了「以應用爲中心」、用戶友好化的 Kubernetes PaaS;充分發揮 OAM 的標準化與可擴展性,實現 OAM 核心 Controller 的同時,快速接入了已有的 Operator 能力;經過 OAM 橫向打通多個模塊,破除了原有 Operator 彼此孤立、沒法複用的窘境。<br />github
瞭解 OAM 的背景及由來,能夠參考《深度解讀!阿里統一應用管理架構升級的教訓與實踐》;web
OAM 能爲終端用戶帶來哪些價值?能夠參考《OAM 深刻解讀:OAM 爲雲原生應用帶來哪些價值?》redis
下面言歸正傳,讓咱們來看一下 v1alpha2 到底作了哪些改動?docker
爲了方便你們閱讀,這裏只羅列了最主要的改動點,一些細節仍是以上游 OAM Spec Github 倉庫爲準。json
CRD(Custom Resource Definition):在 OAM 中說的 CRD 是一種泛指的自定義資源描述定義。在 K8s 的 OAM 實現中能夠徹底對應 K8s 的 CRD,在非 K8s 的實現中,OAM 的 CRD 須要包含 APIVersion/Kind 而且可以描述字段進行校驗;api
CR (Custom Resource),OAM 中的 CR 是 CRD 的一個實例,是符合 CRD 中字段格式定義的一個資源描述。在 K8s 的 OAM 實現中能夠徹底對應 K8s 的 CR,在 非 K8s 的實現中,能夠須要對齊 APIVersion/Kind 和字段格式定義。數組
v1alpha1 原先的方式是這樣的:架構
// 老版本,僅對比使用 apiVersion: core.oam.dev/v1alpha1 kind: WorkloadType metadata: name: OpenFaaS annotations: version: v1.0.0 description: "OpenFaaS a Workload which can serve workload running as functions" spec: group: openfaas.com version: v1alpha2 names: kind: Function singular: function plural: functions workloadSettings: | { "$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "required": [ "name", "image" ], "properties": { "name": { "type": "string", "description": "the name to the function" }, "image": { "type": "string", "description": "the docker image of the function" } } }
在原先的模式中,group/version/kind 分別是字段,spec 的校驗經過 jsonschema 表示,總體的格式實際上相似 CRD,但不徹底一致。
新版 v1alpha2 中完全改成了引用模型,經過 WorkloadDefinition
TraitDefinition
ScopeDefinition
的形式,描述了一個引用關係。能夠直接引用一個 CRD,name 就是 CRD 的名稱。對於非 K8s 的 OAM 實現來講,這裏的名字則是一個索引,能夠找到相似 CRD 的校驗文件,校驗文件中包含 apiVersion 和 kind,以及相應的 schema 校驗。
apiVersion: core.oam.dev/v1alpha2 kind: WorkloadDefinition metadata: name: containerisedworkload.core.oam.dev spec: definitionRef: # Name of CRD. name: containerisedworkload.core.oam.dev
apiVersion: core.oam.dev/v1alpha2 kind: TraitDefinition metadata: name: manualscalertrait.core.oam.dev spec: appliesToWorkloads: - containerizedworkload.core.oam.dev definitionRef: name: manualscalertrait.core.oam.dev
apiVersion: core.oam.dev/v1alpha2 kind: ScopeDefinition metadata: name: networkscope.core.oam.dev spec: allowComponentOverlap: true definitionRef: name: networkscope.core.oam.dev
注意:
這裏對於 K8s 的 OAM 實現來講,name 就是 K8s 裏面 CRD 的 name,由 <plural-kind>.<group>
組成。社區的最佳實踐是一個 CRD 只有一個 version 在集羣中運行,通常新 version 都會向前兼容,升級時都一次性替換到最新 version。若是確實有 2 個 version 同時存在的場景,用戶也能夠經過 kubectl get crd <name>
的方式進一步選擇;
Definition 這一層不面向 end user,主要給平臺實現使用,對於非 K8s 實現來講,若是存在多個 version 的場景,OAM 的實現平臺能夠給終端用戶展現不一樣 version 的選擇。
原先的方式在 Workload 和 Trait 層面咱們都只把 CR 的 spec 部分拿出來,分別放在 workloadSettings
和 properties
字段裏。
這樣的方式雖然已經能夠「推導」出 K8s CR,可是不利於 K8s 生態內的 CRD 接入,須要換種格式從新定義一遍 spec。
// 老版本,僅對比使用 apiVersion: core.oam.dev/v1alpha1 kind: ComponentSchematic metadata: name: rediscluster spec: workloadType: cache.crossplane.io/v1alpha1.RedisCluster workloadSettings: engineVersion: 1.0 region: cn
// 老版本,僅對比使用 apiVersion: core.oam.dev/v1alpha1 kind: ApplicationConfiguration metadata: name: custom-single-app annotations: version: v1.0.0 description: "Customized version of single-app" spec: variables: components: - componentName: frontend instanceName: web-front-end parameterValues: traits: - name: manual-scaler properties: replicaCount: 5
如今的方式則直接嵌入 CR,能夠看到,在 workload
和 trait
字段下面是完整的 CR 描述。
apiVersion: core.oam.dev/v1alpha2 kind: Component metadata: name: example-server spec: prameters: - name: xxx fieldPaths: - "spec.osType" workload: apiVersion: core.oam.dev/v1alpha2 kind: Server spec: osType: linux containers: - name: my-cool-server image: name: example/very-cool-server:1.0.0 ports: - name: http value: 8080 env: - name: CACHE_SECRET
apiVersion: core.oam.dev/v1alpha2 kind: ApplicationConfiguration metadata: name: cool-example spec: components: - componentName: example-server traits: - trait: apiVersion: core.oam.dev/v1alpha2 kind: ManualScalerTrait spec: replicaCount: 3
這樣的好處很明顯:
Deployment
(做爲自定義 workload 接入)等資源;這裏你們注意到 traits 下面是 []trait{CR}
而不是 []CR
的結構,多了一層看似無用的 trait
字段,主要由以下 2 個緣由:
ordering
) 等。研發可以留出字段給運維覆蓋,一直是 OAM 很重要的功能。
體如今 OAM Spec 的流程上就是:研發在 Component 裏面定義 parameter,運維在 AppConfig 裏面經過 parameterValue 去覆蓋對應的參數。
最初的參數傳遞,是在每一個字段後面有個 fromParam
字段,對於支持了自定義 schema 後,這樣的方式顯然是沒法覆蓋全部場景的:
// 老版本,僅對比使用 apiVersion: core.oam.dev/v1alpha1 kind: ComponentSchematic metadata: name: rediscluster spec: workloadType: cache.crossplane.io/v1alpha1.RedisCluster parameters: - name: engineVersion type: string workloadSettings: - name: engineVersion type: string fromParam: engineVersion
後來咱們曾經提議過這樣的方案:
// 老版本,僅對比使用 apiVersion: core.oam.dev/v1alpha1 kind: ComponentSchematic metadata: name: rediscluster spec: workloadType: cache.crossplane.io/v1alpha1.RedisCluster parameters: - name: engineVersion type: string workloadSettings: engineVersion: "[fromParam(engineVersion)]"
這個方案最大的問題是 靜態的 IaD (Infrastructure as Data) 裏面加入了動態的函數,給理解和使用帶來了複雜性。
通過多方面的討論,在新方案裏咱們經過 JsonPath 的形式描述要注入的參數位置,在用戶理解上保證了 AppConfig 是靜態的。
apiVersion: core.oam.dev/v1alpha2 kind: Component metadata: name: example-server spec: workload: apiVersion: core.oam.dev/v1alpha2 kind: Server spec: containers: - name: my-cool-server image: name: example/very-cool-server:1.0.0 ports: - name: http value: 8080 env: - name: CACHE_SECRET value: cache parameters: - name: instanceName required: true fieldPaths: - ".metadata.name" - name: cacheSecret required: true fieldPaths: - ".workload.spec.containers[0].env[0].value"
fieldPaths 是個數組,每一個元素定義了參數和對應 Workload 裏的字段。
apiVersion: core.oam.dev/v1alpha2 kind: ApplicationConfiguration metadata: name: my-app-deployment spec: components: - componentName: example-server parameterValues: - name: cacheSecret value: new-cache
在 AppConfig 中仍是走 parameterValues 去覆蓋 Component 中的 parameter。
原先組件這個概念叫 ComponentSchematic,這樣命名的主要緣由是裏面混了一些語法描述和選擇,好比針對 Core Workload( container
)和針對擴展 Workload ( workloadSettings
),寫法上不同的,container
裏是定義具體的參數,workloadSettings
更像是 schema(參數怎麼填的說明)。v1alpha1 版本的 WorkloadSetting 還融入了 type/description之類的,更顯得模棱兩可。
// 老版本,僅對比使用 apiVersion: core.oam.dev/v1alpha1 kind: ComponentSchematic metadata: name: rediscluster spec: containers: ... workloadSettings: - name: engineVersion type: string description: engine version fromParam: engineVersion ...
在 v1alpha2 版本中,組件這個概念改成 Component,明確爲 Workload 的實例,全部語法定義都是在WorkloadDefinition 中引用的實際 CRD 定義的。
在 K8s 實現中,WorkloadDefinition 就是引用 CRD ,Component.spec.workload 裏就是寫 CRD 對應的實例 CR。
apiVersion: core.oam.dev/v1alpha2 kind: Component metadata: name: example-server spec: workload: apiVersion: core.oam.dev/v1alpha2 kind: Server spec: ...
v1alpha1 中的 Scope 是由 AppConfig 建立的,從例子中能夠看出,本質上它也是個 CR,能夠「推導」建立出 CR來。可是因爲 Scope 的定位是能夠容納不一樣 AppConfig 中的 Component,且 Scope 自己並不是一個 App,因此使用 AppConfig 建立 Scope 一直是不太合適的。
// 老版本,僅對比使用 apiVersion: core.oam.dev/v1alpha1 kind: ApplicationConfiguration metadata: name: my-vpc-network spec: variables: - name: networkName value: "my-vpc" scopes: - name: network type: core.oam.dev/v1alpha1.Network properties: network-id: "[fromVariable(networkName)]" subnet-ids: "my-subnet1, my-subnet2"
v1alpha2 新版本全面使用 CR 來對應實例,爲了讓 Scope 的概念更清晰,更方便對應不一樣類型的 Scope,將 Scope 拿出來直接由 ScopeDefinition 定義的 CRD 對應的 CR 建立。例子以下所示:
apiVersion: core.oam.dev/v1alpha2 kind: ScopeDefinition metadata: name: networkscope.core.oam.dev spec: allowComponentOverlap: true definitionRef: name: networkscope.core.oam.dev
apiVersion: core.oam.dev/v1alpha2 kind: NetworkScope metadata: name: example-vpc-network labels: region: us-west environment: production spec: networkId: cool-vpc-network subnetIds: - cool-subnetwork - cooler-subnetwork - coolest-subnetwork internetGatewayType: nat
在 AppConfig 中使用 scope 引用以下所示:
apiVersion: core.oam.dev/v1alpha2 kind: ApplicationConfiguration metadata: name: custom-single-app annotations: version: v1.0.0 description: "Customized version of single-app" spec: components: - componentName: frontend scopes: - scopeRef: apiVersion: core.oam.dev/v1alpha2 kind: NetworkScope name: my-vpc-network - componentName: backend scopes: - scopeRef: apiVersion: core.oam.dev/v1alpha2 kind: NetworkScope name: my-vpc-network
v1alpha1 版本中有 Variable 是爲了 AppConfig 裏開源引用一些公共變量減小冗餘,因此加入了 Variable 列表。但實踐來看,減小的冗餘並無明顯減小 OAM spec 的複雜性,相反,增長動態的函數顯著增長了複雜性。
另外一方面,fromVariable 這樣的能力徹底能夠經過 helm template/ kustomiz 等工具來作,由這些工具渲染出完整的 OAM spec,再進行使用。
因此這裏 variables 列表和相關的 fromVariable 均去掉,並不影響任何功能。
// 老版本,僅對比使用 apiVersion: core.oam.dev/v1alpha1 kind: ApplicationConfiguration metadata: name: my-app-deployment spec: variables: - name: VAR_NAME value: SUPPLIED_VALUE components: - componentName: my-web-app-component instanceName: my-app-frontent parameterValues: - name: ANOTHER_PARAMETER value: "[fromVariable(VAR_NAME)]" traits: - name: ingress properties: DATA: "[fromVariable(VAR_NAME)]"
由於如今已經統一用 WorkloadDefinition 定義 Workload,Component 變成了實例,因此原先的六種核心Workload 實際上都變成了同一個 WorkloadDefinition,字段描述徹底同樣,惟一的不一樣是對 trait 約束和訴求不同。所以原先的六種核心 Workload 的 spec,統一修改成一種名爲 ContainerizedWorkload 的 Workload 類型。
同時,這裏計劃要經過增長 policy 這樣的概念,來讓研發表達對運維策略的訴求,即 Component 中能夠表達但願增長哪些 trait。
apiVersion: core.oam.dev/v1alpha2 kind: WorkloadDefinition metadata: name: containerizedworkloads.core.oam.dev spec: definitionRef: name: containerizedworkloads.core.oam.dev
一個使用 ContainerizedWorkload 示例:
apiVersion: core.oam.dev/v1alpha2 kind: Component metadata: name: frontend annotations: version: v1.0.0 description: "A simple webserver" spec: workload: apiVersion: core.oam.dev/v1alpha2 kind: ContainerizedWorkload metadata: name: sample-workload spec: osType: linux containers: - name: web image: example/charybdis-single:latest@@sha256:verytrustworthyhash resources: cpu: required: 1.0 memory: required: 100MB env: - name: MESSAGE value: default parameters: - name: message description: The message to display in the web app. required: true type: string fieldPaths: - ".spec.containers[0].env[0].value"
對於原先是 K8s 上的應用管理平臺,接入改造爲 OAM 實現能夠分爲兩個階段:
現有的 CRD Operator** 功能上能夠平滑接入 OAM 體系,好比做爲一個獨立擴展 Workload 接入。可是爲了更好的讓終端用戶體會到 OAM 關注點分離的好處,咱們強烈建議 CRD Operator 根據研發和運維不一樣的關注點分離爲不一樣的 CRD,研發關注的 CRD 做爲 Workload 接入 OAM,運維關注的 CRD 做爲 Trait 接入 OAM。
目前,OAM 規範和模型實際已解決許多現有問題,但它的路程纔剛剛開始。OAM 是一箇中立的開源項目,咱們歡迎更多的人蔘與其中,共同定義雲原生應用交付的將來。
參與方式:
孫健波(花名:天元)阿里雲技術專家,是 OAM 規範的主要制定者之一,致力於推進雲原生應用標準化。同時也在阿里巴巴參與大規模雲原生應用交付與應用管理相關工做。團隊誠邀應用交付、Serverless、PaaS 領域的專家加入,歡迎聯繫 jianbo.sjb AT alibaba-inc.com
雲原生應用平臺誠邀 Kubernetes / Serverless / PaaS / 應用交付領域專家( P6-P8 )加盟:
簡歷馬上回復,2~3 周出結果,簡歷投遞:jianbo.sjb AT alibaba-inc.com。
「阿里巴巴雲原生關注微服務、Serverless、容器、Service Mesh 等技術領域、聚焦雲原生流行技術趨勢、雲原生大規模的落地實踐,作最懂雲原生開發者的技術圈。」