如何编写我的云形成更具可重用性而不是重命名资源
How to write my cloud formation more reusable instead of renaming resources
我是 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 次并重命名资源。有没有更好的方法?
我们团队处理这个问题的方式是我们有一个共享模板,用于为我们的每个环境生成堆栈:dev
、staging
和 production
。每个环境之间的逻辑 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 和 Production 共享,所以我有这样创建的存储桶:
Parameters:
EnvironmentName:
Type: String
AllowedValues:
- dev
- staging
- production
Conditions:
ShouldGenerateArtifactBucket: !Equals [!Ref EnvironemntName, dev]
Resources:
ArtifactBucket:
Type: AWS::S3::Bucket
Condition: ShouldGenerateArtifactBucket
只要您的堆栈名称足够独特,您甚至可以将第一个策略与第二个策略结合使用来创建一个存储桶,该存储桶具有足够可预测的名称,以至于一个堆栈可以引用第一个存储桶工件。
让我试着扩展一下情况,以便更好地理解。就云部署而言,10 个资源算不了什么。即使您设法为您的资源起一个很酷的唯一名称,在尝试管理这些大量资源时也无济于事。
此外,逻辑名称很敏感并且受字符和长度限制,因此您很快就会发现您无法正确地命名它们来实现您的需要。当您使用少量资源时,这种方式很有意义,但在适当的时候,资源往往会扩展,因为这样做很容易。
正如@jamie-starke 所建议的,您需要找到其他方法来帮助您跟踪这些资源。在我的团队中,我们使用大量模板参数来驱动堆栈应该做什么。这就是我们尝试帮助跟踪资源的方式,只要值是正确的即可。这很重要,因为我们最近不得不重命名标签值以确保在搜索过程中没有重叠。例如,我们有 Fe-Multi
、FEMulti-BESingle
和 FEMulti-BESingle-BEMulti
这样的名称。当搜索 FE-Multi
时,所有三个值都被命中,因为控制台执行 StartsWith
条件过滤。
- 尽可能为资源建立一个名称,例如使用
!Sub "${AWS::StackName}-SlackBotLambda"
或 !Join
或其他等价物。
- 我们会尽可能使用标签对资源进行注释,同时始终提供名称标签。
我们以有助于模板更具可读性的方式命名模板中的资源。通常一些逻辑名称会出现在 aws 控制台中,因为它们不接受名称或标签,而这是我们目前接受的。对于其余资源,名称大多是装饰性的。资源名称也很敏感并且受字符和长度限制,因此它们无法表达。出于这个原因,我们选择主要通过标签来管理资源。标签没有限制,它们提供了一种用于查询的隐式语言。
了解 CloudFormation 模板有点笨拙并且最终它们依赖于其余 AWS 资源,因此需要复制和试验一些代码片段,尤其是在使用条件时。如果您需要有关此过程的更多信息,请告诉我。
因为我们不想将标签分配复制到每个资源,所以我们确保在堆栈创建期间提供正确的标签。为避免任何错误,我们不希望人们从控制台初始化堆栈,而只能从完全控制重要内容的 PowerShell 脚本初始化堆栈。
我是 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 次并重命名资源。有没有更好的方法?
我们团队处理这个问题的方式是我们有一个共享模板,用于为我们的每个环境生成堆栈:dev
、staging
和 production
。每个环境之间的逻辑 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 和 Production 共享,所以我有这样创建的存储桶:
Parameters:
EnvironmentName:
Type: String
AllowedValues:
- dev
- staging
- production
Conditions:
ShouldGenerateArtifactBucket: !Equals [!Ref EnvironemntName, dev]
Resources:
ArtifactBucket:
Type: AWS::S3::Bucket
Condition: ShouldGenerateArtifactBucket
只要您的堆栈名称足够独特,您甚至可以将第一个策略与第二个策略结合使用来创建一个存储桶,该存储桶具有足够可预测的名称,以至于一个堆栈可以引用第一个存储桶工件。
让我试着扩展一下情况,以便更好地理解。就云部署而言,10 个资源算不了什么。即使您设法为您的资源起一个很酷的唯一名称,在尝试管理这些大量资源时也无济于事。
此外,逻辑名称很敏感并且受字符和长度限制,因此您很快就会发现您无法正确地命名它们来实现您的需要。当您使用少量资源时,这种方式很有意义,但在适当的时候,资源往往会扩展,因为这样做很容易。
正如@jamie-starke 所建议的,您需要找到其他方法来帮助您跟踪这些资源。在我的团队中,我们使用大量模板参数来驱动堆栈应该做什么。这就是我们尝试帮助跟踪资源的方式,只要值是正确的即可。这很重要,因为我们最近不得不重命名标签值以确保在搜索过程中没有重叠。例如,我们有 Fe-Multi
、FEMulti-BESingle
和 FEMulti-BESingle-BEMulti
这样的名称。当搜索 FE-Multi
时,所有三个值都被命中,因为控制台执行 StartsWith
条件过滤。
- 尽可能为资源建立一个名称,例如使用
!Sub "${AWS::StackName}-SlackBotLambda"
或!Join
或其他等价物。 - 我们会尽可能使用标签对资源进行注释,同时始终提供名称标签。
我们以有助于模板更具可读性的方式命名模板中的资源。通常一些逻辑名称会出现在 aws 控制台中,因为它们不接受名称或标签,而这是我们目前接受的。对于其余资源,名称大多是装饰性的。资源名称也很敏感并且受字符和长度限制,因此它们无法表达。出于这个原因,我们选择主要通过标签来管理资源。标签没有限制,它们提供了一种用于查询的隐式语言。
了解 CloudFormation 模板有点笨拙并且最终它们依赖于其余 AWS 资源,因此需要复制和试验一些代码片段,尤其是在使用条件时。如果您需要有关此过程的更多信息,请告诉我。
因为我们不想将标签分配复制到每个资源,所以我们确保在堆栈创建期间提供正确的标签。为避免任何错误,我们不希望人们从控制台初始化堆栈,而只能从完全控制重要内容的 PowerShell 脚本初始化堆栈。