---
# System prepended metadata

title: Serverless Application Template
tags: [feature]

---

---
tags: feature
author: Oliver.W
---

# Serverless Application Template

Owner: Oliver
Stakeholders: 3rd part Applicaiton developers, Tencent, Serverless China, Serverless

Currently Tencent is working with 3rd part company publish their own application template for end users to easy set up and deploy their own apllications. As the sametime, we like the 3rd part developers can using serverless to build the template while the end user will just need simple configure to start using their own application.

eg: Record service to record and replay the stream content in a short period of time (near realtime.)

* Using Components Solution: Developers cant benefit from exist components and get benefits of serverless. 
* Using Templates Solution: No way to manage the template version and validation rules, also can't publish to registry, and hard to deploy through console.

### Current Template Implementation

当前 全景录制应用 需要配置的我内容

```md
* app：
* region：
* vpc:
    * vpcId: 
    * subnetId: 
* bucket:
* cfs:
* redis:
    * host
    * port
    * password
    * index
```

The currently serverless.yml for record service. 

```yml
component: multi-scf
name: web_record
app: ${env:NAME}
inputs:
src:
  src: ./
  exclude:
    - .env
    - record/**
    - node_modules/**
    - transcode/**
    - docker/**
    - dist/**
    - scripts/**
region: '${env:REGION}'
runtime: Nodejs12.16
role: SCF_QcsRole
memorySize: 256
isAutoPublish: true
timeout: 90
msgTTL: 21600
retryNum: 0
vpc:
  vpcId: '${env:VPC_ID}'
  subnetId: '${env:SUBNET_ID}'
environments:
  - key: SLS_APP_NAME
    value: '${app}'
  - key: ENV
    value: '${env:ENV}'
  - key: APP_VERSION
    value: '${env:APP_VERSION}'
  - key: VPC_ID
    value: '${env:VPC_ID}'
  - key: SUBNET_ID
    value: '${env:SUBNET_ID}'
  - key: REGION
    value: '${env:REGION}'
  - key: COS_BUCKET
    value: '${env:COS_BUCKET}'
  - key: CDN_DOMAIN
    value: '${env:CDN_DOMAIN}'
  - key: REDIS_HOST
    value: '${env:REDIS_HOST}'
  - key: REDIS_PORT
    value: '${env:REDIS_PORT}'
  - key: REDIS_AUTH
    value: '${env:REDIS_AUTH}'
  - key: REDIS_INDEX
    value: '${env:REDIS_INDEX}'
  - key: CFS_ID
    value: '${env:CFS_ID}'
  - key: MOUNT_ID
    value: '${env:MOUNT_ID}'
  - key: RECORD_IMAGE_URL
    value: '${env:RECORD_IMAGE_URL}'
  - key: REGISTRY_ID
    value: '${env:REGISTRY_ID}'
  - key: TRANSCODE_IMAGE_URL
    value: '${env:TRANSCODE_IMAGE_URL}'
functions:
  - name: '${app}-callback'
    src: ./callback
    handler: index.main_handler
    memorySize: 512
    asyncRunEnable: true
    traceEnable: true
  - name: '${app}-upload'
    src: ./upload
    handler: index.main_handler
    memorySize: 512
    timeout: 7200
    asyncRunEnable: true
    traceEnable: true
    cfs:
      - cfsId: '${env:CFS_ID}'
        mountInsId: '${env:MOUNT_ID}'
        localMountDir: /mnt/
        remoteMountDir: /
  - name: '${app}-transcode'
    memorySize: 3072
    timeout: 7200
    asyncRunEnable: true
    traceEnable: true
    image:
      imageUrl: '${env:TRANSCODE_IMAGE_URL}'
      imageType: public
      registryId: '${env:REGISTRY_ID}'
    cfs:
      - cfsId: '${env:CFS_ID}'
        mountInsId: '${env:MOUNT_ID}'
        localMountDir: /mnt/
        remoteMountDir: /
  - name: '${app}-record'
    memorySize: 3072
    timeout: 86400
    asyncRunEnable: true
    traceEnable: true
    image:
      imageUrl: '${env:RECORD_IMAGE_URL}'
      imageType: public
      registryId: '${env:REGISTRY_ID}'
    cfs:
      - cfsId: '${env:CFS_ID}'
        mountInsId: '${env:MOUNT_ID}'
        localMountDir: /mnt/
        remoteMountDir: /
  - name: '${app}-dispatch'
    memorySize: 256
    src: ./dispatch
    handler: index.main_handler
  - name: '${app}-diagnose'
    memorySize: 256
    timeout: 150
    src: ./diagnose
    handler: index.main_handler
triggers:
  - type: timer
    function: '${app}-dispatch'
    parameters:
      name: dispatch_timer
      cronExpression: 0 */10 * * * * *
      enable: true
      argument: Active
  - type: timer
    function: '${app}-diagnose'
    parameters:
      name: diagnose_timer
      cronExpression: '*/30 * * * * * *'
      enable: true
      argument: argument
  - type: timer
    function: '${app}-record'
    parameters:
      name: record_timer
      cronExpression: 0 */10 * * * * *
      enable: true
      argument: Active
  - type: apigw
    parameters:
      name: web_record
      protocols:
        - http
        - https
      description: Serverless web-record API GW
      environment: release
      apis:
        - path: /record
          apiName: dispatch_api
          method: POST
          description: Serverless REST API
          enableCORS: true
          responseType: JSON
          serviceTimeout: 90
          authType: APP
          function: '${app}-dispatch'
```

* The validation rules will still using the multi-scf rules.
* No way to manage the version of the template.
* It is hard for 3rd part developers build template and manage env configs.

## Objectives & Key Results

* 3rd part developer can use components to build Application Template and get benefits of Serverless.
* Application Template should have way to validte the config before deploy. 
* Application Template should have way to define the version of it.

## Proposed Solution

* Add new application template for this use case.
    * Similar to components config but can extend exist components
* End user can use application level config (serverless.yml) to deploy an applicaiton.


修改应用模板使用 组件模板 方式进行开发。如 创建新的 应用模板 `panorama-record` 后， 应用用户 通过 serverless.yml 进行实例配置， 应用开发者使用 serverless.components.yml 中的base 进行模板配置

### 使用 serverless.yml 进行配置

```
SDK. 
image: node12lts
image: tencent-scf-node12lts.

api.get('blogs') => {
....
}
```

```yml
component: multi-scf
name: web_record
app: ${APP:app}

inputs:
    src:
      src: ./
      exclude:
        - .env
        - record/**
        - node_modules/**
        - transcode/**
        - docker/**
        - dist/**
        - scripts/**
    runtime: Nodejs12.16
    role: SCF_QcsRole
        variable:
            default: xxx
            type: string
            rules: 
                - regex: '^[a-zA-Z][a-zA-Z0-9(_)]{0,48}[a-zA-Z0-9]?$'
                  message: "字符不接受"
                - min: 2
                  message: "长度过短"
                - max: 60
                  message: "长度过长"
                
    memorySize: 256
    isAutoPublish: true
    timeout: 90
    msgTTL: 21600
    retryNum: 0

    functions:

    triggers:
  
```

使用 新的[组件校验规则](https://hackmd.io/@serverless-cn/Sy-SRaU0d)完成 serverless.yml 的配置校验。  
  * 可以进行多个规则的校验
  * 通过接口可以直接对配置信息进行校验。
  * 在部署前进行校验

### 使用 serverless.application.yml 配置应用模板

```yml
name: panorama-record
version: 0.1.1
author: Tencent Cloud, Inc.
org: Tencent Cloud, Inc.
description: Deploy a serverless cloud function on Tencent Cloud.
keywords: tencent, serverless, SCF
repo: https://github.com/serverless-components/tencent-scf
readme: https://github.com/serverless-components/tencent-scf/tree/master/README.md
license: MIT
main: ./src
webDeployable: true

# 变量名称，变量类型，变量默认值。

template:  will use as default value for end users when they init. serverless.yml
    app： my-panorama-record-app
    component: panorama-record
    
    inputs: 
      region：ap-guangzhou
          type: string
          default:
          allow:
              - event
              - web
          ...
      vpc:
        vpcId: ${output:${stage}:${app}:sls-demo-msn-vpc.vpcId}
        subnetId: ${output:${stage}:${app}:sls-demo-msn-vpc.subnetId}
    bucket: my-bucket
    cfs: 
      cfsId: my-cfs
      mountId: 1
    redis:
      host: my-cfs.host.com
      port: 3022
      password: ${env: RedisPassword}
      index: 1
    images:
      transcodeUrl: mytrans.host.com
      recordUrl: myrecord.host.com
      registryId: 1
```

With this solution, The benefits are

* Easier for developer to config
* Set up each application config validation rules by reuse [components-types](https://github.com/serverless-components/tencent-types)
* Able to publish to registry and init through CLI.


## The future Serverless Architecture

* The application templates will be used like templates.
* End User can not modify the application template code beside make PR.
* End User need to config application app with `serverless.yml` as usual. 
* Application Template config example defineds in `serverless.application.yml`

![](https://i.imgur.com/IfHiEpF.png)

### 3rd pard developers UX

1. develop app as normal with `serverless.yml`
    ```yml
    component: multi-scf
    name: web_record
    app: ${base:app}

    inputs:
        src:
          src: ./
        runtime: Nodejs12.16
        role: SCF_QcsRole
        memorySize: 256
        isAutoPublish: true
        timeout: 90
        msgTTL: 21600
        retryNum: 0

    functions:
      - name: '${app}-callback'
        src: ./callback
        handler: index.main_handler
        memorySize: 512
        asyncRunEnable: true
      ...
     ```
2. add `serverless.applicaiton.yml` to the application template.
    * Application name, version etc info.
    * Confing file(serverless.yml) template.
    ```yml
    name: panorama-record
    version: 0.1.1
    author: Tencent Cloud, Inc.
    org: Tencent Cloud, Inc.
    description: Deploy a serverless cloud function on Tencent Cloud.
    keywords: tencent, serverless, SCF
    repo: https://github.com/serverless-components/tencent-scf
    readme: https://github.com/serverless-components/tencent-scf/tree/master/README.md
    license: MIT
    main: ./src
    webDeployable: true

    default:  # will use as default value for end users when they init.
        app： my-panorama-record-app
        component: panorama-record

        inputs: 
          region：ap-guangzhou
          vpc:
            vpcId: ${output:${stage}:${app}:sls-demo-msn-vpc.vpcId}
            subnetId: ${output:${stage}:${app}:sls-demo-msn-vpc.subnetId}
        bucket: my-bucket
        cfs: 
          cfsId: my-cfs
          mountId: 1
        redis:
          host: my-cfs.host.com
          port: 3022
          password: ${env: RedisPassword}
          index: 1
        images:
          transcodeUrl: mytrans.host.com
          recordUrl: myrecord.host.com
          registryId: 1
    ```
3. publish as serverless applicaiton template.
4. [optional]upload config validation into [components-types](https://github.com/serverless-components/tencent-types)

### end-user UX

1. init application with name registred
    * through CLI `sls init panorama-record --name my-record-service`
    * through Tencetn Console
2. fill the config file (serverless.yml)
    ```yml
    # serverless.yml

    app： my-panorama-record-app 
    component: panorama-record 

    inputs: 
      region：ap-guangzhou # 应用部署地区
      vpc:
        vpcId: ${output:${stage}:${app}:sls-demo-msn-vpc.vpcId}
        subnetId: ${output:${stage}:${app}:sls-demo-msn-vpc.subnetId}
    bucket: my-bucket
    cfs: 
      cfsId: my-cfs
      mountId: 1
    redis:
      host: my-cfs.host.com
      port: 3022
      password: ${env: RedisPassword}
      index: 1
    images:
      transcodeUrl: mytrans.host.com
      recordUrl: myrecord.host.com
      registryId: 1
    ```
3. deploy the applicaiton.
    * through CLI `sls deploy`
    * through Tencent Console