View a markdown version of this page

资源和 AWS CDK - AWS 云开发套件 (AWS CDK) v2

这是 AWS CDK v2 开发者指南。旧版 CDK v1 于 2022 年 6 月 1 日进入维护阶段,并于 2023 年 6 月 1 日终止支持。

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

资源和 AWS CDK

资源是您为在应用程序中使用 AWS 服务而配置的资源。资源是... 的一个功能 AWS CloudFormation。通过在 AWS CloudFormation 模板中配置资源及其属性,您可以部署 AWS CloudFormation 到来配置资源。使用 AWS 云开发套件 (AWS CDK),您可以通过构造配置资源。然后,您可以部署 CDK 应用程序,这包括合成 AWS CloudFormation 模板并进行部署 AWS CloudFormation 以配置您的资源。

使用构造来配置资源

正如 AWS CDK 结构中所述, AWS CDK 提供了一个丰富的结构类库,称为构造,代表所有资源。 AWS

要使用资源对应的构造来创建资源实例,请将作用域作为第一个参数、构造的逻辑 ID 和一组配置属性(props)传入。例如,以下是如何使用构造库中的sqs.Queue构造创建采用 AWS KMS 加密的 Amazon SQS 队列。 AWS

TypeScript
import * as sqs from '@aws-cdk/aws-sqs'; new sqs.Queue(this, 'MyQueue', { encryption: sqs.QueueEncryption.KMS_MANAGED });
JavaScript
const sqs = require('@aws-cdk/aws-sqs'); new sqs.Queue(this, 'MyQueue', { encryption: sqs.QueueEncryption.KMS_MANAGED });
Python
import aws_cdk.aws_sqs as sqs sqs.Queue(self, "MyQueue", encryption=sqs.QueueEncryption.KMS_MANAGED)
Java
import software.amazon.awscdk.services.sqs.*; Queue.Builder.create(this, "MyQueue").encryption( QueueEncryption.KMS_MANAGED).build();
C#
using Amazon.CDK.AWS.SQS; new Queue(this, "MyQueue", new QueueProps { Encryption = QueueEncryption.KMS_MANAGED });
Go
import ( "github.com/aws/aws-cdk-go/awscdk/v2" "github.com/aws/jsii-runtime-go" sqs "github.com/aws/aws-cdk-go/awscdk/v2/awssqs" ) sqs.NewQueue(stack, jsii.String("MyQueue"), &sqs.QueueProps{ Encryption: sqs.QueueEncryption_KMS_MANAGED, })

有些配置 props 是可选的,而且在许多情况下具有默认值。在某些情况下,所有 props 都是可选的,最后一个参数可以完全省略。

资源属性

AWS 构造库中的大多数资源都暴露了属性,这些属性在部署时由解析 AWS CloudFormation。特性以属性的形式在资源类上公开,并以类型名称为前缀。以下示例展示了如何使用 queueUrl(Python:queue_url)属性获取 Amazon SQS 队列的 URL。

TypeScript
import * as sqs from '@aws-cdk/aws-sqs'; const queue = new sqs.Queue(this, 'MyQueue'); const url = queue.queueUrl; // => A string representing a deploy-time value
JavaScript
const sqs = require('@aws-cdk/aws-sqs'); const queue = new sqs.Queue(this, 'MyQueue'); const url = queue.queueUrl; // => A string representing a deploy-time value
Python
import aws_cdk.aws_sqs as sqs queue = sqs.Queue(self, "MyQueue") url = queue.queue_url # => A string representing a deploy-time value
Java
Queue queue = new Queue(this, "MyQueue"); String url = queue.getQueueUrl(); // => A string representing a deploy-time value
C#
var queue = new Queue(this, "MyQueue"); var url = queue.QueueUrl; // => A string representing a deploy-time value
Go
import ( "github.com/aws/aws-cdk-go/awscdk/v2" "github.com/aws/jsii-runtime-go" sqs "github.com/aws/aws-cdk-go/awscdk/v2/awssqs" ) queue := sqs.NewQueue(stack, jsii.String("MyQueue"), &sqs.QueueProps{}) url := queue.QueueUrl() // => A string representing a deploy-time value

有关 AWS CDK 如何将部署时属性编码为字符串的信息,请参阅令牌和 AWS CDK。

引用资源

配置资源时,您通常需要引用其他资源的属性。示例如下:

  • Amazon Elastic Container Service(Amazon ECS)资源需要引用其运行所在的集群。

  • 亚马逊 CloudFront 分配需要引用包含源代码的亚马逊简单存储服务 (Amazon S3) 存储桶。

您可以通过以下任何一种方式引用资源:

  • 通过传递在 CDK 应用程序中定义的资源,无论是在同一堆栈还是在不同的堆栈中均可

  • 通过传递引用 AWS 账户中定义的资源的代理对象,该资源是根据资源的唯一标识符(例如 ARN)创建的

如果某一构造的属性表示另一种资源的构造,则其类型就是该构造的接口类型。例如,Amazon ECS 构造采用了类型 ecs.ICluster 的属性 cluster。另一个例子是采用类型为的属性 sourceBucket (Python:source_bucket) 的 CloudFront 分布结构s3.IBucket

您可以直接传递在同一 AWS CDK 应用程序中定义的正确类型的任何资源对象。以下示例定义了一个 Amazon ECS 集群,然后使用该集群来定义 Amazon ECS 服务。

TypeScript
const cluster = new ecs.Cluster(this, 'Cluster', { /*...*/ }); const service = new ecs.Ec2Service(this, 'Service', { cluster: cluster });
JavaScript
const cluster = new ecs.Cluster(this, 'Cluster', { /*...*/ }); const service = new ecs.Ec2Service(this, 'Service', { cluster: cluster });
Python
cluster = ecs.Cluster(self, "Cluster") service = ecs.Ec2Service(self, "Service", cluster=cluster)
Java
Cluster cluster = new Cluster(this, "Cluster"); Ec2Service service = new Ec2Service(this, "Service", new Ec2ServiceProps.Builder().cluster(cluster).build());
C#
var cluster = new Cluster(this, "Cluster"); var service = new Ec2Service(this, "Service", new Ec2ServiceProps { Cluster = cluster });
Go
import ( "github.com/aws/aws-cdk-go/awscdk/v2" "github.com/aws/jsii-runtime-go" ecs "github.com/aws/aws-cdk-go/awscdk/v2/awsecs" ) cluster := ecs.NewCluster(stack, jsii.String("MyCluster"), &ecs.ClusterProps{}) service := ecs.NewEc2Service(stack, jsii.String("MyService"), &ecs.Ec2ServiceProps{ Cluster: cluster, })

引用其他堆栈中的资源

您可以引用其他堆栈中的资源,只要它们是在同一个应用程序中定义的。堆栈可以处于相同或不同的 AWS 环境(账户和区域)中。通常使用以下模式:

  • 将对构造的引用存储为生成资源的堆栈属性。(要获取对当前构造堆栈的引用,请使用 Stack.of(this)。)

  • 将此引用传递给堆栈的构造函数,该构造函数将资源作为参数或属性使用。然后,使用堆栈将其作为属性传递给任何需要它的构造。

以下示例定义了堆栈 stack1。此堆栈定义了 Amazon S3 存储桶,并将对存储桶构造的引用存储为堆栈的属性。然后,应用程序定义第二个堆栈stack2,该堆栈在实例化时接受存储桶。stack2例如,可能会定义一个使用存储桶存储数据的 AWS Glue 表。

TypeScript
const prod = { account: '123456789012', region: 'us-east-1' }; const stack1 = new StackThatProvidesABucket(app, 'Stack1', { env: prod }); // stack2 will take a property { bucket: IBucket } const stack2 = new StackThatExpectsABucket(app, 'Stack2', { bucket: stack1.bucket, env: prod });
JavaScript
const prod = { account: '123456789012', region: 'us-east-1' }; const stack1 = new StackThatProvidesABucket(app, 'Stack1', { env: prod }); // stack2 will take a property { bucket: IBucket } const stack2 = new StackThatExpectsABucket(app, 'Stack2', { bucket: stack1.bucket, env: prod });
Python
prod = core.Environment(account="123456789012", region="us-east-1") stack1 = StackThatProvidesABucket(app, "Stack1", env=prod) # stack2 will take a property "bucket" stack2 = StackThatExpectsABucket(app, "Stack2", bucket=stack1.bucket, env=prod)
Java
// 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.bucket);
C#
Amazon.CDK.Environment makeEnv(string account, string region) { return new Amazon.CDK.Environment { Account = account, Region = region }; } var prod = makeEnv(account: "123456789012", region: "us-east-1"); var stack1 = new StackThatProvidesABucket(app, "Stack1", new StackProps { Env = prod }); // stack2 will take a property "bucket" var stack2 = new StackThatExpectsABucket(app, "Stack2", new StackProps { Env = prod, bucket = stack1.Bucket});

如果 AWS CDK 确定资源在同一个环境中,但在不同的堆栈中,它会自动合成生产堆栈中的 AWS CloudFormation 导出内容和消费堆栈Fn::ImportValue中的导出,将该信息从一个堆栈传输到另一个堆栈。这是一个强有力的参考——默认行为。您可以控制跨堆栈引用的强度以避免依赖关系死锁。

参考强度

每个跨堆栈引用都有一个强度,它决定了所使用 CloudFormation 的机制和堆栈之间的耦合:

(默认)

生产堆栈创建 CloudFormation 导出,消费堆栈使用Fn::ImportValue。这意味着,在任何使用者仍在导入的情况下,生产堆栈无法更新以删除导出。 CloudFormation 强制执行此限制。

虚弱

消费堆栈Fn::GetStackOutput用于直接从生产堆栈读取输出。未创建任何导出耦合;任一堆栈均可单独更新或删除。

二者

从强到弱迁移的过渡状态。生产堆栈保留其导出(因此现有的强大消费者不会被打破),而消费堆栈则切换到Fn::GetStackOutput

依赖僵局(致命的拥抱)

强引用可能会造成阻碍堆栈更新的死锁。发生这种情况是因为在另一个堆栈仍在导入导出时 CloudFormation 无法删除该导出,并且在导出存在之前,消费堆栈无法更新为停止导入。你可能会看到这样的错误:

Export Stack1:ExportsOutputFnGetAtt-****** cannot be deleted as it is in use by Stack2

当你尝试删除共享资源或重组堆栈时,通常会发生这种情况。弱引用完全可以避免这个问题,因为它们不会创建导出。

控制参考强度

您可以在三个范围内控制参考强度:应用范围、每个资源或每次使用量。

App-wide 默认

设置以下上下文键cdk.json以更改应用程序中所有跨堆栈引用的默认值:

{ "context": { "@aws-cdk/core:defaultCrossStackReferences": "weak" } }
Per-resource

使用以下方法覆盖所有指向特定资源的参考文献的强度CrossStackReferences.of(resource).produce(strength)

TypeScript
declare const bucket: s3.Bucket; CrossStackReferences.of(bucket).produce(ReferenceStrength.WEAK);
JavaScript
const { CrossStackReferences, ReferenceStrength } = require('aws-cdk-lib'); CrossStackReferences.of(bucket).produce(ReferenceStrength.WEAK);
Python
from aws_cdk import CrossStackReferences, ReferenceStrength CrossStackReferences.of(bucket).produce(ReferenceStrength.WEAK)
Java
import software.amazon.awscdk.CrossStackReferences; import software.amazon.awscdk.ReferenceStrength; CrossStackReferences.of(bucket).produce(ReferenceStrength.WEAK);
C#
using Amazon.CDK; CrossStackReferences.Of(bucket).Produce(ReferenceStrength.WEAK);
Go
import "github.com/aws/aws-cdk-go/awscdk/v2" awscdk.CrossStackReferences_Of(bucket).Produce(awscdk.ReferenceStrength_WEAK)

无论应用范围内的默认值Fn::GetStackOutput如何,现在都将使用bucket来自其他堆栈的所有引用。

Per-usage

使用Stack.consumeReference()以下方法在消费时覆盖单一参考值的强度:

TypeScript
declare const topic: sns.Topic; const consumer = new Stack(app, 'Consumer', { env: { account: '123456789012', region: 'us-east-1' }, }); new sns.Subscription(consumer, 'Subscription', { topic: sns.Topic.fromTopicArn(consumer, 'Topic', Stack.consumeReference(topic.topicArn, ReferenceStrength.WEAK)), endpoint: 'https://example.com/webhook', protocol: sns.SubscriptionProtocol.HTTPS, });
JavaScript
const { Stack, ReferenceStrength } = require('aws-cdk-lib'); const sns = require('aws-cdk-lib/aws-sns'); const subscriptions = require('aws-cdk-lib/aws-sns-subscriptions'); const consumer = new Stack(app, 'Consumer', { env: { account: '123456789012', region: 'us-east-1' }, }); new sns.Subscription(consumer, 'Subscription', { topic: sns.Topic.fromTopicArn(consumer, 'Topic', Stack.consumeReference(topic.topicArn, ReferenceStrength.WEAK)), endpoint: 'https://example.com/webhook', protocol: sns.SubscriptionProtocol.HTTPS, });
Python
from aws_cdk import Stack, ReferenceStrength import aws_cdk.aws_sns as sns consumer = Stack(app, "Consumer", env=core.Environment(account="123456789012", region="us-east-1") ) sns.Subscription(consumer, "Subscription", topic=sns.Topic.from_topic_arn(consumer, "Topic", Stack.consume_reference(topic.topic_arn, ReferenceStrength.WEAK)), endpoint="https://example.com/webhook", protocol=sns.SubscriptionProtocol.HTTPS )
Java
import software.amazon.awscdk.Stack; import software.amazon.awscdk.ReferenceStrength; import software.amazon.awscdk.services.sns.*; Stack consumer = new Stack(app, "Consumer", StackProps.builder() .env(Environment.builder().account("123456789012").region("us-east-1").build()) .build()); Subscription.Builder.create(consumer, "Subscription") .topic(Topic.fromTopicArn(consumer, "Topic", Stack.consumeReference(topic.getTopicArn(), ReferenceStrength.WEAK))) .endpoint("https://example.com/webhook") .protocol(SubscriptionProtocol.HTTPS) .build();
C#
using Amazon.CDK; using Amazon.CDK.AWS.SNS; var consumer = new Stack(app, "Consumer", new StackProps { Env = new Amazon.CDK.Environment { Account = "123456789012", Region = "us-east-1" } }); new Subscription(consumer, "Subscription", new SubscriptionProps { Topic = Topic.FromTopicArn(consumer, "Topic", Stack.ConsumeReference(topic.TopicArn, ReferenceStrength.WEAK)), Endpoint = "https://example.com/webhook", Protocol = SubscriptionProtocol.HTTPS });
Go
import ( "github.com/aws/aws-cdk-go/awscdk/v2" "github.com/aws/aws-cdk-go/awscdk/v2/awssns" "github.com/aws/jsii-runtime-go" ) consumer := awscdk.NewStack(app, jsii.String("Consumer"), &awscdk.StackProps{ Env: &awscdk.Environment{Account: jsii.String("123456789012"), Region: jsii.String("us-east-1")}, }) awssns.NewSubscription(consumer, jsii.String("Subscription"), &awssns.SubscriptionProps{ Topic: awssns.Topic_FromTopicArn(consumer, jsii.String("Topic"), awscdk.Stack_ConsumeReference(topic.TopicArn(), awscdk.ReferenceStrength_WEAK)), Endpoint: jsii.String("https://example.com/webhook"), Protocol: awssns.SubscriptionProtocol_HTTPS, })

Stack.consumeListReference()用于字符串列表引用。

作用域覆盖

您还可以使用设置构造子树的参考强度。CrossStackReferences.of(scope).consume(strength)在该范围内使用的所有跨堆栈引用都将使用指定的强度。

从强引用迁移到弱引用

如果您已经部署了具有强引用的堆栈,则无法直接切换到弱引用,CloudFormation 这将失败,因为导出仍在使用中。取而代之的是,使用通过BOTH过渡状态的两阶段迁移。

使用哪个 API 取决于你的目标:

  • 删除单个引用(但同时保留堆栈和资源)——仅用于削弱该特定用Stack.consumeReference()法。

  • 移除或重组生产资源 —— CrossStackReferences.of(producer).produce() 用来削弱所有同时指向该资源的引用。

两种方法都遵循下文描述的相同两阶段模式。这些示例显示了按资源分列的方法。对于每次使用情况,Stack.consumeReference(ref, ReferenceStrength.BOTH)在第 1 阶段和第 2 阶段使用参考文献Stack.consumeReference(ref, ReferenceStrength.WEAK)进行封装。

第 1 阶段:使用 BOTH 进行部署

将参考强度切换为BOTH。这使消费堆栈开始使用Fn::GetStackOutput,但会将导出保留在生产堆栈中,因此过渡是安全的:

TypeScript
declare const bucket: s3.Bucket; CrossStackReferences.of(bucket).produce(ReferenceStrength.BOTH);
JavaScript
const { CrossStackReferences, ReferenceStrength } = require('aws-cdk-lib'); CrossStackReferences.of(bucket).produce(ReferenceStrength.BOTH);
Python
from aws_cdk import CrossStackReferences, ReferenceStrength CrossStackReferences.of(bucket).produce(ReferenceStrength.BOTH)
Java
import software.amazon.awscdk.CrossStackReferences; import software.amazon.awscdk.ReferenceStrength; CrossStackReferences.of(bucket).produce(ReferenceStrength.BOTH);
C#
using Amazon.CDK; CrossStackReferences.Of(bucket).Produce(ReferenceStrength.BOTH);
Go
import "github.com/aws/aws-cdk-go/awscdk/v2" awscdk.CrossStackReferences_Of(bucket).Produce(awscdk.ReferenceStrength_BOTH)

部署两个堆栈。

第 2 阶段:使用 WEAK 进行部署

现在没有消费者使用Fn::ImportValue,可以安全地移除出口。切换到WEAK

TypeScript
declare const bucket: s3.Bucket; CrossStackReferences.of(bucket).produce(ReferenceStrength.WEAK);
JavaScript
const { CrossStackReferences, ReferenceStrength } = require('aws-cdk-lib'); CrossStackReferences.of(bucket).produce(ReferenceStrength.WEAK);
Python
from aws_cdk import CrossStackReferences, ReferenceStrength CrossStackReferences.of(bucket).produce(ReferenceStrength.WEAK)
Java
import software.amazon.awscdk.CrossStackReferences; import software.amazon.awscdk.ReferenceStrength; CrossStackReferences.of(bucket).produce(ReferenceStrength.WEAK);
C#
using Amazon.CDK; CrossStackReferences.Of(bucket).Produce(ReferenceStrength.WEAK);
Go
import "github.com/aws/aws-cdk-go/awscdk/v2" awscdk.CrossStackReferences_Of(bucket).Produce(awscdk.ReferenceStrength_WEAK)

部署两个堆栈。导出已删除,引用现在完全不足。

在这次迁移之后,你可以自由地移除、移动或重组资源,而不会陷入致命的拥抱。

手动解决方法(旧版)

如果您尚未使用参考强度控制,则可以手动绕过死锁。从消费堆栈中移除共享资源的使用。然后,使用与自动生成的导出完全相同的逻辑 ID 手动将相同的导出添加到生产堆栈中。部署两个堆栈以移除. Fn::ImportValue 然后删除手动导出(如果不再需要则删除共享资源),并再次部署这两个堆栈。堆栈的 exportValue() 方法是一种为此目的创建手动导出的便捷方法。

引用您的资源 AWS 账户

假设你想在 AWS CDK 应用程序中使用 AWS 账户中已经可用的资源。这可能是通过控制台、 AWS SDK、直接使用 AWS CloudFormation或在其他 AWS CDK 应用程序中定义的资源。您可以将资源的 ARN(或其他标识属性或属性组)转换为代理对象。代理对象通过调用资源类上的静态工厂方法来用作对资源的引用。

当你创建这样的代理时,外部资源不会成为 AWS CDK 应用程序的一部分。因此,您在 AWS CDK 应用程序中对代理所做的更改不会影响已部署的资源。但是,可以将代理传递给任何需要该类型资源的 AWS CDK 方法。

以下示例展示了如何基于具有 ARN arn:aws:s3:::amzn-s3-demo-bucket1 的现有存储桶来引用存储桶,以及如何基于具有特定 ID 的现有 VPC 来引用 Amazon Virtual Private Cloud。

TypeScript
// Construct a proxy for a bucket by its name (must be same account) s3.Bucket.fromBucketName(this, 'MyBucket', 'amzn-s3-demo-bucket1'); // Construct a proxy for a bucket by its full ARN (can be another account) s3.Bucket.fromBucketArn(this, 'MyBucket', 'arn:aws:s3:::amzn-s3-demo-bucket1'); // Construct a proxy for an existing VPC from its attribute(s) ec2.Vpc.fromVpcAttributes(this, 'MyVpc', { vpcId: 'vpc-1234567890abcde', });
JavaScript
// Construct a proxy for a bucket by its name (must be same account) s3.Bucket.fromBucketName(this, 'MyBucket', 'amzn-s3-demo-bucket1'); // Construct a proxy for a bucket by its full ARN (can be another account) s3.Bucket.fromBucketArn(this, 'MyBucket', 'arn:aws:s3:::amzn-s3-demo-bucket1'); // Construct a proxy for an existing VPC from its attribute(s) ec2.Vpc.fromVpcAttributes(this, 'MyVpc', { vpcId: 'vpc-1234567890abcde' });
Python
# Construct a proxy for a bucket by its name (must be same account) s3.Bucket.from_bucket_name(self, "MyBucket", "amzn-s3-demo-bucket1") # Construct a proxy for a bucket by its full ARN (can be another account) s3.Bucket.from_bucket_arn(self, "MyBucket", "arn:aws:s3:::amzn-s3-demo-bucket1") # Construct a proxy for an existing VPC from its attribute(s) ec2.Vpc.from_vpc_attributes(self, "MyVpc", vpc_id="vpc-1234567890abcdef")
Java
// Construct a proxy for a bucket by its name (must be same account) Bucket.fromBucketName(this, "MyBucket", "amzn-s3-demo-bucket1"); // Construct a proxy for a bucket by its full ARN (can be another account) Bucket.fromBucketArn(this, "MyBucket", "arn:aws:s3:::amzn-s3-demo-bucket1"); // Construct a proxy for an existing VPC from its attribute(s) Vpc.fromVpcAttributes(this, "MyVpc", VpcAttributes.builder() .vpcId("vpc-1234567890abcdef").build());
C#
// Construct a proxy for a bucket by its name (must be same account) Bucket.FromBucketName(this, "MyBucket", "amzn-s3-demo-bucket1"); // Construct a proxy for a bucket by its full ARN (can be another account) Bucket.FromBucketArn(this, "MyBucket", "arn:aws:s3:::amzn-s3-demo-bucket1"); // Construct a proxy for an existing VPC from its attribute(s) Vpc.FromVpcAttributes(this, "MyVpc", new VpcAttributes { VpcId = "vpc-1234567890abcdef" });
Go
// Define a proxy for a bucket by its name (must be same account) s3.Bucket_FromBucketName(stack, jsii.String("MyBucket"), jsii.String("amzn-s3-demo-bucket1")) // Define a proxy for a bucket by its full ARN (can be another account) s3.Bucket_FromBucketArn(stack, jsii.String("MyBucket"), jsii.String("arn:aws:s3:::amzn-s3-demo-bucket1")) // Define a proxy for an existing VPC from its attributes ec2.Vpc_FromVpcAttributes(stack, jsii.String("MyVpc"), &ec2.VpcAttributes{ VpcId: jsii.String("vpc-1234567890abcde"), })

让我们来详细了解一下 Vpc.fromLookup() 方法。由于 ec2.Vpc 构造很复杂,您可以通过多种方式选择要与 CDK 应用程序一起使用的 VPC。为了解决这个问题,VPC 结构具有fromLookup静态方法 (Python:from_lookup),允许您在合成时通过查询您的 AWS 账户来查找所需的亚马逊 VPC。

要使用 Vpc.fromLookup(),合成堆栈的系统必须有权访问拥有 Amazon VPC 的账户。这是因为 CDK Toolkit 会在合成时查询账户以找到正确的 Amazon VPC。

此外,仅Vpc.fromLookup()适用于使用显式帐户区域定义的堆栈(参见 AWS CDK AWS CDK 的环境 环境)。如果 AWS CDK 尝试从与环境无关的堆栈中查找亚马逊 VPC,CDK 工具包不知道要查询哪个环境才能找到该 VPC。

您必须提供足以唯一标识 AWS 账户中的 VPC 的Vpc.fromLookup()属性。例如,只能有一个默认 VPC,因此将该 VPC 指定为默认 VPC 就足够了。

TypeScript
ec2.Vpc.fromLookup(this, 'DefaultVpc', { isDefault: true });
JavaScript
ec2.Vpc.fromLookup(this, 'DefaultVpc', { isDefault: true });
Python
ec2.Vpc.from_lookup(self, "DefaultVpc", is_default=True)
Java
Vpc.fromLookup(this, "DefaultVpc", VpcLookupOptions.builder() .isDefault(true).build());
C#
Vpc.FromLookup(this, id = "DefaultVpc", new VpcLookupOptions { IsDefault = true });
Go
ec2.Vpc_FromLookup(this, jsii.String("DefaultVpc"), &ec2.VpcLookupOptions{ IsDefault: jsii.Bool(true), })

您还可以使用 tags 属性按标签查询 VPC。您可以使用 AWS CloudFormation 或 AWS CDK 在创建 Amazon VPC 时向其添加标签。创建标签后,您可以使用 AWS 管理控制台、 AWS CLI 或 AWS SDK 随时编辑标签。除了您自己添加的任何标签外, AWS CDK 还会自动将以下标签添加到其创建的所有 VPC 中。

  • 名称:VPC 的名称。

  • aws-cdk:subnet-name:子网的名称。

  • aws-cdk:subnet-type:子网类型:公有子网、私有子网或隔离子网。

TypeScript
ec2.Vpc.fromLookup(this, 'PublicVpc', {tags: {'aws-cdk:subnet-type': "Public"}});
JavaScript
ec2.Vpc.fromLookup(this, 'PublicVpc', {tags: {'aws-cdk:subnet-type': "Public"}});
Python
ec2.Vpc.from_lookup(self, "PublicVpc", tags={"aws-cdk:subnet-type": "Public"})
Java
Vpc.fromLookup(this, "PublicVpc", VpcLookupOptions.builder() .tags(java.util.Map.of("aws-cdk:subnet-type", "Public")) // Java 9 or later .build());
C#
Vpc.FromLookup(this, id: "PublicVpc", new VpcLookupOptions { Tags = new Dictionary<string, string> { ["aws-cdk:subnet-type"] = "Public" } });
Go
ec2.Vpc_FromLookup(this, jsii.String("DefaultVpc"), &ec2.VpcLookupOptions{ Tags: &map[string]*string{"aws-cdk:subnet-type": jsii.String("Public")}, })

Vpc.fromLookup() 的结果缓存在项目的 cdk.context.json 文件中。(请参阅上下文值和 AWS CDK 。) 将此文件提交到版本控制,这样您的应用程序就可以继续引用同一 Amazon VPC。即使您稍后更改了 VPC 的属性,从而导致选择了不同的 VPC,这也会起作用。如果您要在无法访问定义 VPC 的 AWS 账户(例如 CDK Pipelines)的环境中部署堆栈,这一点尤其重要。

尽管您可以在使用 AWS CDK 应用程序中定义的类似资源的任何地方使用外部资源,但您无法对其进行修改。例如,在外部 s3.Bucket 上调用 addToResourcePolicy(Python:add_to_resource_policy)不会执行任何操作。

资源物理名称

中 AWS CloudFormation 资源的逻辑名称与部署后在 AWS 管理控制台中显示的资源名称不同 AWS CloudFormation。 AWS CDK 将这些最终名称称为物理名称

例如, AWS CloudFormation 可能会使用逻辑 ID Stack2MyBucket4DD88B4F 和物理名称创建 Amazon S3 存储桶stack2MyBucket4dd88b4f-iuv1rbv9z3to

在创建表示资源的构造时,您可以使用属性 <resourceType>Name 来指定物理名称。以下示例创建了物理名称为 amzn-s3-demo-bucket 的 Amazon S3 存储桶。

TypeScript
const bucket = new s3.Bucket(this, 'MyBucket', { bucketName: 'amzn-s3-demo-bucket', });
JavaScript
const bucket = new s3.Bucket(this, 'MyBucket', { bucketName: 'amzn-s3-demo-bucket' });
Python
bucket = s3.Bucket(self, "MyBucket", bucket_name="amzn-s3-demo-bucket")
Java
Bucket bucket = Bucket.Builder.create(this, "MyBucket") .bucketName("amzn-s3-demo-bucket").build();
C#
var bucket = new Bucket(this, "MyBucket", new BucketProps { BucketName = "amzn-s3-demo-bucket" });
Go
bucket := s3.NewBucket(this, jsii.String("MyBucket"), &s3.BucketProps{ BucketName: jsii.String("amzn-s3-demo-bucket"), })

为资源分配物理名称有一些缺点 AWS CloudFormation。最重要的是,如果资源已分配了物理名称,则对需要替换资源的已部署资源进行任何更改(例如更改创建后不可变的资源属性)都将失败。如果你最终处于这种状态,唯一的解决方案是删除 AWS CloudFormation 堆栈,然后再次部署 AWS CDK 应用程序。有关详细信息,请参阅 AWS CloudFormation 文档

在某些情况下,例如使用跨环境引用创建 AWS CDK 应用程序时, AWS CDK 需要物理名称才能正常运行。在这种情况下,如果你不想费心自己想出一个物理名字,你可以让 AWS CDK 为你命名。为此,请使用特殊值 PhysicalName.GENERATE_IF_NEEDED,如下所示。

TypeScript
const bucket = new s3.Bucket(this, 'MyBucket', { bucketName: core.PhysicalName.GENERATE_IF_NEEDED, });
JavaScript
const bucket = new s3.Bucket(this, 'MyBucket', { bucketName: core.PhysicalName.GENERATE_IF_NEEDED });
Python
bucket = s3.Bucket(self, "MyBucket", bucket_name=core.PhysicalName.GENERATE_IF_NEEDED)
Java
Bucket bucket = Bucket.Builder.create(this, "MyBucket") .bucketName(PhysicalName.GENERATE_IF_NEEDED).build();
C#
var bucket = new Bucket(this, "MyBucket", new BucketProps { BucketName = PhysicalName.GENERATE_IF_NEEDED });
Go
bucket := s3.NewBucket(this, jsii.String("MyBucket"), &s3.BucketProps{ BucketName: awscdk.PhysicalName_GENERATE_IF_NEEDED(), })

传递唯一资源标识符

应尽可能通过引用来传递资源,如上节中所述。但是,在某些情况下,您别无选择,只能通过资源的某个属性来引用该资源。以下是使用案例示例:

  • 当你使用低级 AWS CloudFormation 资源时。

  • 当您需要向 AWS CDK 应用程序的运行时组件公开资源时,例如通过环境变量引用 Lambda 函数时。

这些标识符可用作资源的属性,如下所示。

TypeScript
bucket.bucketName lambdaFunc.functionArn securityGroup.groupArn
JavaScript
bucket.bucketName lambdaFunc.functionArn securityGroup.groupArn
Python
bucket.bucket_name lambda_func.function_arn security_group_arn
Java

Java AWS CDK 绑定使用 getter 方法作为属性。

bucket.getBucketName() lambdaFunc.getFunctionArn() securityGroup.getGroupArn()
C#
bucket.BucketName lambdaFunc.FunctionArn securityGroup.GroupArn
Go
bucket.BucketName() fn.FunctionArn()

以下示例显示如何将生成的存储桶名称传递给 AWS Lambda 函数。

TypeScript
const bucket = new s3.Bucket(this, 'Bucket'); new lambda.Function(this, 'MyLambda', { // ... environment: { BUCKET_NAME: bucket.bucketName, }, });
JavaScript
const bucket = new s3.Bucket(this, 'Bucket'); new lambda.Function(this, 'MyLambda', { // ... environment: { BUCKET_NAME: bucket.bucketName } });
Python
bucket = s3.Bucket(self, "Bucket") lambda.Function(self, "MyLambda", environment=dict(BUCKET_NAME=bucket.bucket_name))
Java
final Bucket bucket = new Bucket(this, "Bucket"); Function.Builder.create(this, "MyLambda") .environment(java.util.Map.of( // Java 9 or later "BUCKET_NAME", bucket.getBucketName())) .build();
C#
var bucket = new Bucket(this, "Bucket"); new Function(this, "MyLambda", new FunctionProps { Environment = new Dictionary<string, string> { ["BUCKET_NAME"] = bucket.BucketName } });
Go
bucket := s3.NewBucket(this, jsii.String("Bucket"), &s3.BucketProps{}) lambda.NewFunction(this, jsii.String("MyLambda"), &lambda.FunctionProps{ Environment: &map[string]*string{"BUCKET_NAME": bucket.BucketName()}, })

在资源之间授予权限

Higher-level 结构通过提供简单的、基于意图的 API 来表达权限要求,使最低权限权限成为可能。例如,许多结构提供授予方法,您可以使用这些方法向实体(例如 IAM 角色或用户)授予使用资源的权限,而无需手动创建 IAM 权限声明。

授权方法可通过授予类获得(BucketGrants例如 Amazon S3 存储桶)。这些类适用于 L1 和 L2 结构。为方便起见,L2 结构公开了grants属性,但您也可以直接从 L1 构造创建 Grants 类。你可以将 Grant s 类与 Mixin 结合使用,以 L2-like 方便使用 L1 构造。

以下示例创建了权限以允许 Lambda 函数的执行角色读取对象并将其写入特定 Amazon S3 存储桶。如果使用 AWS KMS 密钥加密 Amazon S3 存储桶,则此方法还向 Lambda 函数的执行角色授予使用该密钥解密的权限。

TypeScript
if (bucket.grants.readWrite(func).success) { // ... }
JavaScript
if ( bucket.grants.readWrite(func).success) { // ... }
Python
if bucket.grants.read_write(func).success: # ...
Java
if (bucket.getGrants().readWrite(func).getSuccess()) { // ... }
C#
if (bucket.Grants.ReadWrite(func).Success) { // ... }
Go
if *bucket.Grants().ReadWrite(function, nil).Success() { // ... }

授权方法会返回一个 iam.Grant 对象。使用 Grant 对象的 success 属性来确定是否有效应用了授权(例如,其可能尚未应用于外部资源)。您也可以使用 Grant 对象的 assertSuccess(Python:assert_success)方法来强制执行授权已成功应用。

如果特定的使用案例没有可用的特定授权方法,则可以使用通用的授权方法,通过指定的操作列表来定义新的授权。

以下示例显示了如何授予 Lambda 函数对 Amazon DynamoDB CreateBackup 操作的访问权限。

TypeScript
table.grants.actions(func, 'dynamodb:CreateBackup');
JavaScript
table.grants.actions(func, 'dynamodb:CreateBackup');
Python
table.grants.actions(func, "dynamodb:CreateBackup")
Java
table.getGrants().actions(func, "dynamodb:CreateBackup");
C#
table.Grants.Actions(func, "dynamodb:CreateBackup");
Go
table := dynamodb.NewTable(this, jsii.String("MyTable"), &dynamodb.TableProps{}) table.Grants().Actions(function, jsii.String("dynamodb:CreateBackup"))

许多资源(例如 Lambda 函数)都需要在执行代码时承担角色。配置属性让您能够指定 iam.IRole。如果未指定角色,则该函数会自动创建一个专门用于此用途的角色。然后您可以对资源使用授权方法,以向该角色添加语句。

使用较低级别的 API 构建授予方法,用于处理 IAM 策略。策略被建模为PolicyDocument对象。使用 addToRolePolicy 方法(Python:add_to_role_policy)将语句直接添加到角色(或构造的附加角色),或者使用 addToResourcePolicy(Python:add_to_resource_policy)方法将语句添加到资源的策略(例如 Bucket 策略)中。

资源指标和警报

许多资源发布的 CloudWatch 指标可用于设置监控仪表板和警报。 Higher-level 构造具有指标方法,使您无需查找要使用的正确名称即可访问指标。

以下示例显示了如何定义当 Amazon SQS 队列的 ApproximateNumberOfMessagesNotVisible 超过 100 时的警报。

TypeScript
import * as cw from '@aws-cdk/aws-cloudwatch'; import * as sqs from '@aws-cdk/aws-sqs'; import { Duration } from '@aws-cdk/core'; const queue = new sqs.Queue(this, 'MyQueue'); const metric = queue.metricApproximateNumberOfMessagesNotVisible({ label: 'Messages Visible (Approx)', period: Duration.minutes(5), // ... }); metric.createAlarm(this, 'TooManyMessagesAlarm', { comparisonOperator: cw.ComparisonOperator.GREATER_THAN_THRESHOLD, threshold: 100, // ... });
JavaScript
const cw = require('@aws-cdk/aws-cloudwatch'); const sqs = require('@aws-cdk/aws-sqs'); const { Duration } = require('@aws-cdk/core'); const queue = new sqs.Queue(this, 'MyQueue'); const metric = queue.metricApproximateNumberOfMessagesNotVisible({ label: 'Messages Visible (Approx)', period: Duration.minutes(5) // ... }); metric.createAlarm(this, 'TooManyMessagesAlarm', { comparisonOperator: cw.ComparisonOperator.GREATER_THAN_THRESHOLD, threshold: 100 // ... });
Python
import aws_cdk.aws_cloudwatch as cw import aws_cdk.aws_sqs as sqs from aws_cdk.core import Duration queue = sqs.Queue(self, "MyQueue") metric = queue.metric_approximate_number_of_messages_not_visible( label="Messages Visible (Approx)", period=Duration.minutes(5), # ... ) metric.create_alarm(self, "TooManyMessagesAlarm", comparison_operator=cw.ComparisonOperator.GREATER_THAN_THRESHOLD, threshold=100, # ... )
Java
import software.amazon.awscdk.core.Duration; import software.amazon.awscdk.services.sqs.Queue; import software.amazon.awscdk.services.cloudwatch.Metric; import software.amazon.awscdk.services.cloudwatch.MetricOptions; import software.amazon.awscdk.services.cloudwatch.CreateAlarmOptions; import software.amazon.awscdk.services.cloudwatch.ComparisonOperator; Queue queue = new Queue(this, "MyQueue"); Metric metric = queue .metricApproximateNumberOfMessagesNotVisible(MetricOptions.builder() .label("Messages Visible (Approx)") .period(Duration.minutes(5)).build()); metric.createAlarm(this, "TooManyMessagesAlarm", CreateAlarmOptions.builder() .comparisonOperator(ComparisonOperator.GREATER_THAN_THRESHOLD) .threshold(100) // ... .build());
C#
using cdk = Amazon.CDK; using cw = Amazon.CDK.AWS.CloudWatch; using sqs = Amazon.CDK.AWS.SQS; var queue = new sqs.Queue(this, "MyQueue"); var metric = queue.MetricApproximateNumberOfMessagesNotVisible(new cw.MetricOptions { Label = "Messages Visible (Approx)", Period = cdk.Duration.Minutes(5), // ... }); metric.CreateAlarm(this, "TooManyMessagesAlarm", new cw.CreateAlarmOptions { ComparisonOperator = cw.ComparisonOperator.GREATER_THAN_THRESHOLD, Threshold = 100, // .. });
Go
import ( "github.com/aws/aws-cdk-go/awscdk/v2" "github.com/aws/jsii-runtime-go" cw "github.com/aws/aws-cdk-go/awscdk/v2/awscloudwatch" sqs "github.com/aws/aws-cdk-go/awscdk/v2/awssqs" ) queue := sqs.NewQueue(this, jsii.String("MyQueue"), &sqs.QueueProps{}) metric := queue.MetricApproximateNumberOfMessagesNotVisible(&cw.MetricOptions{ Label: jsii.String("Messages Visible (Approx)"), Period: awscdk.Duration_Minutes(jsii.Number(5)), }) metric.CreateAlarm(this, jsii.String("TooManyMessagesAlarm"), &cw.CreateAlarmOptions{ ComparisonOperator: cw.ComparisonOperator_GREATER_THAN_THRESHOLD, Threshold: jsii.Number(100), })

如果没有针对特定指标的方法,则可以使用通用指标方法来手动指定指标名称。

也可以将指标添加到 CloudWatch 仪表板中。请参阅CloudWatch

网络流量

在许多情况下,您必须启用网络权限才能使应用程序正常运行,例如当计算基础设施需要访问持久层时。建立或侦听连接的资源会公开启用流量的方法,包括设置安全组规则或网络 ACL。

IConnectable 资源具有 connections 属性,该属性是网络流量规则配置的网关。

您可以使用 allow 方法让数据能够在给定的网络路径上流动。以下示例启用了与 Web 的 HTTPS 连接以及来自 Amazon EC2 Auto Scaling 组 fleet2 的传入连接。

TypeScript
import * as asg from '@aws-cdk/aws-autoscaling'; import * as ec2 from '@aws-cdk/aws-ec2'; const fleet1: asg.AutoScalingGroup = asg.AutoScalingGroup(/*...*/); // Allow surfing the (secure) web fleet1.connections.allowTo(new ec2.Peer.anyIpv4(), new ec2.Port({ fromPort: 443, toPort: 443 })); const fleet2: asg.AutoScalingGroup = asg.AutoScalingGroup(/*...*/); fleet1.connections.allowFrom(fleet2, ec2.Port.AllTraffic());
JavaScript
const asg = require('@aws-cdk/aws-autoscaling'); const ec2 = require('@aws-cdk/aws-ec2'); const fleet1 = asg.AutoScalingGroup(); // Allow surfing the (secure) web fleet1.connections.allowTo(new ec2.Peer.anyIpv4(), new ec2.Port({ fromPort: 443, toPort: 443 })); const fleet2 = asg.AutoScalingGroup(); fleet1.connections.allowFrom(fleet2, ec2.Port.AllTraffic());
Python
import aws_cdk.aws_autoscaling as asg import aws_cdk.aws_ec2 as ec2 fleet1 = asg.AutoScalingGroup( ... ) # Allow surfing the (secure) web fleet1.connections.allow_to(ec2.Peer.any_ipv4(), ec2.Port(PortProps(from_port=443, to_port=443))) fleet2 = asg.AutoScalingGroup( ... ) fleet1.connections.allow_from(fleet2, ec2.Port.all_traffic())
Java
import software.amazon.awscdk.services.autoscaling.AutoScalingGroup; import software.amazon.awscdk.services.ec2.Peer; import software.amazon.awscdk.services.ec2.Port; AutoScalingGroup fleet1 = AutoScalingGroup.Builder.create(this, "MyFleet") /* ... */.build(); // Allow surfing the (secure) Web fleet1.getConnections().allowTo(Peer.anyIpv4(), Port.Builder.create().fromPort(443).toPort(443).build()); AutoScalingGroup fleet2 = AutoScalingGroup.Builder.create(this, "MyFleet2") /* ... */.build(); fleet1.getConnections().allowFrom(fleet2, Port.allTraffic());
C#
using cdk = Amazon.CDK; using asg = Amazon.CDK.AWS.AutoScaling; using ec2 = Amazon.CDK.AWS.EC2; // Allow surfing the (secure) Web var fleet1 = new asg.AutoScalingGroup(this, "MyFleet", new asg.AutoScalingGroupProps { /* ... */ }); fleet1.Connections.AllowTo(ec2.Peer.AnyIpv4(), new ec2.Port(new ec2.PortProps { FromPort = 443, ToPort = 443 })); var fleet2 = new asg.AutoScalingGroup(this, "MyFleet2", new asg.AutoScalingGroupProps { /* ... */ }); fleet1.Connections.AllowFrom(fleet2, ec2.Port.AllTraffic());
Go
import ( "github.com/aws/aws-cdk-go/awscdk/v2" "github.com/aws/jsii-runtime-go" autoscaling "github.com/aws/aws-cdk-go/awscdk/v2/awsautoscaling" ec2 "github.com/aws/aws-cdk-go/awscdk/v2/awsec2" ) fleet1 := autoscaling.NewAutoScalingGroup(this, jsii.String("MyFleet1"), &autoscaling.AutoScalingGroupProps{}) fleet1.Connections().AllowTo(ec2.Peer_AnyIpv4(),ec2.NewPort(&ec2.PortProps{ FromPort: jsii.Number(443), ToPort: jsii.Number(443) }),jsii.String("secure web")) fleet2 := autoscaling.NewAutoScalingGroup(this, jsii.String("MyFleet2"), &autoscaling.AutoScalingGroupProps{}) fleet1.Connections().AllowFrom(fleet2, ec2.Port_AllTraffic(),jsii.String("all traffic"))

某些资源具有与之关联的默认端口。示例包括公有端口上负载均衡器的侦听器,以及数据库引擎接受 Amazon RDS 数据库实例连接的端口。在这种情况下,您可以实施严格的网络控制,而无需手动指定端口。为此,请使用 allowDefaultPortFromallowToDefaultPort 方法(Python:allow_default_port_fromallow_to_default_port)。

以下示例显示了如何启用来自任意 IPV4 地址的连接以及启用来自自动扩缩组的连接,以访问某个数据库。

TypeScript
listener.connections.allowDefaultPortFromAnyIpv4('Allow public access'); fleet.connections.allowToDefaultPort(rdsDatabase, 'Fleet can access database');
JavaScript
listener.connections.allowDefaultPortFromAnyIpv4('Allow public access'); fleet.connections.allowToDefaultPort(rdsDatabase, 'Fleet can access database');
Python
listener.connections.allow_default_port_from_any_ipv4("Allow public access") fleet.connections.allow_to_default_port(rds_database, "Fleet can access database")
Java
listener.getConnections().allowDefaultPortFromAnyIpv4("Allow public access"); fleet.getConnections().AllowToDefaultPort(rdsDatabase, "Fleet can access database");
C#
listener.Connections.AllowDefaultPortFromAnyIpv4("Allow public access"); fleet.Connections.AllowToDefaultPort(rdsDatabase, "Fleet can access database");
Go
listener.Connections().AllowDefaultPortFromAnyIpv4(jsii.String("Allow public Access")) fleet.Connections().AllowToDefaultPort(rdsDatabase, jsii.String("Fleet can access database"))

事件处理

有些资源可以充当事件源。使用 addEventNotification 方法(Python:add_event_notification)将事件目标注册到资源发出的特定事件类型。除此之外,addXxxNotification 方法还提供了一种简单的方式来注册常见事件类型的处理程序。

以下示例显示了如何在将对象添加到 Amazon S3 存储桶时触发 Lambda 函数。

TypeScript
import * as s3nots from '@aws-cdk/aws-s3-notifications'; const handler = new lambda.Function(this, 'Handler', { /*…*/ }); const bucket = new s3.Bucket(this, 'Bucket'); bucket.addObjectCreatedNotification(new s3nots.LambdaDestination(handler));
JavaScript
const s3nots = require('@aws-cdk/aws-s3-notifications'); const handler = new lambda.Function(this, 'Handler', { /*…*/ }); const bucket = new s3.Bucket(this, 'Bucket'); bucket.addObjectCreatedNotification(new s3nots.LambdaDestination(handler));
Python
import aws_cdk.aws_s3_notifications as s3_nots handler = lambda_.Function(self, "Handler", ...) bucket = s3.Bucket(self, "Bucket") bucket.add_object_created_notification(s3_nots.LambdaDestination(handler))
Java
import software.amazon.awscdk.services.s3.Bucket; import software.amazon.awscdk.services.lambda.Function; import software.amazon.awscdk.services.s3.notifications.LambdaDestination; Function handler = Function.Builder.create(this, "Handler")/* ... */.build(); Bucket bucket = new Bucket(this, "Bucket"); bucket.addObjectCreatedNotification(new LambdaDestination(handler));
C#
using lambda = Amazon.CDK.AWS.Lambda; using s3 = Amazon.CDK.AWS.S3; using s3Nots = Amazon.CDK.AWS.S3.Notifications; var handler = new lambda.Function(this, "Handler", new lambda.FunctionProps { .. }); var bucket = new s3.Bucket(this, "Bucket"); bucket.AddObjectCreatedNotification(new s3Nots.LambdaDestination(handler));
Go
import ( "github.com/aws/aws-cdk-go/awscdk/v2" "github.com/aws/jsii-runtime-go" s3 "github.com/aws/aws-cdk-go/awscdk/v2/awss3" s3nots "github.com/aws/aws-cdk-go/awscdk/v2/awss3notifications" ) handler := lambda.NewFunction(this, jsii.String("MyFunction"), &lambda.FunctionProps{}) bucket := s3.NewBucket(this, jsii.String("Bucket"), &s3.BucketProps{}) bucket.AddObjectCreatedNotification(s3nots.NewLambdaDestination(handler), nil)

删除策略

维护持久性数据的资源(例如数据库、Amazon S3 存储桶和 Amazon ECR 注册表)都具有删除策略。移除策略指示在包含永久对象的 AWS CDK 堆栈被销毁时是否删除这些对象。指定移除策略的值可通过 AWS CDK core 模块中的RemovalPolicy枚举获得。

注意

除了持久存储数据的资源之外,其他资源还可能具有用于其他目的的 removalPolicy。例如,Lambda 函数版本使用 removalPolicy 属性来确定是否在部署新版本时保留给定版本。与 Amazon S3 存储桶或 DynamoDB 表上的删除策略相比,这些策略具有不同的含义和默认值。

含义

RemovalPolicy.RETAIN

销毁堆栈时保留资源内容(默认)。该资源在堆栈中处于孤立状态,必须手动删除。如果您在资源仍然存在的情况下尝试重新部署堆栈,则您会因名称冲突而收到错误消息。

RemovalPolicy.DESTROY

该资源将随堆栈一起被销毁。

AWS CloudFormation 即使删除政策设置为,也不会移除包含文件的 Amazon S3 存储桶。DESTROY尝试这样做是 AWS CloudFormation 错误的。要让 AWS CDK 在销毁存储桶之前将其从存储桶中删除所有文件,请将存储桶的autoDeleteObjects属性设置为。true

以下是创建 Amazon S3 存储桶的示例,其中 RemovalPolicyDESTROYautoDeleteOjbects 设置为 true

TypeScript
import * as cdk from '@aws-cdk/core'; import * as s3 from '@aws-cdk/aws-s3'; export class CdkTestStack extends cdk.Stack { constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) { super(scope, id, props); const bucket = new s3.Bucket(this, 'Bucket', { removalPolicy: cdk.RemovalPolicy.DESTROY, autoDeleteObjects: true }); } }
JavaScript
const cdk = require('@aws-cdk/core'); const s3 = require('@aws-cdk/aws-s3'); class CdkTestStack extends cdk.Stack { constructor(scope, id, props) { super(scope, id, props); const bucket = new s3.Bucket(this, 'Bucket', { removalPolicy: cdk.RemovalPolicy.DESTROY, autoDeleteObjects: true }); } } module.exports = { CdkTestStack }
Python
import aws_cdk.core as cdk import aws_cdk.aws_s3 as s3 class CdkTestStack(cdk.stack): def __init__(self, scope: cdk.Construct, id: str, **kwargs): super().__init__(scope, id, **kwargs) bucket = s3.Bucket(self, "Bucket", removal_policy=cdk.RemovalPolicy.DESTROY, auto_delete_objects=True)
Java
software.amazon.awscdk.core.*; import software.amazon.awscdk.services.s3.*; public class CdkTestStack extends Stack { public CdkTestStack(final Construct scope, final String id) { this(scope, id, null); } public CdkTestStack(final Construct scope, final String id, final StackProps props) { super(scope, id, props); Bucket.Builder.create(this, "Bucket") .removalPolicy(RemovalPolicy.DESTROY) .autoDeleteObjects(true).build(); } }
C#
using Amazon.CDK; using Amazon.CDK.AWS.S3; public CdkTestStack(Construct scope, string id, IStackProps props) : base(scope, id, props) { new Bucket(this, "Bucket", new BucketProps { RemovalPolicy = RemovalPolicy.DESTROY, AutoDeleteObjects = true }); }
Go
import ( "github.com/aws/aws-cdk-go/awscdk/v2" "github.com/aws/jsii-runtime-go" s3 "github.com/aws/aws-cdk-go/awscdk/v2/awss3" ) s3.NewBucket(this, jsii.String("Bucket"), &s3.BucketProps{ RemovalPolicy: awscdk.RemovalPolicy_DESTROY, AutoDeleteObjects: jsii.Bool(true), })

您也可以通过该applyRemovalPolicy()方法将移除策略直接应用于基础 AWS CloudFormation 资源。此方法适用于某些在其 L2 资源的 props 中没有 removalPolicy 属性的有状态资源。示例包括:

  • AWS CloudFormation 堆栈

  • Amazon Cognito 用户群体

  • Amazon DocumentDB 数据库实例

  • Amazon EC2 卷

  • 亚马逊 OpenSearch 服务域

  • Amazon FSx 文件系统

  • Amazon SQS 队列

TypeScript
const resource = bucket.node.findChild('Resource') as cdk.CfnResource; resource.applyRemovalPolicy(cdk.RemovalPolicy.DESTROY);
JavaScript
const resource = bucket.node.findChild('Resource'); resource.applyRemovalPolicy(cdk.RemovalPolicy.DESTROY);
Python
resource = bucket.node.find_child('Resource') resource.apply_removal_policy(cdk.RemovalPolicy.DESTROY);
Java
CfnResource resource = (CfnResource)bucket.node.findChild("Resource"); resource.applyRemovalPolicy(cdk.RemovalPolicy.DESTROY);
C#
var resource = (CfnResource)bucket.node.findChild('Resource'); resource.ApplyRemovalPolicy(cdk.RemovalPolicy.DESTROY);
注意

AWS CDK 的RemovalPolicy意思是 “。 AWS CloudFormation DeletionPolicy但是, AWS CDK 中的默认设置是保留数据,这与 AWS CloudFormation 默认值相反。