【问题标题】:AWS CDK: how do I reference cross-stack resources in same app?AWS CDK:如何在同一应用程序中引用跨堆栈资源?
【发布时间】:2020-08-18 03:26:03
【问题描述】:

我有一个应用程序,它有两个堆栈,都在同一个区域/帐户中。其中一个堆栈需要另一个堆栈中存在的 lambda 的 ARN。如何引用?

// within stackA constructor
public StackA(Construct scope, String id, StackProps props) {
        SingletonFunction myLambda = SingletonFunction.Builder.create(this, "myLambda")
                                                              // some code here
                                                              .build()
        CfnOutput myLambdaArn = CfnOutput.Builder.create(this, "myLambdaArn")
                                                  .exportName("myLambdaArn")
                                                  .description("ARN of the lambda that I want to use in StackB")
                                                  .value(myLambda.getFunctionArn())
                                                  .build();
    
}

App app = new App();
Stack stackA = new StackA(app, "stackA", someAProps);    
Stack stackB = new StackB(app, "stackB", someBProps);
stackB.dependsOn(stackA);

如何将 ARN 传递到 StackB?

【问题讨论】:

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


    【解决方案1】:

    您可以访问不同堆栈中的资源,只要它们位于同一账户和 AWS 区域中。以下示例定义了堆栈 stack1,它定义了一个 Amazon S3 存储桶。然后它定义了第二个堆栈 stack2,它从 stack1 中获取存储桶作为构造函数属性。

    // Helper method to build an environment
    static Environment makeEnv(String account, String region) {
        return Environment.builder().account(account).region(region)
                .build();
    }
    
    App app = new App();
    
    Environment prod = makeEnv("123456789012", "us-east-1");
    
    StackThatProvidesABucket stack1 = new StackThatProvidesABucket(app, "Stack1",
            StackProps.builder().env(prod).build());
    
    // stack2 will take an argument "bucket"
    StackThatExpectsABucket stack2 = new StackThatExpectsABucket(app, "Stack,",
            StackProps.builder().env(prod).build(), stack1.getBucket());
    

    【讨论】:

    • 很好,你有关于这个实现的任何文档吗?
    • 您可以在下面的 AWS 文档docs.aws.amazon.com/cdk/latest/guide/resources.html中找到更详细的信息
    • 我宁愿使用我的示例,因为我也可以从其他区域\帐户导入和导出,但很高兴知道。感谢分享:)
    • stack1.getBucket 定义在哪里?不定义它意味着我们必须猜测,有时我们会猜错。
    • 这是一个包含完整示例的帖子:stackoverflow.com/a/57586393/856498
    【解决方案2】:

    CDK 的官方文档有一个完整的sharing a S3 bucket between stacks 示例。我在下面复制了它以便更快地参考。

    /**
     * Stack that defines the bucket
     */
    class Producer extends cdk.Stack {
      public readonly myBucket: s3.Bucket;
    
      constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
        super(scope, id, props);
    
        const bucket = new s3.Bucket(this, 'MyBucket', {
          removalPolicy: cdk.RemovalPolicy.DESTROY,
        });
        this.myBucket = bucket;
      }
    }
    
    interface ConsumerProps extends cdk.StackProps {
      userBucket: s3.IBucket;
    }
    
    /**
     * Stack that consumes the bucket
     */
    class Consumer extends cdk.Stack {
      constructor(scope: cdk.App, id: string, props: ConsumerProps) {
        super(scope, id, props);
    
        const user = new iam.User(this, 'MyUser');
        props.userBucket.grantReadWrite(user);
      }
    }
    
    const producer = new Producer(app, 'ProducerStack');
    new Consumer(app, 'ConsumerStack', { userBucket: producer.myBucket });
    

    【讨论】:

    【解决方案3】:

    选项 1:

    使用构造函数将数据从堆栈 A 传递到堆栈 B:

    您可以扩展 cdk.stack 并创建一个包含 stackA 的新类。

    在该堆栈中,使用 public XXX: string\number (etc) 公开您想要的相关数据(参见示例中的第 2 行)。

    稍后,只需将此数据传递给 StackB 构造函数(您也可以使用 props 传递它)。

    工作代码sn-p:

    堆栈 A:

        export class StackA extends cdk.Stack {
            public YourKey: KEY_TYPE;
        
            constructor(scope: cdk.Construct, id: string, props: cdk.StackProps ) {
                super(scope, id, props);
        
                Code goes here...
        
                // Output the key 
                new cdk.CfnOutput(this, 'KEY', { value: this.YourKey });
        
            }
        }
    

    堆栈 B:

    export class StackB extends cdk.Stack {
        constructor(scope: cdk.Construct, id: string,importedKey: KEY_TYPE, props: cdk.props) {
            super(scope, id, props)
    
            Code goes here...
            
            console.log(importedKey)
    
        }
    }
    

    垃圾箱:

    const importedKey = new StackA(app, 'id',props).YourKey;
    new StackB(app, 'id',importedKey,props);
    

    选项 2:

    有时最好将此类内容保存在参数存储中并从那里读取。

    更多信息here.

    【讨论】:

    • 这适用于跨账户部署吗?例如如果它们位于 2 个不同的帐户中,我将如何从 Stack B 中引用 Stack A 中定义的 Lambda 之类的资源?我正在尝试使用该帐户的凭据部署Stack B,但收到错误消息,我也需要Stack A 的凭据。
    • 这应该也适用于跨区域\帐户。你能确定错误吗?
    • 错误看起来像:“需要为账户 111111111111 执行 AWS 调用,但没有找到凭证。尝试过:默认凭证”,我使用账户 222222222222 的凭证来部署堆栈 B。相关问题在这里:stackoverflow.com/review/suggested-edits/26137203
    • 堆栈A中YourKey的值在哪里设置?
    • @PaulS 您可以将其设置为硬编码或使用this.YourKey填充它
    【解决方案4】:

    我发现所有答案都在正确的道路上,但没有一个能够完全和/或很好地解释它。在此示例中,我将 VPC 从 VPC 堆栈传递到 ECS 集群。

    首先,向原始堆栈添加一个属性。每当创建资产时都会设置此属性:

    export class VpcStack extends cdk.Stack {
        readonly vpc: Vpc;
    
        constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
            super(scope, id, props);
        
            // Here
            this.vpc = new Vpc(this, 'vpc', {
                maxAzs: 3,
                cidr: '10.0.0.0/16',
            });
        });
    }
    

    接下来,要求此属性作为消费堆栈的参数:

    // Create an interface that extends cdk.StackProps
    // The VPC property is added here
    interface EcsClusterStackProps extends cdk.StackProps {
        vpc: Vpc,
    }
    
    export class EcsClusterStack extends cdk.Stack {
        // Use your interface instead of the regular cdk.StackProps
        constructor(scope: cdk.Construct, id: string, props: EcsClusterStackProps) {  
            super(scope, id, props);
        
            // Use the passed-in VPC where you need it
            new Cluster(this, "myCluster", {
                capacity: {
                    instanceType: InstanceType.of(InstanceClass.M6I, InstanceSize.LARGE)
                },
                clusterName: "myCluster",
                vpc: props.vpc,  // Here
            });
        }
    }
    

    第三,在你的应用文件中传递引用:

    const app = new cdk.App();
    
    // Create the VPC stack
    const vpcStack = new VpcStack(app, 'vpc-stack', {
        env: { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION },
    });
    
    // Pass the VPC directly to the consuming stack's constructor
    const ecsClusterStack = new EcsClusterStack(app, 'ecs-cluster-stack', {
        vpc: vpcStack.vpc,  // Here
    });
    

    希望这有助于澄清一些模棱两可的领域。

    【讨论】:

    • 一些对我有帮助的资源:@​​987654321@ 和 AWS docs
    猜你喜欢
    • 2020-10-29
    • 2021-03-15
    • 2022-01-03
    • 1970-01-01
    • 2020-12-19
    • 2018-06-21
    • 1970-01-01
    • 2021-06-19
    • 2020-12-13
    相关资源
    最近更新 更多