如何将条件放入 serverless.yml 文件?

How can I put condition in serverless.yml file?

我正在使用 serverless 框架来部署 api 网关。我不想在 Serverless 的每个阶段都应用 VPC。有没有办法根据 stage 名称添加以下配置?

provider:
  name: aws
  runtime: nodejs12.x

...

endpointType: PRIVATE
vpcEndpointIds:
    -  'Fn::ImportValue': 'api-gateway-endpoint'
resourcePolicy:
    - Effect: Deny
...

您可以查看以下答案:Conditional serverless.yml based on stage?

因此,您会得到如下内容:

resources:
    Conditions:
        IsProd:
          Fn::Equals:
            - ${opt:stage}
            - prod  

    Resources:
        SomeIAMRole:
            Type: AWS::IAM::Role
            Condition: IsProd
            Properties:
                etc
                etc

在 serverless.yml 中有几种方法可以进行条件部署,有些方法比其他方法更脆弱,每种方法都有 pros/cons 但这里是我收集的方法列表:

控制条件的变量

注意: 我们使用自定义正则表达式变量语法将无服务器变量与 cloudformation 变量语法分开。以下所有代码段都使用此修改后的语法:

provider:
  name: aws
  # Changes serverless variable to ${{}} double curly braces
  variableSyntax: "\${{([ ~:a-zA-Z0-9._\'\",\-\/\(\)]+?)}}"

Serverless Custom Variables

custom:
  scheduleEnabled:
    dev: true
    stage: true
    prod: true

# Then In lambda function declaration
    events:
      - schedule:
          name: MyScheduleName
          description: SomeDescription
          rate: cron(0/5 * * * ? *)
          # Use custom variable and the serverless `stage` supplied 
          # via your deployment command to choose whether this feature is enabled
          enabled: ${{self:custom.scheduleEnabled.${{self:provider.stage}}}} 
          input: {"_keepwarm": true}

使用条件运算

设置 CloudFormation 条件

resources:
  - Conditions:
      # True if they are equal ==
      MyCondition: [!Equals ["${{env:SOMETHING}}","SOME_STRING"]]
      # True if they are not equal !=
      MyConditionTwo: !Not [!Equals ["${{env:SOMETHING_ELSE}}","SOME_OTHER_STRING"]]
      # Using a custom serverless variable
      IsProd: [!Equals ["${{self:provider.stage}}","prod"]]

使用 Cloudformation 条件

如果你的条件有两个选项,你可以写成:

# If true choose X, if False choose Y
Source:
  Type: !If
    - MyCondition # Conditional Name
    - GITHUB # If condition is true
    - GITHUB_ENTERPRISE # if condition is false

如果你的条件是你想打开或关闭的东西,你可以把它写成:

# If True do nothing, If False choose X
MyCodebuildSetup:
  Type: "AWS::CodeBuild::Project"
  VpcConfig: !If
    - MyCondition # Condition Name
    - !Ref AWS::NoValue # If True, AWS will not attach a VPC Config
    - VpcId: <My_VPC_ID> # If False, Use this VPC Config
      Subnets:
        - <my_VPC_Subnet>
      SecurityGroupIds:
        - <my_VPC_security_group

奇怪的条件黑客(如果您决定实施它们,请记录使用情况)

有条件部署大系列资源

使用 Serverless 使用通过环境变量设置的字符串有选择地部署整个资源文件。

resources:
  - ${{file(some_dir/conditional_file_${{env:MY_CONDITION}}.yml)}}

这也是一种通过条件来切换部署许多资源的方法。

conditional_file_A.yaml 可以包含您切换部署的所有资源,而 conditional_file_B.yaml 可以包含一个空的资源列表(如果您不希望来自无服务器的“找不到文件”警告:

Resources:

在将发送到 cloudformation(参数存储文件等)的 buildspec.yml 文件或 .json 文件中使用无服务器变量

如果您想有条件地修改将作为某些 CloudFormation 密钥的值发送的 .json 或 .yml 文件(例如为参数存储部署 .json 文件,或为 CodePipeline 提交 buildspec.yml 个文件),您实际上不能在这些外部文件中使用 ${} 无服务器语法。这是因为 serverless gets confused with it's own method of calling Key/Values from external files.

为了在这些文件中使用无服务器变量,您可以将它们扩展为 .txt,只要实际文件的格式正确。json 或 .yml

Source:
  Type: CODEPIPELINE
  # This file can't have any serverless variables in it
  BuildSpec: ${{file(my_buildspec_file.yml)}}
Source:
  Type: CODEPIPELINE
  # This file CAN have serverless variables because it is 
  # interpreted by serverless as a .txt, the variables
  # are resolved and then it is sent to cloudformation as a string anyway
  BuildSpec: ${{file(my_buildspec_file_yaml_formatted.txt)}}

或者,有一个 Serverless Plugin Ifelse

添加插件:

plugins:  
  - serverless-plugin-ifelse

然后添加您的条件:

custom:
.....
....

  serverlessIfElse:
    - If: '"${opt:stage}" == "production"'    
      Set:
        functions.helloWorld.cors: true

查看更多信息Serveless plugin if-else