10

我想从 CloudFormation 模板中的参数存储中读取我的数据库的 URL。对于单个 URL,这很容易,但我不知道如何在不同的环境中更改 URL。

我有四个环境(开发、集成、预生产和生产),它们的详细信息存储在 Parameter Store 的四个不同路径中:

/database/dev/url
/database/int/url
/database/ppe/url
/database/prod/url

我现在想在通过 CloudFormation 部署时选择正确的数据库 URL。我怎样才能做到这一点?

Parameters:
  Environment:
    Type: String
    Default: dev
    AllowedValues:
      - dev
      - int
      - ppe
      - prod
  DatabaseUrl:
    Type: 'AWS::SSM::Parameter::Value<String>'
    # Obviously the '+' operator here won't work - so what do I do?
    Default: '/database/' + Environment + '/url'
4

5 回答 5

6

此功能并不像人们希望的那样整洁。您必须实际传递要从参数存储中查找的每个参数的名称/路径。

模板:

AWSTemplateFormatVersion: 2010-09-09

Description: Example

Parameters:

  BucketNameSuffix:
    Type: AWS::SSM::Parameter::Value<String>
    Default: /example/dev/BucketNameSuffix

Resources:

  Bucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub parameter-store-example-${BucketNameSuffix}

如果您不向模板传递任何参数,BucketNameSuffix将使用存储在/example/dev/BucketNameSuffix. 如果你想使用一个prod值(由 指向/example/prod/BucketNameSuffix),那么你应该为 parameter 指定值BucketNameSuffix,但你应该传递要使用的参数的替代名称,而不是传递实际值,所以你会传递/example/prod/BucketNameSuffix.

aws cloudformation update-stack --stack-name example-dev \
--template-body file://./example-stack.yml

aws cloudformation update-stack --stack-name example-prod \
--template-body file://./example-stack.yml \
--parameters ParameterKey=BucketNameSuffix,ParameterValue=/example/prod/BucketNameSuffix

关于此的不太好的 AWS 博客文章:https ://aws.amazon.com/blogs/mt/integrating-aws-cloudformation-with-aws-systems-manager-parameter-store/

因为传递数百万个无意义的参数似乎很愚蠢,我实际上可能会生成一个特定于环境的模板并Default:在生成的模板中设置正确的prod环境,然后我可以在不传递任何参数的情况下更新Default堆栈。/example/prod/BucketNameSuffixprod

于 2018-12-25T20:57:33.097 回答
0

您可以在此处使用Fn::Join

这是一些伪代码。

您必须将 Environment 作为参数,您已经在这样做了。

在需要 DatabaseUrl 的资源中创建所需的字符串。

Resources :
  Instance :
    Type : 'AWS::Some::Resource'
    Properties :
       DatabaseURL : !Join [ "", [ "/database/", !Ref "Environment" , "/url ] ]

希望这可以帮助。

注意:您不能使用某些计算逻辑为参数动态分配值。定义参数的所有值都应作为输入给出。

于 2018-02-09T14:32:09.623 回答
0

我陷入了同样的问题,以下是我的发现:

  1. 我们可以在从 CloudFormation 写入 SSM 参数存储时组合值和描述,如下所示:

    LambdaARN:
      Type: AWS::SSM::Parameter
      Properties:
        Type: String
        Description: !Sub "Lambda ARN from ${AWS::StackName}"
        Name: !Sub "/secure/${InstallationId}/${AWS::StackName}/lambda-function-arn"
        Value: !GetAtt LambdaFunction.Arn
    
  2. 我们无法在 SSM Parameter Store 中编写值/默认值来查找。如下所示:

    Parameters:
    ...
      LambdaARN:
        Type: Type: AWS::SSM::Parameter::Value<String>
        Value: !Sub "/secure/${InstallationId}/teststack/lambda-function-arn"
    

根据 AWS 文档 [1],这是不允许的。两个(子/加入)函数都不起作用。以下是我得到的错误:

调用 CreateChangeSet 操作时发生错误 (ValidationError):模板格式错误:每个默认成员都必须是字符串。

  1. 在创建堆栈时组合和传递值可以这样完成:

    Parameters:
    ...
      LambdaARN:
        Type: Type: AWS::SSM::Parameter::Value<String>
    ....
    
    $ aws cloudformation deploy --template-file cfn.yml --stack-name mystack  --parameter-overrides 'LambdaARN=/secure/devtest/teststack/lambda_function-arn'
    
  2. 如果在将值放入 Parameter Store 时添加自定义标签,它将覆盖 CFN 添加的默认标签。

默认标签:

- aws:cloudformation:stack-id
- aws:cloudformation:stack-name
- aws:cloudformation:logical-id
  1. 每次我们更新参数存储中的值时,它都会创建一个新版本,这在我们使用DynamicResolvers时很有用,这可以作为问题中问题的解决方案,例如

{{ 解决:ssm:/my/value:1}}

最后一个字段是版本。不同的版本可以指向不同的环境。

  1. 我们正在使用带有参数的版本,并向它们添加标签[2],这不能通过 CFN[3] 完成,只能通过 CLI 或 AWS 控制台进行。这是 AWS 处理多个环境的方式。

[1] https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference.html

[2] https://docs.aws.amazon.com/systems-manager/latest/userguide/sysman-paramstore-labels.html

[3] https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ssm-parameter.html

于 2020-06-29T08:56:01.270 回答
0

我喜欢Fn::Sub,它更简洁易读。

!Sub "/database/${Environment}/url"
于 2018-02-15T17:36:54.260 回答
0

您可以使用动态引用使用存储在 AWS Systems Manager Parameter Store 中的参数填充 CloudFormation 模板

在这个人为的示例中,我们使用和替换环境进行了两次resolve:ssm查找!Join!Sub

AWSTemplateFormatVersion: 2010-09-09
Parameters:
  Environment:
    Type: String
    Default: prod
    AllowedValues:
      - prod
      - staging
Resources:
  TaskDefinition:
    Type: AWS::ECS::TaskDefinition
    Properties:
      ContainerDefinitions:
        Image: !Join
          - ''
          -   - 'docker.io/bitnami/redis@'
              - !Sub '{{resolve:ssm:/app/${Environment}/digest-sha/redis}}'
        Environment:
          - Name: DB_HOST
            Value: !Sub '{{resolve:ssm:/app/${Environment}/db-host}}'
于 2022-02-03T21:39:39.437 回答