<AWS CloudFormation> 如何从外部脚本获取和使用 return 值?

<AWS CloudFormation> How to get and use return values from external script?

我正在尝试使用 CloudFormation 自动创建资源。在以下设置中,我试图将负载平衡目标组的创建从主脚本分解为一个单独的脚本。我知道我们可以通过“转换”部分引用外部脚本,但主脚本流程需要创建的目标组的 ARN 才能继续。我可以知道是否有办法从外部脚本传回值吗?谢谢

(Create_Cluster.yaml) 主脚本

    AWSTemplateFormatVersion: 2010-09-09
    Description: Create ECS cluster, task definition and service

    Transform:
      Name: 'AWS::Include'
      Parameters:
        Location: s3://MyAmazonS3BucketName/Create_Target_Group.yaml

    Resources:
      TestECSCluster:
        Type: 'AWS::ECS::Cluster'
        Properties: {}

      ECSTaskExecutionRole:
        Type: 'AWS::IAM::Role'
        Properties:
          AssumeRolePolicyDocument:
            Version: 2012-10-17
            Statement:
              - Sid: ''
                Effect: Allow
                Principal:
                  Service: ecs-tasks.amazonaws.com
                Action: 'sts:AssumeRole'
          ManagedPolicyArns:
            - 'arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy'

      PostCodeECSTaskDefinition:
        Type: 'AWS::ECS::TaskDefinition'
        Properties:
          ExecutionRoleArn: !GetAtt 
            - ECSTaskExecutionRole
            - Arn
          ContainerDefinitions:
            - Name: PostCode
              Image: 'nginxdemos/hello:latest'
              Essential: true
              PortMappings:
                - HostPort: 80
                  Protocol: tcp
                  ContainerPort: 80
          RequiresCompatibilities:
            - FARGATE
          NetworkMode: awsvpc
          Cpu: '256'
          Memory: '512'
          Family: ecs-demo

      PostCodeECSService:
        Type: 'AWS::ECS::Service'
        Properties:
          Cluster: TestCluster
          DeploymentController: 
            Type: CODE_DEPLOY
          DesiredCount: 1
          HealthCheckGracePeriodSeconds: 300
          LaunchType: FARGATE
          LoadBalancers: 
            - ContainerName: PostCode
              ContainerPort: 80
              TargetGroupArn: <HOW TO GET THE ARN OF THE TARGET GROUP CREATED IN EXTERNAL SCRIPT?>
          SchedulingStrategy: REPLICA
          ServiceName: TestService
          TaskDefinition: PostCodeECSTaskDefinition

(Create_Target.yaml) 创建目标组的脚本

    AWSTemplateFormatVersion: 2010-09-09
    Description: Create target group
    Resources:
      TestTargetGroup01:
        Type: AWS::ElasticLoadBalancingV2::TargetGroup
        Properties:
          Name: TestTargetGroup01
          Protocol: HTTP
          Port: 80
          TargetType: instance
          VpcId: vpc-b830c6c5

================================
更新(2021 年 4 月 6 日)
==============================

经过一些研究,我让它工作了。您需要将要外部化的部分放在单独的堆栈(嵌套堆栈)中,然后在主堆栈中调用它。在嵌套堆栈中,向 return 任意值添加一个“输出”部分;在主堆栈中,使用“GetAtt”函数从嵌套堆栈中获取 return 值。

      ...
      TargetGroupArn: !GetAtt
        - TargetGroup01Stack
        - Outputs.TargetGroupARN
      ...

这里我使用了嵌套堆栈而不是转换部分,因为它可以有自己的“输出”部分。
参考:
https://aws.amazon.com/premiumsupport/knowledge-center/cloudformation-nested-stacks-values/

这里讨论嵌套堆栈和转换之间的区别:
https://acloud.guru/forums/aws-cda-2018/discussion/-LYOIsyqQdHckIbop4XP/difference_between_nested_stac#:~:text=2%20Answers&text=Nested%20stacks%20create%20a%20distinctly,master%20template's%20parameters%2C%20conditions%20etc

(Create_ECS_Cluster.yaml) 创建主栈,并调用里面的嵌套栈作为步骤

    AWSTemplateFormatVersion: '2010-09-09'
    Description: Create ECS cluster, task definition and service
    Resources:
      TargetGroup01Stack:
        Type: 'AWS::CloudFormation::Stack'
        Properties:
          TemplateURL: 'https://mys3bucket.s3.amazonaws.com/Create_Target_Group.yaml'

      TestSecurityGroup:
        Type: 'AWS::EC2::SecurityGroup'
        Properties:
          GroupDescription: Security group for ec2 access
          VpcId: vpc-b830c6c5
          SecurityGroupIngress:
            - IpProtocol: tcp
              FromPort: 80
              ToPort: 80
              CidrIp: 0.0.0.0/0
            - IpProtocol: tcp
              FromPort: 8080
              ToPort: 8080
              CidrIp: 0.0.0.0/0
            - IpProtocol: tcp
              FromPort: 22
              ToPort: 22
              CidrIp: 0.0.0.0/0

      TestALB:
        Type: 'AWS::ElasticLoadBalancingV2::LoadBalancer'
        Properties:
          Scheme: internet-facing
          SecurityGroups:
            - !Ref TestSecurityGroup
          Subnets:
            - subnet-e80ed48e
            - subnet-7c3ba772
          Tags:
            - Key: Group
              Value: Example
          Type: application
          IpAddressType: ipv4

      TestALBListener:
        Type: 'AWS::ElasticLoadBalancingV2::Listener'
        Properties:
          DefaultActions:
            - Type: forward
              ForwardConfig:
                TargetGroups:
                  - TargetGroupArn: !GetAtt
                    - TargetGroup01Stack
                    - Outputs.TargetGroupARN
          LoadBalancerArn: !Ref TestALB
          Port: 80
          Protocol: HTTP

      TestECSCluster:
        Type: 'AWS::ECS::Cluster'
        Properties: {}

      ECSTaskExecutionRole:
        Type: 'AWS::IAM::Role'
        Properties:
          AssumeRolePolicyDocument:
            Version: 2012-10-17
            Statement:
              - Sid: ''
                Effect: Allow
                Principal:
                  Service: ecs-tasks.amazonaws.com
                Action: 'sts:AssumeRole'
          ManagedPolicyArns:
            - 'arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy'

      PostCodeECSTaskDefinition:
        Type: 'AWS::ECS::TaskDefinition'
        Properties:
          ExecutionRoleArn: !GetAtt 
            - ECSTaskExecutionRole
            - Arn
          ContainerDefinitions:
            - Name: PostCode
              Image: patrick888/postcode:latest
              Essential: true
              PortMappings:
                - HostPort: 80
                  Protocol: tcp
                  ContainerPort: 80
              LogConfiguration:
                LogDriver: awslogs
                Options:
                  awslogs-group: awslogs-ecs
                  awslogs-region: us-east-1
                  awslogs-stream-prefix: PostCodeECSService
          RequiresCompatibilities:
            - FARGATE
          NetworkMode: awsvpc
          Cpu: '256'
          Memory: '512'
          Family: ecs-demo

      PostCodeECSService:
        Type: 'AWS::ECS::Service'
        Properties:
          Cluster: !Ref TestECSCluster
          DeploymentController: 
            Type: CODE_DEPLOY
          DesiredCount: 1
          HealthCheckGracePeriodSeconds: 300
          LaunchType: FARGATE
          LoadBalancers: 
            - ContainerName: PostCode
              ContainerPort: 80
              TargetGroupArn: !GetAtt
                - TargetGroup01Stack
                - Outputs.TargetGroupARN
          NetworkConfiguration:
            AwsVpcConfiguration:
              AssignPublicIp: ENABLED
              SecurityGroups:
                - !Ref TestSecurityGroup
              Subnets:
                - subnet-e80ed48e
                - subnet-7c3ba772
          SchedulingStrategy: REPLICA
          ServiceName: TestService
          TaskDefinition: !Ref PostCodeECSTaskDefinition
        DependsOn: TestALBListener

(Create_Target_Group.yaml) 创建用于创建目标组的嵌套堆栈

    AWSTemplateFormatVersion: 2010-09-09
    Description: Create target group
    Resources:
      TestTargetGroup01:
        Type: AWS::ElasticLoadBalancingV2::TargetGroup
        Properties:
          Name: TestTargetGroup01
          Protocol: HTTP
          Port: 80
          TargetType: ip
          VpcId: vpc-b830c6c5
          HealthCheckPath: /healthcheck.html
    Outputs:
      TargetGroupARN:
        Value: !Ref TestTargetGroup01       
        Description: The target group ARN

通过使用嵌套堆栈和嵌套堆栈的“输出”部分中的 return 值使设置正常工作。详情请参考上文,谢谢