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:如何在同一应用程序中引用跨堆栈资源?的主要内容,如果未能解决你的问题,请参考以下文章
使用来自共享资源的 api-gatewayv2 时未绑定 aws cdk lambda