The App Store lets you create application services (CafeDeployment) with a single click from application templates that are defined by the Open Application Model (OAM). You can customize OAM templates to quickly create application services. This topic uses a sample template to demonstrate how to write a product template that complies with the OAM specification.
Background
The Open Application Model (OAM) is a standard specification for building and delivering cloud-native applications that was jointly launched by Alibaba and Microsoft. OAM aims to simplify application management by providing a new model for application definition, operations and maintenance (O&M), distribution, and delivery. In the context of Kubernetes, OAM serves as both a standard application definition project, similar to the now-inactive Kubernetes Application Custom Resource Definition (CRD) project, and a platform-layer project. The platform-layer project focuses on encapsulating, organizing, and managing various O&M capabilities in Kubernetes and connecting these capabilities to applications. By providing these two core features—defining applications and organizing the O&M capabilities to manage them—the OAM project has become a key component of Alibaba's strategy for upgrading its unified application architecture and building its next-generation Platform as a Service (PaaS)/Serverless platform.
In OAM, an application consists of three core concepts:
Component: The individual parts that constitute an application. A component can be a collection of microservices, a database, or a cloud load balancer.
Trait: A collection of O&M features that describe the application, such as Auto Scaling and Ingress. These are critical to the application's operation, but their implementation varies across different environments.
Application Configuration: An application configuration combines components and their corresponding traits to create a specific, deployable instance of an application.
For more information about OAM, see the official documentation.
Preparations
Download any of the following templates and upload it to AKS under App Store > Product Templates > Private Templates.
sofaboot-helloworld template: Demonstrates the release policy.
sofaboot-helloworld-service template: Demonstrates the network policy.
Directory description
After you upload the template, the directory structure of the configuration files is as follows:
The following are the key configuration files:
templates:
AppConfig.yaml: The application configuration file. This is usually written by O&M engineers.
Component.yaml: The component configuration file. This is usually written by developers.
values.yaml: Contains the application name, user logon name, and the four-tuple information for accessing middleware services.
NoteYou must specify values for `app` (application name), `access` (AccessKey ID), and `secret` (AccessKey secret). For more information, see Create an AccessKey to obtain the `access` and `secret` values.
Chart.yaml: Describes the metadata of the product template, including the template name, template version, and application version.
NoteThe value of the `type` parameter is fixed as `application` and cannot be changed. You can customize the other parameter values.

Template parameter description
For a description of the template parameters, refer to the comments in the sample template. You can modify the parameters as needed.
sofaboot-helloworld template
Component
apiVersion: core.oam.dev/v1alpha2
kind: Component # Component type: Must be Component
metadata:
name: "{{ .Release.Name }}-component" # Component name: Used to select the component in component[].componentName of the appconfig
spec:
# Parameter list: Contains all configurable parameters for the component. You can configure them using name and value in component[].parameterValues of the appconfig.
parameters:
- name: imageName # Parameter name: Must be unique within each component
required: false # Specifies whether a value must be provided when configuring this component in the appconfig
fieldPaths: # The corresponding field in the workload will be overwritten by this parameter
-"/spec/containers/0/image"
- name: sofa_instanceid
required: true
fieldPaths:
-"/spec/containers/0/env/2/value"
- name: sofa_anvip_endpoint
required: true
fieldPaths:
-"/spec/containers/0/env/3/value"
- name: sofa_ak
required: true
fieldPaths:
-"/spec/containers/0/env/4/value"
- name: sofa_sk
required: true
fieldPaths:
-"/spec/containers/0/env/5/value"
workload:
apiVersion: oam.cafe.cloud.alipay.com/v1alpha1
kind: CafeContainerizedworkload # Existing workload type: CafeContainerizedworkload
spec:
containers:
- name: sofaboot-helloworld
image: registry-vpc.cn-shanghai.aliyuncs.com/sofastackcafe/sofaboot-helloworld:v0.0.1
resources:
limits:
memory: "700Mi"
cpu: "700m"
requests:
memory: "500Mi"
cpu: "500m"
ports:
- containerPort: 8080
protocol: TCP
- containerPort: 8341
protocol: TCP
env:
- name: run.mode
value: NORMAL
- name: logging.path
value: /home/admin/logs
- name: SOFA_INSTANCE_ID
value: ""
- name: SOFA_ANTVIP_ENDPOINT
value: ""
- name: SOFA_ACCESS_KEY
value: ""
- name: SOFA_SECRET_KEY
value: ""
Application Configuration
apiVersion: core.oam.dev/v1alpha2
kind: ApplicationConfiguration
metadata:
name: "{{ .Release.Name }}" # The release name entered when installing the template
annotations:
app.kubernetes.io/name: "{{ .Values.sofastack.app}}" # Name of the application to which it belongs (required)
app.kubernetes.io/description: "{{ .Release.Name }} from OAM Chart"
cafe.sofastack.io/loginName: "{{ .Values.sofastack.loginName }}" # Logon name of the owner/operator (optional)
cafe.sofastack.io/userId: "{{ .Values.sofastack.userId }}" # User ID of the owner/operator (optional)
spec:
components:
- componentName: "{{ .Release.Name }}-component" # Component name: Must be the same as component.metadata.name
parameterValues: # Overwrites the corresponding parameters in component.spec.parameters
- name: sofa_instanceid
value: "{{ .Values.sofastack.instanceid }}"
- name: sofa_anvip_endpoint
value: "{{ .Values.sofastack.endpoint }}"
- name: sofa_ak
value: "{{ .Values.sofastack.access }}"
- name: sofa_sk
value: "{{ .Values.sofastack.secret }}"
traits:
- trait:
apiVersion: core.oam.dev/v1alpha2
kind: Strategy # Existing O&M feature types: Strategy, CafeService
metadata:
annotations:
groupStrategy: QUICK # Grouping strategy: QUICK (quick grouping), EACH_ONE (one pod per group), or ALL_ONE (all in one group)
groupCount: 1 # Number of pods per group
enableSofaMesh: false # enableSofaMesh: Specifies whether to enable Mesh. Valid values: true, false (default).
spec:
replicas: 1 # Number of pod replicas
strategy:
upgradeType: Beta # Beta grouping
needWaitingForConfirm: true # In a batch release, specifies whether to wait for user confirmation for each batch
sofaboot-helloworld-service template
Component
apiVersion: core.oam.dev/v1alpha2
kind: Component # Component type: Must be Component
metadata:
name: "{{ .Release.Name }}-component" # Component name: Used to select the component in component[].componentName of the appconfig
spec:
# Parameter list: Contains all configurable parameters for the component. You can configure them using name and value in component[].parameterValues of the appconfig.
parameters:
- name: imageName # Parameter name: Must be unique within each component
required: false # Specifies whether a value must be provided when configuring this component in the appconfig
fieldPaths: # The corresponding field in the workload will be overwritten by this parameter
-"/spec/containers/0/image"
- name: sofa_instanceid
required: true
fieldPaths:
-"/spec/containers/0/env/2/value"
- name: sofa_anvip_endpoint
required: true
fieldPaths:
-"/spec/containers/0/env/3/value"
- name: sofa_ak
required: true
fieldPaths:
-"/spec/containers/0/env/4/value"
- name: sofa_sk
required: true
fieldPaths:
-"/spec/containers/0/env/5/value"
workload:
apiVersion: oam.cafe.cloud.alipay.com/v1alpha1
kind: CafeContainerizedworkload # Existing workload type: CafeContainerizedworkload
spec:
containers:
- name: sofaboot-helloworld
image: registry-vpc.cn-shanghai.aliyuncs.com/sofastackcafe/sofaboot-helloworld:v0.0.1
resources:
limits:
memory: "700Mi"
cpu: "700m"
requests:
memory: "500Mi"
cpu: "500m"
ports:
- containerPort: 8080
protocol: TCP
- containerPort: 8341
protocol: TCP
env:
- name: run.mode
value: NORMAL
- name: logging.path
value: /home/admin/logs
- name: SOFA_INSTANCE_ID
value: ""
- name: SOFA_ANTVIP_ENDPOINT
value: ""
- name: SOFA_ACCESS_KEY
value: ""
- name: SOFA_SECRET_KEY
value: ""
Application Configuration
apiVersion: core.oam.dev/v1alpha2
kind: ApplicationConfiguration
metadata:
name: "{{ .Release.Name }}"
annotations:
app.kubernetes.io/name: "{{ .Values.sofastack.app}}" # Name of the application to which it belongs (required)
app.kubernetes.io/description: "{{ .Release.Name }} from OAM Chart"
cafe.sofastack.io/loginName: "{{ .Values.sofastack.loginName }}" # Logon name of the owner/operator (required)
cafe.sofastack.io/userId: "{{ .Values.sofastack.userId }}"
spec:
components:
- componentName: "{{ .Release.Name }}-component" # Component name: Must be the same as component.metadata.name
parameterValues: # Overwrites the corresponding parameters in component.spec.parameters
- name: sofa_instanceid
value: "{{ .Values.sofastack.instanceid }}"
- name: sofa_anvip_endpoint
value: "{{ .Values.sofastack.endpoint }}"
- name: sofa_ak
value: "{{ .Values.sofastack.access }}"
- name: sofa_sk
value: "{{ .Values.sofastack.secret }}"
traits:
- trait:
apiVersion: core.oam.dev/v1alpha2
kind: Strategy # Existing O&M feature types: Strategy, CafeService
metadata:
annotations:
groupStrategy: EACH_ONE # Grouping strategy: QUICK (quick grouping), EACH_ONE (one pod per group), or ALL_ONE (all in one group)
groupCount: 2 # BatchSize Number of pods per group
# enableSofaMesh: true # enableSofaMesh: true or false (default)
spec:
replicas: 1 # Total number of pods
strategy:
batchSize: 1 # Number of pods to update in each batch during an upgrade
upgradeType: Beta # Beta grouping
needWaitingForConfirm: true # In a batch release, specifies whether to wait for user confirmation for each batch
topology:
unitType: Cell
values: # Deployment unit
-CellA
# podSetType: InPlaceSet # Upgrade policy: InPlaceSet (in-place) or ReplicaSet (replace, default)
- trait:
apiVersion: core.oam.dev/v1alpha2
kind: CafeService
metadata:
name: sofaboot-helloworld-service
annotations:
service.beta.kubernetes.io/antcloud-loadbalancer-address-type: INTERNET # Load balancer type (required for access from outside the cluster): INTRANET (internal network) or INTERNET (public network)
service.beta.kubernetes.io/antcloud-loadbalancer-internet-charge-type: PAY_BY_TRAFFIC
service.beta.kubernetes.io/antcloud-loadbalancer-listener-healthcheck: 8080:ON;8341:ON
service.beta.kubernetes.io/antcloud-loadbalancer-listener-healthcheck-interval: "8080:2;8341:2" # Health check interval (required for access from outside the cluster): Specify the interval for each port separately, such as 8341:3. Use semicolons (;) to separate them. (Alibaba Cloud default: 45; Finance Cloud default: 5)
service.beta.kubernetes.io/antcloud-loadbalancer-listener-healthcheck-timeout: "8080:5;8341:5" # Health check timeout (required for access from outside the cluster): Specify the timeout for each port separately, such as 8341:3. Use semicolons (;) to separate them.
service.beta.kubernetes.io/antcloud-loadbalancer-listener-scheduler: 8080:WRR;8341:WRR # Forwarding rule (required for access from outside the cluster): WRR or WLC
service.beta.kubernetes.io/antcloud-loadbalancer-port-protocol: 8080:TCP;8341:TCP
service.beta.kubernetes.io/antcloud-loadbalancer-lb-name: sofaboot # Load balancer name (required for access from outside the cluster)
# service.beta.kubernetes.io/antcloud-loadbalancer-listener-healthcheck-uri: 8080:/actuator/readiness;8341:/actuator/readiness # Health check path (required for access from outside the cluster if the protocol type is http/https): Set the check path for each port separately. Use semicolons (;) to separate them.
# service.beta.kubernetes.io/antcloud-loadbalancer-listener-healthcheck-domain: 8080:www.alipay.net # Health check domain name (optional)
spec:
type: 'LoadBalancer' # Access method: "ClusterIP" (cluster-internal access), "LoadBalancer" (VPC network access), 'LoadBalancer' (public network access)
ports:
- protocol: TCP # Protocol type (required): TCP, UDP, HTTP, or HTTPS
port: 8080 # Frontend port
targetPort: 8080 # Backend port
# name: helloworld-conn # Service name
- protocol: TCP
port: 8341
targetPort: 8341