【问题标题】:How can I put condition in serverless.yml file?如何将条件放入 serverless.yml 文件中?
【发布时间】:2021-09-16 07:23:04
【问题描述】:

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

provider:
  name: aws
  runtime: nodejs12.x

...

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

【问题讨论】:

    标签: amazon-web-services serverless-framework


    【解决方案1】:

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

    控制条件的变量

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

    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
    

    Weird Conditional Hacks(如果您决定实施它们,请记录使用情况)

    有条件地部署大量资源

    使用无服务器通过环境变量设置的字符串选择性地部署整个资源文件。

    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

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

    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)}}
    

    【讨论】:

      【解决方案2】:

      您可以查看以下答案: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
      

      【讨论】:

        【解决方案3】:

        或者,有一个Serverless Plugin Ifelse

        添加插件:

        plugins:  
          - serverless-plugin-ifelse
        

        然后添加你的条件:

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

        查看更多信息Serveless plugin if-else

        【讨论】:

          猜你喜欢
          • 2019-03-14
          • 1970-01-01
          • 2021-08-01
          • 2021-07-29
          • 1970-01-01
          • 2019-03-10
          • 2020-08-30
          • 1970-01-01
          • 2020-07-11
          相关资源
          最近更新 更多