我正在使用 CloudFormation 创建一个 REST API。在另一个 CloudFormation 堆栈中,我希望能够访问该 CloudFormation 脚本的输出部分(调用 URL)中的值。
这可能吗,如果可以,怎么办?
我正在使用 CloudFormation 创建一个 REST API。在另一个 CloudFormation 堆栈中,我希望能够访问该 CloudFormation 脚本的输出部分(调用 URL)中的值。
这可能吗,如果可以,怎么办?
您可以导出您的输出。导出使它们可供其他堆栈访问。
来自AWS 文档:
要导出堆栈的输出值,请使用堆栈模板的输出部分中的导出字段。要导入这些值,请在其他堆栈的模板中使用 Fn::ImportValue 函数
以下导出 API 网关 ID。
Description: API for interacting with API resources
Parameters:
TargetEnvironment:
Description: 'Examples can be dev, test or prod'
Type: 'String'
ProductName:
Description: 'Represents the name of the product you want to call the deployment'
Type: 'String'
Resources:
MyApi:
Type: AWS::ApiGateway::RestApi
Properties:
Name: !Sub '${ProductName}-${TargetEnvironment}-apigw-primaryapi'
Outputs:
MyApiId:
Description: 'Id of the API'
Value: !Ref MyApi
Export:
Name: !Sub '${ProductName}-${TargetEnvironment}-apigw-primaryapi'
MyApiRootResourceId:
Description: 'Id of the root resource on the API'
Value: !GetAtt MyApi.RootResourceId
Export:
Name: !Sub '${ProductName}-${TargetEnvironment}-apigw-primaryapirootresource'
输出部分是这里的Export
重要部分。如果您提供导出,则其他堆栈可以从中使用。
现在,在另一个文件中,我可以MyApiId
使用Fn::Import
内部函数导入该值,导入导出的名称。我还可以导入它的根资源并在创建子 API 资源时使用这两个值。
来自AWS 文档:
内部函数 Fn::ImportValue 返回另一个堆栈导出的输出值。您通常使用此函数来创建跨堆栈引用。
Description: Resource endpoints for interacting with the API
Parameters:
TargetEnvironment:
Description: 'Examples can be dev, test or prod'
Type: 'String'
ProductName:
Description: 'Represents the name of the product you want to call the deployment'
Type: 'String'
Resources:
MyResource:
Type: AWS::ApiGateway::Resource
Properties:
ParentId: {'Fn::ImportValue': !Sub '${ProductName}-${TargetEnvironment}-apigw-primaryapirootresource' }
PathPart: foobar
RestApiId: {'Fn::ImportValue': !Sub '${ProductName}-${TargetEnvironment}-apigw-primaryapi' }
这是两个完全不同的.yaml文件,可以部署为两个独立的堆栈,但现在它们相互依赖。如果您在删除堆栈之前尝试删除MyApi
API Gateway 堆栈MyResource
,CloudFormation 删除操作将失败。您必须先删除依赖项。
要记住的一件事是,在某些情况下,您可能希望能够灵活地删除根资源而不用担心依赖关系。在某些情况下,删除操作可以在没有任何副作用的情况下完成。例如,删除 SNS 主题不会破坏 Lambda - 它会阻止它运行。没有理由仅仅为了重新部署新的 SNS 主题而删除 Lambda。在那种情况下,我使用命名约定并以这种方式将事物联系在一起,而不是使用导出。例如 - 以上AWS::ApiGateway::Resource
可以基于命名约定绑定到特定于环境的 API 网关。
Parameters:
TargetEnvironment:
Description: 'Examples can be dev, test or prod'
Type: 'String'
ProductName:
Description: 'Represents the name of the product you want to call the deployment'
Type: 'String'
Resources:
MyResource:
Type: AWS::ApiGateway::Resource
Properties:
ParentId: {'Fn::ImportValue': !Sub '${ProductName}-${TargetEnvironment}-apigw-primaryapirootresource' }
PathPart: foobar
RestApiId: !Sub '${ProductName}-${TargetEnvironment}-apigw-primaryapi'
有了这个,只要资源的后半部分在所有环境中命名相同,就无需担心导出/导入。环境可以通过TargetEnvironment
参数更改,因此可以在 dev、test 和 prod 中重复使用。
对这种方法的一个警告是,命名约定仅适用于您想要访问可以通过名称引用的内容时。如果您需要一个属性,例如RootResource
本例中的 ,或者 EC2 大小、EBS 卷大小等,那么您不能只使用命名约定。您需要导出值并导入它。在上面的示例中,我可以用RestApiId
命名约定替换导入用法,但我不能用ParentId
约定替换 - 我必须执行导入。
我在我的模板中混合使用了这两种方法——你会发现在积累经验时使用一种方法而不是另一种方法是有意义的。