在无服务器 yaml 配置中使用 fn::split 不起作用

Posted

技术标签:

【中文标题】在无服务器 yaml 配置中使用 fn::split 不起作用【英文标题】:Using fn::split in Serverless yaml configuration not working 【发布时间】:2021-04-12 11:42:54 【问题描述】:

我正在使用无服务器框架在 AWS 上部署 API。我的serverless.yml 文件中有以下内容:

custom:
  vpcSettings:
    private:
      securityGroupIds:
        private:
          fn::split:
            delimiter: ','
            value: $env:VPC_SG_ID

VPC_SG_ID 包含以下字符串:sg-1111111111,sg-222222222,sg-3333333333

但是,在部署应用程序时,我收到以下错误: An error occurred: MyLambdaFunction - Value of property SecurityGroupIds must be of type List of String.

如果我对 SG 列表进行硬编码,它可以正常工作:

custom:
  vpcSettings:
    private:
      securityGroupIds:
        private:
          - "sg-1111111111"
          - "sg-2222222222"
          - "sg-3333333333"

为什么 fn::split 函数没有返回字符串列表?

编辑:

以下配置导致同样的错误

custom:
  vpcSettings:
    private:
      securityGroupIds:
        private:
          Fn::Split:
            - ','
            - $env:VPC_SG_ID

【问题讨论】:

以下解决方案是否使用Split from parameter work? @cramix 你是怎么解决这个问题的? 【参考方案1】:

如果安全组作为输入参数添加到模板

Parameters:
  VPCSGID:
    Type: String
    Description: Comma separated Security Groups

安全组可以用!Split 分割成

SecurityGroupIds: !Split [",", !Ref VPCSGID]

可以用Fn:Split分割成

SecurityGroupIds:  "Fn::Split": [",", !Ref VPCSGID] 

sam deploy 的参数可以传递为

sam deploy --parameter-overrides 'ParameterKey=VPCSGID,ParameterValue=sg-011111,sg-222222'

【讨论】:

问题是关于“无服务器框架”而不是“SAM”【参考方案2】:

我正在尝试实现相同的目标,但我很确定您不能在 serverless.yml 中使用 CloudFormation 函数 (Fn::Split)。

替代解决方案 1

通过环境变量传递 YAML 列表/数组对于无服务器来说似乎是不可能的,因为我们无法编写代码来解析来自环境变量的字符串。也许你可以写一个无服务器插件,但我还没有研究过。

我假设您需要能够传递可变长度和任意值的列表,因此以下解决方案可能不适合您。

如果你有已知的值,你可以保留列表in serverless.yml 并选择一个带有 env var 的列表:

custom:
  sgLists:
    list1:
      - sg-11
      - sg-22
    list2:
      - sg-33
      - sg-44
  vpcSettings:
    private:
      securityGroupIds:
        private: $self:custom.sgLists.$env:LIST_SELECTOR

...然后你选择一个列表:

LIST_SELECTOR=list1 sls print
LIST_SELECTOR=list2 sls print

如果您需要任意值,并且您的列表不会太长,那么您可以变得非常 hacky 并将每个列表项设置为 env var:

custom:
  sgLists:
    twoItems:
      - $env:SG1
      - $env:SG2
    threeItems:
      - $env:SG1
      - $env:SG2
      - $env:SG3
  vpcSettings:
    private:
      securityGroupIds:
        private: $self:custom.sgLists.$env:LIST_SELECTOR

..并将所有内容作为环境变量提供:

LIST_SELECTOR=twoItems SG1=sg-11 SG2=sg-22 sls print
LIST_SELECTOR=threeItems SG1=sg-11 SG2=sg-22 SG3-33 sls print

替代方案 2

您还可以利用无服务器功能来reference properties in other files。您可以创建一个小的 YAML 文件(版本控制会忽略该文件):

cd `dirname "$0"`
cat <<EOF > ../sgConfig.yml
groups:
  - sg-11
  - sg-22
EOF

...然后在您的serverless.yml 中引用该文件:

custom:
  vpcSettings:
    private:
      securityGroupIds:
        private: $file(./sgConfig.yml):groups

解释错误信息

我认为您的错误消息是指您在需要 YAML 列表/数组时将 YAML 对象/字典传递到 private 的事实。关键是这与 YAML 语法有关。 Fn::Split 函数是 specific to AWS CloudFormation 的东西,我猜这个函数的“执行”发生在 AWS 基础设施中。

我们可以通过更改您的代码来提供一个列表来测试这个理论:

        private:
          - fn::split: # add the "-" for a list
            delimiter: ','

...然后你会看到类似的错误

Configuration error at 'custom.vpcSettings.private.securityGroupIds.private[0]': should be string

这意味着我们修复了之前的错误,但现在我们遇到了同样的问题,但降了一级,因为 fn::split: 是一个 YAML 对象/字典。您还可以添加另一个列表项,例如:

        private:
          - blah # add this line
          - fn::split:
            delimiter: ','

..您将看到错误消息更改为引用索引[1]。要证明 fn::split 值不特殊,请将其更改为其他值,例如:

        private:
          - blah
          - asdf:  # change this line
            delimiter: ','

...您会看到错误消息没有改变。这是因为 Serverless 不关心 CloudFormation 函数,它只是检查 YAML 模式匹配。

【讨论】:

以上是关于在无服务器 yaml 配置中使用 fn::split 不起作用的主要内容,如果未能解决你的问题,请参考以下文章

在无服务器框架中创建可用于 Lambda 函数的 RDS 实例

如何在无服务器中使用带有 ses 的 vpc 端点

如何在 cloudformation yaml 中配置路由规则?

如何使用 spring boot + .yaml 创建配置文件?

如何使用 spring boot + .yaml 创建配置文件?

如何在 Silex 框架中使用 YAML 配置文件