Cloudformation 和参数存储:如何为环境选择参数

问题描述 投票:0回答:6

我想从 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'
amazon-web-services aws-cloudformation amazon-systems-manager
6个回答
8
投票

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

模板:

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
指向),则应为参数
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/BucketNameSuffix
然后我可以更新
 prod
不传递任何参数的堆栈。


3
投票

您可以使用动态引用

使用 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}}'

0
投票

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

这是一些伪代码。

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

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

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

希望这有帮助。

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


0
投票

我喜欢 Fn::Sub,它更干净且易于阅读。

!Sub "/database/${Environment}/url"

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 参数存储中查找。如下:

    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:/我的/值: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


0
投票

扩展@jbasko的示例,您还可以将键值参数映射放在单独的JSON文件中,并为每个环境使用不同的JSON文件。

云形成文件看起来是一样的:

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}

然后你就可以为每个环境拥有一个 JSON 文件。例如,生产参数文件如下所示:

[
  {
    "ParameterKey": "BucketNameSuffix",
    "ParameterValue": "/example/prod/BucketNameSuffix"
  }
]

生产环境的部署如下所示:

aws cloudformation update-stack --stack-name example-prod \
--template-body file://./example-stack.yml \
--parameters file://./production-parameters.json

因此,您需要做的就是每次部署到环境时传递正确的文件。

© www.soinside.com 2019 - 2024. All rights reserved.