1

我正在使用 CloudFormation 创建一个 REST API。在另一个 CloudFormation 堆栈中,我希望能够访问该 CloudFormation 脚本的输出部分(调用 URL)中的值。

这可能吗,如果可以,怎么办?

4

1 回答 1

0

您可以导出您的输出。导出使它们可供其他堆栈访问。

来自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文件,可以部署为两个独立的堆栈,但现在它们相互依赖。如果您在删除堆栈之前尝试删除MyApiAPI 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约定替换 - 我必须执行导入。

我在我的模板中混合使用了这两种方法——你会发现在积累经验时使用一种方法而不是另一种方法是有意义的。

于 2021-08-10T02:29:45.713 回答