AWS CDK:如何在同一应用程序中引用跨堆栈资源?

Posted

技术标签:

【中文标题】AWS CDK:如何在同一应用程序中引用跨堆栈资源?【英文标题】:AWS CDK: how do I reference cross-stack resources in same app? 【发布时间】: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?

【问题讨论】:

【参考方案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 定义在哪里?不定义它意味着我们必须猜测,有时我们会猜错。 这是一个包含完整示例的帖子:***.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 );

【讨论】:

谢谢。否则不会发现,文档中的示例 (docs.aws.amazon.com/cdk/latest/guide/…) 非常有限。【参考方案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。相关问题在这里:***.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

以上是关于AWS CDK:如何在同一应用程序中引用跨堆栈资源?的主要内容,如果未能解决你的问题,请参考以下文章

如何将现有资源从不同的 AWS 账户导入 AWS CDK

如何覆盖 AWS CDK 中的资源?

如何识别 aws cdk 应用程序何时在部署状态下运行?

使用来自共享资源的 api-gatewayv2 时未绑定 aws cdk lambda

AWS 跨账户 - 对 AWS CDK 中的参数的参数存储/Secrets Manager 访问

AWS CDK 生成的资源标识符非常糟糕且不可读。有任何解决这个问题的方法吗?