AWS serverless.yml 文件详解

澹台景辉
2023-12-01

serverless.yml文件的作用

  • service: 声明一个serverless的service
  • frameworkVersion:用于指定部署时需要的serverless版本,可以使用sls -v命令查看本地安装的serverless的版本
  • plugins:定义service用到的plugin
  • provider: 定义云服务提供者,比如aws
  • functions:在service中定义一个或多个函数,对于aws来说,就是lambda函数
  • events:定义触发函数的事件,比如http 请求,在events中定义的资源在部署时会自动创建
  • resources:定义函数使用到的一系列的资源,比如AWS DynamoDB table
  • variables: 可以使用变量来进行灵活配置

service

一个service可以认为是一个工程,service通过其根目录下的serverless.yml文件定义了service提供的lambda函数,触发lambda函数的events,以及lambda函数用到的各种resources.

创建service

可以使用serverless create命令使用模版创建一个service,详情请参考: AWS Serverless CLI命令参考2--Create&Install.

每个serverless.yml文件都会被翻译成一个AWS CloudFormation模版,在部署时会使用该模版创建一个CloudFormation stack.

部署service

可以使用serverless deploy命令对service进行部署,详情请参考: AWS Serverless CLI命令参考3--package&deploy

删除部署的service

可以使用serverless remove命令对service进行部署,详情请参考: AWS Serverless CLI命令参考5--rollback&remove

frameworkVersion

通过在serverless.yml文件中指定frameworkVersion属性,可以对部署该service所需的serverless的版本进行限制.通过限制版本可以避免由serverless版本升级导致的错误.

如果制定了该属性, 在运行serverless命令时会检查serverless的版本与文件中定义的版本是否一致.

指定一个确定的版本:

# serverless.yml

frameworkVersion: "=1.0.3"

service: users

provider:
  name: aws
  runtime: java8
  memorySize: 512

指定一个版本范围

#Version Range
# serverless.yml

frameworkVersion: ">=1.0.0 <2.0.0"

service: users

provider:
  name: aws
  runtime: java8
  memorySize: 512

plugins

插件就是用于创建新的或者扩展原有的serverless framework命令的自定义的js代码.serverless framework本身由一组核心插件构成.

插件类型包括external plugins 和 core plugins.

安装插件

external plugins需要为每个service单独安装,在service的根目录下执行如下命令即可:

npm install --save custom-serverless-plugin

使用插件

在serverless.yml中的plugins属性中指定service需要使用的插件

plugins:
  - plugin1
  - plugin2

配置插件

可以通过serverless.yml的custom属性配置plugin

plugins:
  - custom-serverless-plugin

custom:
  customkey: customvalue

provider

用于指定服务提供商,以及lambda函数或其他资源用到的公共配置等,如果lambda函数没有对这些配置进行覆盖,则会使用provider中定义的配置.

custom:
  configFile: ${file(config.yml)}

provider:
  name: aws
  region: ${self:custom.configFile.region}
  stage: ${self:custom.configFile.stage}
  variant: ${self:custom.configFile.variant} 
  runtime: java8
  timeout: 30 # The default is 6 seconds. Note: API Gateway current maximum is 30 seconds
  memorySize: 1024 # Overwrite the default memory size. Default is 1024. Increase by 64.
  deploymentBucket: ${self:custom.configFile.deploymentBucket}
  environment: ${file(config.yml)}
  stackName: ${self:provider.stage}-${self:provider.variant}-${self:service}
  versionFunctions: ${self:custom.configFile.versionFunctions}

functions

配置

aws的所有lambda函数都定义在functions属性下,provider中可以对所有的function进行权限全局配置,比如runtime, timeout,每个function可以对provider的配置进行重写.

# serverless.yml
service: myService

provider:
  name: aws
  runtime: nodejs12.x
  memorySize: 512 # optional, in MB, default is 1024
  timeout: 10 # optional, in seconds, default is 6
  versionFunctions: false # optional, default is true
  tracing:
    lambda: true # optional, enables tracing for all functions (can be true (true equals 'Active') 'Active' or 'PassThrough')

functions:
  hello:
    handler: handler.hello # required, handler set in AWS Lambda
    name: ${opt:stage, self:provider.stage, 'dev'}-lambdaName # optional, Deployed Lambda name
    description: Description of what the lambda function does # optional, Description to publish to AWS
    runtime: python2.7 # optional overwrite, default is provider runtime
    memorySize: 512 # optional, in MB, default is 1024
    timeout: 10 # optional, in seconds, default is 6
    provisionedConcurrency: 3 # optional, Count of provisioned lambda instances
    reservedConcurrency: 5 # optional, reserved concurrency limit for this function. By default, AWS uses account concurrency limit
    tracing: PassThrough # optional, overwrite, can be 'Active' or 'PassThrough'

functions属性下可以定义多个function

service: myService

provider:
  name: aws
  runtime: nodejs12.x

functions:
  functionOne:
    handler: handler.functionOne
    description: optional description for your Lambda
  functionTwo:
    handler: handler.functionTwo
  functionThree:
    handler: handler.functionThree

function 可以通过单独的ymal文件进行定义,并在serverless.yml文件中引入

# serverless.yml
---
functions:
  - ${file(../foo-functions.yml)}
  - ${file(../bar-functions.yml)}


# foo-functions.yml
getFoo:
  handler: handler.foo
deleteFoo:
  handler: handler.foo

权限

lambda函数与其他aws资源进行交互时,需要具有访问被访问资源的权限,可以通过provider.iamRoleStatements 属性设置lambda函数的权限,也可以通过provider.role或者在定义function时指定role来配置函数权限.

provider.iamRoleStatements

# serverless.yml
service: myService

provider:
  name: aws
  runtime: nodejs12.x
  iamRoleStatements: # permissions for all of your functions can be set here
    - Effect: Allow
      Action: # Gives permission to DynamoDB tables in a specific region
        - dynamodb:DescribeTable
        - dynamodb:Query
        - dynamodb:Scan
        - dynamodb:GetItem
        - dynamodb:PutItem
        - dynamodb:UpdateItem
        - dynamodb:DeleteItem
      Resource: 'arn:aws:dynamodb:us-east-1:*:*'
    - Effect: 'Allow'
      Action:
        - 's3:ListBucket'
      # You can put CloudFormation syntax in here.  No one will judge you.
      # Remember, this all gets translated to CloudFormation.
      Resource: { 'Fn::Join': ['', ['arn:aws:s3:::', { 'Ref': 'ServerlessDeploymentBucket' }]] }
    - Effect: 'Allow'
      Action:
        - 's3:PutObject'
      Resource:
        Fn::Join:
          - ''
          - - 'arn:aws:s3:::'
            - 'Ref': 'ServerlessDeploymentBucket'
            - '/*'
functions:
  functionOne:
    handler: handler.functionOne
    memorySize: 512

provider.role

# serverless.yml
service: new-service
provider:
  name: aws
  role: arn:aws:iam::YourAccountNumber:role/IamRole1

functions:
  # use role 
  functionOne:
    handler: handler.functionOne
  functionTwo:
    handler: handler.functionTwo
    role: arn:aws:iam::YourAccountNumber:role/IamRole2

VPC配置

可以通过在 lambda函数的配置中添加vpc属性配置来对特定的lambda函数进行vpc配置,也可以在provider中添加添加vpc属性配置来对所有的lambda函数进行vpc配置。两个都定义时,lambda函数的配置优先级高。

vpc配置必须包含 securityGroupIds 和subnetIds属性

# serverless.yml
service: service-name
provider:
  name: aws
  vpc:
    securityGroupIds:
      - securityGroupId1
      - securityGroupId2
    subnetIds:
      - subnetId1
      - subnetId2

functions:
  hello: # this function will overwrite the service level vpc config above
    handler: handler.hello
    vpc:
      securityGroupIds:
        - securityGroupId1
        - securityGroupId2
      subnetIds:
        - subnetId1
        - subnetId2
  users: # this function will inherit the service level vpc config above
    handler: handler.users

VPC IAM权限

使用vpc配置时必须保证lambda函数的执行权限包含 Elastic Network Interfaces (ENI)的创建,描述和删除权限。

参考:配置 Lambda 函数以访问 VPC 中的资源

VPC Lambda Internet 访问权限

默认配置下,当lambda函数在vpc内运行时,它会失去对Internet的访问权限,因此无法使用一些AWS资源。

为了使lambda函数能够访问S3和DynamoDB,需要创建一个VPC end point,参考 VPC Endpoint for Amazon S3

为了使lambda函数能够Kinesisi streams,需要在运行lambda的子网内配置一个NAT Gateway,参考Enable Outgoing Internet Access within VPC

环境变量

可以通过在 lambda函数的配置中添加environment属性配置来对特定的lambda函数进行环境变量配置,也可以在provider中添加添加environment属性配置来对所有的lambda函数进行环境变量配置。两个都定义时,lambda函数的配置优先级高。

# serverless.yml
service: service-name
provider:
  name: aws
  environment:
    SYSTEM_NAME: mySystem
    TABLE_NAME: tableName1

functions:
  hello:
    # this function will have SYSTEM_NAME=mySystem and TABLE_NAME=tableName1 from the provider-level environment config above
    handler: handler.hello
  users:
    # this function will have SYSTEM_NAME=mySystem from the provider-level environment config above
    # but TABLE_NAME will be tableName2 because this more specific config will override the default above
    handler: handler.users
    environment:
      TABLE_NAME: tableName2

可以使用整个yaml文件作为环境变量的源

# serverless.yml
service: service-name
provider:
  name: aws  
  environment: ${file(environment.yml)}

Tags

可以通过在 lambda函数的配置中添加tags属性配置来对特定的lambda函数进行tag配置,也可以在provider中添加添加tags属性配置来对所有的lambda函数进行tag配置。两个都定义时,lambda函数的配置优先级高。

# serverless.yml
service: service-name
provider:
  name: aws
  tags:
    foo: bar
    baz: qux

functions:
  hello:
    # this function will inherit the service level tags config above
    handler: handler.hello
  users:
    # this function will overwrite the foo tag and inherit the baz tag
    handler: handler.users
    tags:
      foo: quux

Layers

通过layers属性可以对lambda函数使用的层进行配置,layer的配置请参考: Layers

functions:
  hello:
    handler: handler.hello
    layers:
      - arn:aws:lambda:region:XXXXXX:layer:LayerName:Y

Log Group Resources

默认情况下,lambda函数的log group无需手动创建,serverless framework会为lambda函数自动创建log group。

可以通过disableLogs属性禁用log group。

functions:
  hello:
    handler: handler.hello
    disableLogs: true

版本管理

默认情况下,serverless framework会为lambda函数的每次部署创建一个版本,可以通过versionFunctions属性进行配置。

provider:
  versionFunctions: false

死信队列

lambda函数执行失败时会进行重试,如果重试依然失败,aws通过死信队列对失败的函数进行保存,以便后续对执行失败的原因进行追踪和分析。

死信队列可是SNS和SQS.

SNS

可以通过onError配置属性和SNS的topic实现死信队列。

service: service

provider:
  name: aws
  runtime: nodejs12.x

functions:
  hello:
    handler: handler.hello
    onError: arn:aws:sns:us-east-1:XXXXXX:test # Ref, Fn::GetAtt and Fn::ImportValue are supported as well

SQS

虽然lambda的死信队列支持SNS和SQS,但是目前onError 只支持SNS。

KMS Keys

AWS Lambda使用KMS Keys对环境变量进行加密。

awsKmsKeyArn 属性用于指定使用哪个key来进行加密。

service:
  name: service-name
  awsKmsKeyArn: arn:aws:kms:us-east-1:XXXXXX:key/some-hash

provider:
  name: aws
  environment:
    TABLE_NAME: tableName1

functions:
  hello: # this function will OVERWRITE the service level environment config above
    handler: handler.hello
    awsKmsKeyArn: arn:aws:kms:us-east-1:XXXXXX:key/some-hash
    environment:
      TABLE_NAME: tableName2
  goodbye: # this function will INHERIT the service level environment config above
    handler: handler.goodbye

AWS X-Ray Tracing

可以通过X-Ray对lambda函数的执行时间进行监控,通过配置tracing属性可以对监控进行开关。

# serverless.yml
service: myService

provider:
  name: aws
  runtime: nodejs12.x
  tracing:
    lambda: true # optional, enables tracing for all functions (can be true (true equals 'Active') 'Active' or 'PassThrough')

functions:
  hello:
    handler: handler.hello # required, handler set in AWS Lambda
    name: ${opt:stage, self:provider.stage, 'dev'}-lambdaName # optional, Deployed Lambda name
    tracing: PassThrough # optional, overwrite, can be 'Active' or 'PassThrough'

Destinations

异步调用lambda的时候需要配置异步调用目标,异步调用目标可以是其他lambda函数,EventBridge,SQS或者SNS 。可为处理失败的事件和处理成功的事件配置单独的目标。

参考:配置异步调用目标 

functions:
  asyncHello:
    handler: handler.asyncHello
    destinations:
      onSuccess: otherFunctionInService
      onFailure: arn:aws:sns:us-east-1:xxxx:some-topic-name

events

events用于触发lambda函数。对于aws而言,events就是用于触发lambda函数的任意事件,比如 S3的文件上传,SNS topic,API Gateway创建的HTTP endpoints。

部署lambda函数时,serverless framework会自动创建event所需的资源,并且配置lambda函数对资源进行监听。

# 'functions' in serverless.yml
functions:
  createUser: # Function name
    handler: handler.users # Reference to file handler.js & exported function 'users'
    events: # All events associated with this function
      - http:
          path: users/create
          method: post
      - http:
          path: users/update
          method: put
      - http:
          path: users/delete
          method: delete
     - http: #support path variable
          path: users/{id}
          method: get

layers

用于对aws lambda layer进行配置。

layers属性中最多可以添加5个layer。

# serverless.yml
service: myService

provider:
  name: aws

layers:
  hello:
    path: layer-dir # required, path to layer contents on disk
    name: ${opt:stage, self:provider.stage, 'dev'}-layerName # optional, Deployed Lambda layer name
    description: Description of what the lambda layer does # optional, Description to publish to AWS
    compatibleRuntimes: # optional, a list of runtimes this layer is compatible with
      - python3.8
    licenseInfo: GPLv3 # optional, a string specifying license information
    # allowedAccounts: # optional, a list of AWS account IDs allowed to access this layer.
    #   - '*'
    # note: uncommenting this will give all AWS users access to this layer unconditionally.
    retain: false # optional, false by default. If true, layer versions are not deleted as new ones are created

path

  • 用于指定layer包含的内容所在的位置。

  • path与package:artifact必须设置一个。

# serverless.yml
service: myService

provider:
  name: aws

layers:
  layerOne:
    package:
      artifact: layerSource.zip

package

  • 可以继承自权限的package属性也可以在layer中对全局的package属性进行覆盖

# serverless.yml
service: myService

provider:
  name: aws

package:
  exclude:
    - layerSourceTarball1.tar.gz

layers:
  layerOne:
    path: layerOne
  layerTwo:
    path: layerTwo
    package:
      exclude:
        - layerSourceTarball2.tar.gz

权限

可以通过allowedAccounts对layer的访问权限进行配置。

# serverless.yml
service: myService

provider:
  name: aws

layers:
  layerOne:
    path: layerOne
    allowedAccounts:
      - 111111111111 # a specific account ID
      - 222222222222 # a different specific account ID
  layerTwo:
    path: layerTwo
    allowedAccounts:
      - '*' # ALL accounts!

在lambda函数中使用layer

可以通过layer的arn在lambda配置中指定使用哪一个layer,如果layer与lambda函数定义在同一个配置文件中,还可以使用CloudFormation Ref来指定使用哪一个layer。

# serverless.yml
service: myService

provider:
  name: aws

layers:
  layerOne:
    path: layerOne
    allowedAccounts:
      - 111111111111 # a specific account ID
      - 222222222222 # a different specific account ID
  layerTwo:
    path: layerTwo
    allowedAccounts:
      - '*' # ALL accounts!
functions:
  hello1:
    handler: handler.hello1
    layers:
      - arn:aws:lambda:region:XXXXXX:layer:LayerName:Y
  hello2:
    handler: handler.hello2
    layers:
      - { Ref: layerTwo}

resources

使用原生的CloudFormation模板语法来定义resources。resources中可以使用ResourcesOutputs属性。

aws资源命名规则参考

normalizedFunctionName即为配置文件中指定的名字经过一下处理得到的字符串:

  • 首字符大写
  • -   会被替换为Dash
  • _ 下划线会被替换为Underscore

对于如下lambda函数:

  • hello-test1的normalizedFunctionName为HelloDashTest1
  • hello_test2的normalizedFunctionName为HelloUnderscoreTest2
# serverless.yml
service: service-name
provider:
  name: aws

functions:
  hello-test1:
    handler: handler.hello1
    name: hello1
  hello_test2:
    handler: handler.hello2
    name: hello2

在最终生成的CloudFormation模板中:

(注意资源名称并不是function配置中的name属性,资源名称是可以通过CloudFormation Ref进行引用的)

  • hello-test1
    • lambda函数的资源名字为:HelloDashTest1LambdaFunction。
    • lambda函数的LogGroup的资源名字为:HelloDashTest1LogGroup
  • hello_test2
    • lambda函数的资源名字为:HelloUnderscoreTest2Function。
    • lambda函数的LogGroup的资源名字为:HelloUnderscoreTest2LogGroup
AWS ResourceName TemplateExample
S3::BucketS3Bucket{normalizedBucketName}S3BucketMybucket
IAM::RoleIamRoleLambdaExecutionIamRoleLambdaExecution
Lambda::Function{normalizedFunctionName}LambdaFunctionHelloLambdaFunction
Lambda::Version{normalizedFunctionName}LambdaVersion{sha256}HelloLambdaVersionr3pgoTvv1xT4E4NiCL6JG02fl6vIyi7OS1aW0FwAI
Logs::LogGroup{normalizedFunctionName}LogGroupHelloLogGroup
Lambda::Permission
  • Schedule: {normalizedFunctionName}LambdaPermissionEventsRuleSchedule{index}
  • CloudWatch Event: {normalizedFunctionName}LambdaPermissionEventsRuleCloudWatchEvent{index}
  • CloudWatch Log: {normalizedFunctionName}LambdaPermissionLogsSubscriptionFilterCloudWatchLog{index}
  • IoT: {normalizedFunctionName}LambdaPermissionIotTopicRule{index}
  • S3: {normalizedFunctionName}LambdaPermission{normalizedBucketName}S3
  • APIG: {normalizedFunctionName}LambdaPermissionApiGateway
  • SNS: {normalizedFunctionName}LambdaPermission{normalizedTopicName}SNS
  • Alexa Skill: {normalizedFunctionName}LambdaPermissionAlexaSkill
  • Alexa Smart Home: {normalizedFunctionName}LambdaPermissionAlexaSmartHome{index}
  • Cognito User Pool Trigger Source: {normalizedFunctionName}LambdaPermissionCognitoUserPool{normalizedPoolId}TriggerSource{triggerSource}
  • Schedule: HelloLambdaPermissionEventsRuleSchedule1
  • CloudWatch Event: HelloLambdaPermissionEventsRuleCloudWatchEvent1
  • CloudWatch Log: HelloLambdaPermissionLogsSubscriptionFilterCloudWatchLog1
  • IoT: HelloLambdaPermissionIotTopicRule1
  • S3: HelloLambdaPermissionBucketS3
  • APIG: HelloLambdaPermissionApiGateway
  • SNS: HelloLambdaPermissionTopicSNS
  • Alexa Skill: HelloLambdaPermissionAlexaSkill
  • Alexa Smart Home: HelloLambdaPermissionAlexaSmartHome1
  • Cognito User Pool Trigger Source: HelloLambdaPermissionCognitoUserPoolMyPoolTriggerSourceCustomMessage
Events::Rule
  • Schedule: {normalizedFunctionName}EventsRuleSchedule{SequentialID}
  • CloudWatch Event: {normalizedFunctionName}EventsRuleCloudWatchEvent{SequentialID}
  • Schedule: HelloEventsRuleSchedule1
  • CloudWatch Event: HelloEventsRuleCloudWatchEvent1
AWS::Logs::SubscriptionFilter{normalizedFunctionName}LogsSubscriptionFilterCloudWatchLog{SequentialID}HelloLogsSubscriptionFilterCloudWatchLog1
AWS::IoT::TopicRule{normalizedFunctionName}IotTopicRule{SequentialID}HelloIotTopicRule1
ApiGateway::RestApiApiGatewayRestApiApiGatewayRestApi
ApiGateway::ResourceApiGatewayResource{normalizedPath}ApiGatewayResourceUsers
ApiGateway::MethodApiGatewayMethod{normalizedPath}{normalizedMethod}ApiGatewayMethodUsersGet
ApiGateway::Authorizer{normalizedFunctionName}ApiGatewayAuthorizerHelloApiGatewayAuthorizer
ApiGateway::DeploymentApiGatewayDeployment{instanceId}ApiGatewayDeployment12356789
ApiGateway::ApiKeyApiGatewayApiKey{OptionalNormalizedName}{SequentialID}ApiGatewayApiKeyFree1
ApiGateway::UsagePlanApiGatewayUsagePlan{OptionalNormalizedName}ApiGatewayUsagePlanFree
ApiGateway::UsagePlanKeyApiGatewayUsagePlanKey{OptionalNormalizedName}{SequentialID}ApiGatewayUsagePlanKeyFree1
ApiGateway::StageApiGatewayStageApiGatewayStage
SNS::TopicSNSTopic{normalizedTopicName}SNSTopicSometopic
SNS::Subscription{normalizedFunctionName}SnsSubscription{normalizedTopicName}HelloSnsSubscriptionSomeTopic
AWS::Lambda::EventSourceMapping
  • DynamoDB: {normalizedFunctionName}EventSourceMappingDynamodb{tableName}
  • Kinesis: {normalizedFunctionName}EventSourceMappingKinesis{streamName}
  • DynamoDB: HelloLambdaEventSourceMappingDynamodbUsers
  • Kinesis: HelloLambdaEventSourceMappingKinesisMystream
Cognito::UserPoolCognitoUserPool{normalizedPoolId}CognitoUserPoolPoolId

自定义资源属性

可以通过在resources.extensions中定义与自动生成的资源属性名称相同的资源来对自动生成的资源的配置进行重写。

一下配置会将hello-test1生成的log group的保留时间设置为30天。

# serverless.yml
service: service-name
provider:
  name: aws

functions:
  hello-test1:
    handler: handler.hello1
    name: hello1
  hello_test2:
    handler: handler.hello2
    name: hello2

resources:
  extensions:
    HelloDashTest1LogGroup:
      Properties:
        RetentionInDays: '30'

对不同的配置选项,重写规则不同,有的会覆盖默认配置,有的则与默认配置进行合并,具体参考下表:

Resource attributeOperation
CreationPolicySet to extension value if present.
DeletionPolicySet to extension value if present.
DependsOnMerge. The extension value will be added to the resource's DependsOn list.
MetadataMerge. If a metadata key with the same name exists in the resource, the value will be replaced with the extension value.
PropertiesMerge. If a property with the same name exists in the resource, the value will be replaced with the extension value.
UpdatePolicySet to extension value if present.
UpdateReplacePolicySet to extension value if present.
otherNot supported. An error will be thrown if you try to extend an unsupported attribute.

variables

在配置文件中使用${} 对变量进行引入。

变量来源

递归引用属性

provider:
  name: aws
  stage: ${opt:stage, 'dev'}
  environment:
    MY_SECRET: ${file(../config.${opt:stage, self:provider.stage, 'dev'}.json):CREDS}

对于上述示例:

  • 使用sls deploy --stage qa 命令对service进行部署时,opt:stage的value即为qa,因此MY_SECRET最终会被解析为${file(../config.qa.json):CREDS},即使用上层目录的config.qa.json文件中定义的CREDS属性的值作为MY_SECRET
  • 使用sls deploy 命令对service进行部署时,则provider.stage会使用默认值dev,因此MY_SECRET最终会被解析为${file(../config.dev.json):CREDS},即使用上层目录的config.qadev.json文件中定义的CREDS属性的值作为MY_SECRET

引用serverless.yml中的属性

可以使用${self:someProperty}对当前serverless文件中的属性进行引用

service: new-service
provider: aws
custom:
  globalSchedule: rate(10 minutes)
  newService: ${self:}
  # the following will resolve identically in other serverless.yml files so long as they define
  # `custom.newService: ${file(<relative-path-to-this-file>/serverless.yml)}`
  exportName: ${self:custom.newService.service}-export

functions:
  hello:
    handler: handler.hello
    events:
      - schedule: ${self:custom.globalSchedule}
  world:
    handler: handler.world
    events:
      - schedule: ${self:custom.globalSchedule}
resources:
  Outputs:
    NewServiceExport:
      Value: 'A Value To Export'
      Export:
        Name: ${self:custom.exportName}

引用Serverless Core Variables

Serverless initializes core variables 是Framework 内部使用的变量,这些变量会通过Serverless Variables暴露出来,可以通过 ${sls:}进行引用。

目前可用的变量为:instanceId

instanceId是 Serverless CLI 运行时随机生成的。

service: new-service
provider: aws

functions:
  func1:
    name: function-1
    handler: handler.func1
    environment:
      APIG_DEPLOYMENT_ID: ApiGatewayDeployment${sls:instanceId}

引用 Environment Variables

可以使用${env:SOME_VAR}引用环境变量。

${env:}表示引用所有的环境变量。

service: new-service
provider: aws
functions:
  hello:
    name: ${env:FUNC_PREFIX}-hello
    handler: handler.hello
  world:
    name: ${env:FUNC_PREFIX}-world
    handler: handler.world

引用CLI Options

可以使用 ${opt:some_option} 引用命令行参数。

${env:}表示引用所有的命令行参数。

service: new-service
provider: aws
functions:
  hello:
    name: ${opt:stage}-hello
    handler: handler.hello
  world:
    name: ${opt:stage}-world
    handler: handler.world

在上述示例中使用serverless deploy --stage dev命令对service进行部署时${opt:stage}的值即为dev。

引用CloudFormation Outputs

通过${cf:stackName.outputKey} 来对同一个region中的其他service的CloudFormation stack的导出属性进行引用.

service: new-service
provider: 
  name: aws
  region: ap-northeast-1
functions:
  hello:
    name: ${cf:another-service-stack.prefix}-hello
    handler: handler.hello
service: another-service
custom:
  functionPrefix: 'my-prefix-'

provider:
  name: aws
  runtime: nodejs12.x
  region: ap-northeast-1
  memorySize: 512
  stackName: ${self:service}-stack

functions:
  hello:
    name: ${self:custom.functionPrefix}hello
    handler: handler.hello

resources:
  Outputs:
    prefix:
      Value: ${self:custom.functionPrefix}
      Export:
        Name: functionPrefix

通过${cf.us-west-2:stackName.outputKey} 来对其他region中的service的CloudFormation stack的导出属性进行引用.

service: new-service
provider: 
  name: aws
  region: ap-southeast-1
functions:
  hello:
    name: ${cf.ap-northeast-1:another-service-stack.prefix}-hello
    handler: handler.hello

通过CloudFormation stack的导出属性的name对属性值进行引用.

service: new-service
provider: 
  name: aws
  region: ap-southeast-1
  stage: develop
  environment:
    Table:
        'Fn::ImportValue': 'DynamoDbTable-${self:provider.stage}'
  prefix: 'Fn::ImportValue': 'functionPrefix'
functions  
  hello:
    name: ${self:provider.functionPrefix}-hello
    handler: handler.hello
service: another-service
custom:
  functionPrefix: 'my-prefix-'

provider: 
  name: aws
  region: ap-southeast-1
  stage: develop

resources:
  Resources:
    DynamoDbTable:
      Type: 'AWS::DynamoDB::Table'
      ......
    
  Outputs:
    DynamoDbTable:
      Value:
        "Ref": DynamoDbTable
      Export:
        Name: DynamoDbTable-${self:provider.stage}
    prefix:
      Value: ${self:custom.functionPrefix}
      Export:
        Name: functionPrefix

引用 S3 Objects

可以使用${s3:bucketName/key}引入s3的值。

service: new-service
provider: aws
functions:
  hello:
    name: ${s3:myBucket/myKey}-hello
    handler: handler.hello

上述示例中, ${s3:myBucket/myKey}的值会被替换为S3 的myBucket 中myKey 的value值。

引用 SSM 参数库变量

可以使用${ssm:/path/to/param}引入SSM 参数库的值。

service: ${ssm:/path/to/service/id}-service
provider:
  name: aws
functions:
  hello:
    name: ${ssm:/path/to/service/myParam}-hello
    handler: handler.hello

可以使用${ssm:/path/to/secureparam~true}引入加密的SSM 参数库的值。

service: new-service
provider: aws
functions:
  hello:
    name: hello
    handler: handler.hello
custom:
  supersecret: ${ssm:/path/to/secureparam~true}

上述示例中,supersecret的值为解密后的value。

可以使用${ssm:/path/to/stringlistparam~split}可以将SSM 参数库的值分割成array之后再引入。

service: new-service
provider: aws
functions:
  hello:
    name: hello
    handler: handler.hello
custom:
  myArrayVar: ${ssm:/path/to/stringlistparam~split}

可以使用${ ssm.REGION:/path/to/param }引入其他region的SSM 参数库的值。

service: ${ssm.us-west-2:/path/to/service/id}-service
provider:
  name: aws
functions:
  hello:
    name: ${ssm.ap-northeast-1:/path/to/service/myParam}-hello
    handler: handler.hello

引用AWS Secrets Manager中的变量

可以使用ssm语法${ ssm:/aws/reference/secretsmanager/secret_ID_in_Secrets_Manager~true }对WS Secrets Manager中的变量进行引用。

service: new-service
provider: aws
functions:
  hello:
    name: hello
    handler: handler.hello
custom:
  supersecret: ${ssm:/aws/reference/secretsmanager/secret_ID_in_Secrets_Manager~true}

上述示例中,supersecret的值为解密后的value。

被引用的变量可以是字符串,也可以是object,因为AWS Secrets Manager不仅可存储string类型的value,也可以存储object的json。

如果被引用的变量是一个object

{
  "num": 1,
  "str": "secret",
  "arr": [true, false]
}

则引入之后会被解析为如下形式:

service: new-service
provider: aws
functions:
  hello:
    name: hello
    handler: handler.hello
custom:
  supersecret:
    num: 1
    str: secret
    arr:
      - true
      - false

引用其他配置文件中的变量

可以在当前文件中使用引用其他YAML或者JSON文件中定义的变量:

  •  ${file(../myFile.yml):someProperty}
  • ${file(../myFile.json):someProperty}

也可以使用${file(../myCustomFile.yml)}引用整个文件。

引用时需使用被引用文件相对当前文件的路径。

# myCustomFile.yml
globalSchedule: rate(10 minutes)
# serverless.yml
service: new-service
provider: aws
custom: ${file(../myCustomFile.yml)} # You can reference the entire file
functions:
  hello:
    handler: handler.hello
    events:
      - schedule: ${file(../myCustomFile.yml):globalSchedule} # Or you can reference a specific property
  world:
    handler: handler.world
    events:
      - schedule: ${self:custom.globalSchedule} # This would also work in this case

引用JS文件中的变量

可以通过引用js文件中的变量来向配置文件中引入动态数据。

  •  ${file(../myFile.js):someModule}对js文件中的命名导出数据进行引入
  •  ${file(../myFile.js)}对js文件中的未命名导出数据进行引入
// scheduleConfig.js
module.exports.rate = 'rate(10 minutes)';
// config.js
module.exports = serverless => {
  serverless.cli.consoleLog('You can access Serverless config and methods as well!');

  return {
    property1: 'some value',
    property2: 'some other value',
  };
};
# serverless.yml
service: new-service
provider: aws

custom: ${file(../config.js)}

functions:
  hello:
    handler: handler.hello
    events:
      - schedule: ${file(../scheduleConfig.js):rate} # Reference a specific module

引用导出的命名数据的特定属性:

# serverless.yml
service: new-service
provider: aws
functions:
  scheduledFunction:
    handler: handler.scheduledFunction
    events:
      - schedule: ${file(../myCustomFile.js):schedule.ten}
// myCustomFile.js
module.exports.schedule = () => {
  // Code that generates dynamic data
  return {
    ten: 'rate(10 minutes)',
    twenty: 'rate(20 minutes)',
    thirty: 'rate(30 minutes)',
  };
};

如果需要引入动态/异步数据,可以在js文件中导出Promise 。

# serverless.yml
service: new-service
provider: aws
functions:
  scheduledFunction:
    handler: handler.scheduledFunction
    events:
      - schedule: ${file(../myCustomFile.js):promised}
// myCustomFile.js
module.exports.promised = () => {
  // Async code that fetches the rate config...
  return Promise.resolve('rate(10 minutes)');
};

 

// myCustomFile.js
const { STS } = require('aws-sdk');
const sts = new STS();

module.exports.getAccountId = async () => {
  // Checking AWS user details
  const { Account } = await sts.getCallerIdentity().promise();
  return Account;
};
# serverless.yml
service: new-service
provider: aws
custom:
  accountId: ${file(../myCustomFile.js):getAccountId}

多配置文件

将多个配置文件引入到一个配置文件中,可以将配置文件模块化。

resources:
  - Resources:
      ApiGatewayRestApi:
        Type: AWS::ApiGateway::RestApi

  - ${file(resources/first-cf-resources.yml)}
  - ${file(resources/second-cf-resources.yml)}

  - Outputs:
      CognitoUserPoolId:
      Value:
        Ref: CognitoUserPool

需要注意的是每个cloudformation 配置文件都必须以Resources开头。

Resources:
  Type: 'AWS::S3::Bucket'
  Properties:
    BucketName: some-bucket-name

嵌套引用

service: new-service
provider: aws
custom:
  myFlexibleArn: ${env:${opt:stage}_arn}

functions:
  hello:
    handler: handler.hello

Overwriting Variables

Serverless framework 支持多参数引用,对于如下示例,当部署时没有指定任何命令行参数时:

  • myStage会引用self:provider.stage的值
  • myRegiongion会设置为us-west-1
  • myCfnRole会设置为false}
  • myLambdaMemory会设置为1024

Serverless framework 支持指定任意数量的引用参数,参数的来源和类型也可以任意指定。

service: new-service
provider:
  name: aws
  stage: dev
custom:
  myStage: ${opt:stage, self:provider.stage}
  myRegion: ${opt:region, 'us-west-1'}
  myCfnRole: ${opt:role, false}
  myLambdaMemory: ${opt:memory, 1024}

functions:
  hello:
    handler: handler.hello

 

使用自定义的变量引入语法

通过设置provider.variableSyntax property来自定变量引入语法。

以下示例使用 ${{}}代替 ${}。

service: new-service

provider:
  name: aws
  runtime: nodejs12.x
  variableSyntax: "\\${{([ ~:a-zA-Z0-9._@\\'\",\\-\\/\\(\\)]+?)}}" # notice the double quotes for yaml to ignore the escape characters!
#  variableSyntax: "\\${((?!AWS)[ ~:a-zA-Z0-9._@'\",\\-\\/\\(\\)]+?)}" # Use this for allowing CloudFormation Pseudo-Parameters in your serverless.yml -- e.g. ${AWS::Region}. All other Serverless variables work as usual.

custom:
  myStage: ${{opt:stage}}

Pseudo Parameters Reference

参考: AWS Pseudo Parameters

目前支持的类型:

  • AWS::AccountId
    • 返回在其中创建堆栈的账户的 AWS 账户 ID,如 123456789012
  • AWS::NotificationARNs
    • 返回当前堆栈的通知Amazon 资源名称 (ARN) 列表。
  • AWS::NoValue
  • AWS::Partition
    • 返回资源所处的分区。对于标准 AWS 区域,分区是 aws。对于位于其他分区中的资源,则分区是 aws-partitionname。例如,中国(北京和宁夏)区域中的资源的分区为 aws-cn,AWS GovCloud (US-West) 区域中的资源的分区为 aws-us-gov
  • AWS::Region
    • 返回代表包容性资源在其中创建的 AWS 区域的字符串,如 us-west-2
  • AWS::StackId
    • 返回使用 aws cloudformation create-stack 命令指定的堆栈的 ID,如 arn:aws:cloudformation:us-west-2:123456789012:stack/teststack/51af3dc0-da77-11e4-872e-1234567db123
  • AWS::StackName
    • 返回使用 aws cloudformation create-stack 命令指定的堆栈的名称,如 teststack
  • AWS::URLSuffix
Resources:
  - 'Fn::Join':
      - ':'
      - - 'arn:aws:logs'
        - Ref: 'AWS::Region'
        - Ref: 'AWS::AccountId'
        - 'log-group:/aws/lambda/*:*:*'

将string类型的变量转换为boolean类型的变量

在使用SSM variables等作为变量引入源时,boolean类型的变量可能会以string的形式进行返回,如果变量引入的地方需要使用boolean类型,则需要进行转化。

provider:
  tracing:
    apiGateway: ${strToBool(${ssm:API_GW_DEBUG_ENABLED})}

转化规则如下:

${strToBool(true)} => true
${strToBool(false)} => false
${strToBool(0)} => false
${strToBool(1)} => true
${strToBool(2)} => Error
${strToBool(null)} => Error
${strToBool(anything)} => Error

参考

https://www.serverless.com/framework/docs/providers/aws/guide/services/

https://www.serverless.com/framework/docs/providers/aws/guide/functions/

https://docs.aws.amazon.com/zh_cn/lambda/latest/dg/configuration-vpc.html

https://docs.aws.amazon.com/zh_cn/lambda/latest/dg/invocation-async.html#invocation-async-destinations

https://www.serverless.com/framework/docs/providers/aws/guide/events/

https://www.serverless.com/framework/docs/providers/aws/guide/layers/

https://www.serverless.com/framework/docs/providers/aws/guide/resources/

https://www.serverless.com/framework/docs/providers/aws/guide/variables/

https://www.serverless.com/framework/docs/providers/aws/guide/iam/

https://www.serverless.com/framework/docs/providers/aws/guide/serverless.yml/

 类似资料: