如何编写我的云形成更可重用而不是重命名资源

时间:2017-09-11 21:21:17

标签: amazon-web-services amazon-cloudformation aws-opsworks

我是cloudformation的新手,我正在为我的项目的基础架构编写一些cfn代码。但是当我编写代码时,有一个问题一直困扰着我。我们假设我有以下资源要创建:

Resources: 
MyEC2Instance: 
  Type: "AWS::EC2::Instance"
  Properties: 
    ImageId: "ami-79fd7eee"
    KeyName: "testkey"
    BlockDeviceMappings: 
      - DeviceName: "/dev/sdm"
        Ebs: 
          VolumeType: "io1"
          Iops: "200"
          DeleteOnTermination: "false"
          VolumeSize: "20"
      - DeviceName: "/dev/sdk"
        NoDevice: {}

如您所见,我正在创建一个名为MyEC2Instance的资源。现在假设我有另一个名为stg的环境,它与上面完全相同,所以一个简单的方法是使用上面的代码和不同的堆栈名称,但我被告知我需要重命名我的资源名称,如下所示:

Resources: 
MyEC2InstanceStg1: 
  Type: "AWS::EC2::Instance"
  Properties: 
    ImageId: "ami-79fd7eee"
    KeyName: "testkey"
    BlockDeviceMappings: 
      - DeviceName: "/dev/sdm"
        Ebs: 
          VolumeType: "io1"
          Iops: "200"
          DeleteOnTermination: "false"
          VolumeSize: "20"
      - DeviceName: "/dev/sdk"
        NoDevice: {}

但对我而言,这看起来并不专业,因为如果我有10个环境,这意味着我需要复制我的代码10次并重命名资源。还有更好的方法吗?

2 个答案:

答案 0 :(得分:4)

我们在团队中处理此问题的方式是,我们有一个共享模板,用于为每个环境生成堆栈:devstagingproduction。每个环境之间的逻辑ID将相同,但生成的物理ID将不同。

关于这一点的一个问题是,如果您在同一帐户中拥有不同的环境堆栈,则必须确保任何Name属性都是唯一的。如果他们不是必需的,请不要设置它们,CloudFormation将为您生成它们。在需要它们的情况下,我发现{"Fn::Sub": "${AWS::StackName}-SomeName"}对此有帮助,因为它使每个物理资源名称相对于它们的环境堆栈。例如,使用CodeBuild,需要项目名称,因此我们执行以下操作:

Resources:
  Project:
    Type: AWS::CodeBuild::Project
    Properties:
      Name: !Sub "${AWS::StackName}-SlackBotLambda"
      ...

因此,如果我在我的dev堆栈上,这会使CodeBuild项目名为dev-SlackBotLambda

我们采用的另一种策略是传入EnvironmentName参数,这样我们就可以拥有在一个环境中而不是在另一个环境中创建的资源。例如,我通常希望在Dev中创建构建工件,然后与Staging and Production共享,因此我创建了这样的桶:

Parameters:
  EnvironmentName:
    Type: String
    AllowedValues:
      - dev
      - staging
      - production

  Conditions:
    ShouldGenerateArtifactBucket: !Equals [!Ref EnvironemntName, dev]

  Resources:
    ArtifactBucket:
      Type: AWS::S3::Bucket
      Condition: ShouldGenerateArtifactBucket

只要您的堆栈名称足够独特,您甚至可以使用第一个策略和第二个策略来创建一个具有足够可预测名称的存储桶,以便一个堆栈可以引用第一个存储桶工件。

答案 1 :(得分:1)

让我尝试扩大情况以便更好地理解。就云部署而言,10资源都不算什么。即使您设法为您的资源提供一个很酷的独特名称,在尝试管理这些大量资源时也不会有太大帮助。

此外,逻辑名称是敏感的,仅限于字符和长度,因此您很快就会发现,您无法正确命名它们以达到您的需要。当您使用少量资源时,这种情况很有意义,但在适当的时候,资源往往会扩展,因为它很容易实现。

正如@ jamie-starke建议的那样,您需要找到其他方法来帮助您跟踪这些资源。在我的团队中,我们使用了很多模板参数来驱动堆栈应该做的事情。这就是我们尝试帮助跟踪资源的方式,只要值正确无误即可。这很重要,因为我们最近不得不重命名标记值以确保在搜索过程中没有重叠。例如,我们有Fe-MultiFEMulti-BESingleFEMulti-BESingle-BEMulti等名称。当搜索FE-Multi所有三个值都被命中时,因为控制台执行StartsWith条件过滤。

  • 尽可能使用例如资源建立资源名称!Sub "${AWS::StackName}-SlackBotLambda"!Join或其他等同物。
  • 如果可能的话,我们使用标签注释资源,同时始终提供名称标签。

我们以帮助模板更具可读性的方式命名模板中的资源。通常一些逻辑名称出现在aws控制台中,因为它们不接受名称或标签,这是我们目前接受的。对于其他资源,名称大多是装饰性的。资源名称也很敏感,并且仅限于字符和长度,因此它们无法表达。出于这个原因,我们选择主要通过标签来管理资源。标签没有限制,它们提供了一种隐含的查询语言。

了解到CloudFormation模板有点尴尬,并且最终它们依赖于其他AWS资源,因此需要复制和实验某些代码片段,尤其是在使用条件时。如果您需要有关此流程的更多信息,请与我们联系。

因为我们不想将标记分配复制到每个资源,所以我们确保在创建堆栈时提供正确的标记。为了避免任何错误,我们不希望人们从控制台初始化堆栈,而只能从完全控制重要内容的PowerShell脚本中初始化。