这是 AWS CDK v2 开发者指南。旧版 CDK v1 于 2022 年 6 月 1 日进入维护阶段,并于 2023 年 6 月 1 日终止支持。
本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
资源是您配置为在应用程序 AWS 服务 中使用的资源。资源是的功能 AWS CloudFormation。通过在 AWS CloudFormation 模板中配置资源及其属性,您可以部署 AWS CloudFormation 到以配置资源。使用 AWS Cloud Development Kit (AWS CDK),您可以通过构造配置资源。然后,您部署您的 CDK 应用程序,其中包括合成 AWS CloudFormation 模板并部署 AWS CloudFormation 到以配置您的资源。
使用构造来配置资源
如中所述AWS CDK 构造, AWS CDK 提供了一个丰富的类库,其中包含代表所有 AWS 资源的AWS 构造(称为构造)。
要使用资源对应的构造来创建资源实例,请将作用域作为第一个参数、构造的逻辑 ID 和一组配置属性(props)传入。例如,以下是如何使用构造库中的 SQS .Queue 构造创建带 AWS KMS 加密功能的 Amazon SQUEU 队列。 AWS
import * as sqs from '@aws-cdk/aws-sqs';
new sqs.Queue(this, 'MyQueue', {
encryption: sqs.QueueEncryption.KMS_MANAGED
});
有些配置 props 是可选的,而且在许多情况下具有默认值。在某些情况下,所有 props 都是可选的,最后一个参数可以完全省略。
资源属性
AWS 构造库中的大多数资源都公开属性,这些属性在部署时由解析 AWS CloudFormation。特性以属性的形式在资源类上公开,并以类型名称为前缀。以下示例展示了如何使用 queueUrl
(Python:queue_url
)属性获取 Amazon SQS 队列的 URL。
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
有关如何将部署时属性 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 服务。
const cluster = new ecs.Cluster(this, 'Cluster', { /*...*/ });
const service = new ecs.Ec2Service(this, 'Service', { cluster: cluster });
引用其他堆栈中的资源
您可以引用其他堆栈中的资源,前提是这些资源是在同一应用程序中定义的,并且处于相同的 AWS 环境中。通常使用以下模式:
-
将对构造的引用存储为生成资源的堆栈属性。(要获取对当前构造堆栈的引用,请使用
Stack.of(this)
。) -
将此引用传递给堆栈的构造函数,该构造函数将资源作为参数或属性使用。然后,使用堆栈将其作为属性传递给任何需要它的构造。
以下示例定义了堆栈 stack1
。此堆栈定义了 Amazon S3 存储桶,并将对存储桶构造的引用存储为堆栈的属性。然后,该应用程序定义了第二个堆栈 stack2
,该堆栈在实例化时接受了一个存储桶。例如,stack2
可能定义了一个使用存储桶进行数据存储的 AWS Glue 表。
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
});
如果 AWS CDK 确定资源位于相同的环境中,但位于不同的堆栈中,则它会自动合成生成堆栈中的 AWS CloudFormation 导出和使用堆栈ImportValue中的 Fn::,以将该信息从一个堆栈传输到另一个堆栈。
解决依赖死锁
从一个堆栈引用另一个堆栈的资源会在两个堆栈之间建立依赖关系。这样可以确保堆栈按正确的顺序进行部署。部署堆栈后,这种依赖关系就具体化了。之后,从使用堆栈中删除对共享资源的使用可能会意外导致部署失败。如果两个堆栈之间存在另一种依赖关系,但迫使它们按相同的顺序进行部署,就会发生这种情况。如果只是由 CDK Toolkit 选择首先部署生成堆栈,那么在没有依赖关系时也可能发生这种情况。由于不再需要 AWS CloudFormation 导出,因此已将其从生成堆栈中删除,但是由于尚未部署更新,导出的资源仍在使用堆栈中使用。因此,生产者堆栈会部署失败。
要打破这种死锁,请从使用堆栈中删除对共享资源的使用。(这将从生成堆栈中删除自动导出。) 接下来,使用与自动生成的导出完全相同的逻辑 ID,手动将相同的导出添加到生成堆栈中。删除使用堆栈中共享资源的使用,然后部署两个堆栈。然后删除手动导出(以及不再需要的共享资源),并再次部署两个堆栈。堆栈的 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。
// 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',
});
让我们来详细了解一下 Vpc.fromLookup()
方法。由于 ec2.Vpc
构造很复杂,您可以通过多种方式选择要与 CDK 应用程序一起使用的 VPC。为了解决这个问题,VPC 结构有一个fromLookup
静态方法 (Python:from_lookup
),允许您在综合时通过查询您的 AWS 账户来查找所需的 Amazon VPC。
要使用 Vpc.fromLookup()
,合成堆栈的系统必须有权访问拥有 Amazon VPC 的账户。这是因为 CDK Toolkit 会在合成时查询账户以找到正确的 Amazon VPC。
此外,Vpc.fromLookup()
仅适用于使用明确账户和区域定义的堆栈(请参阅的环境 AWS CDK)。如果 AWS CDK 尝试从与环境无关的堆栈中查找 Amazon VPC,CDK Toolkit 将不知道要查询哪个环境才能找到该 VPC。
您必须提供足以在 AWS
账户中唯一标识 VPC 的 Vpc.fromLookup()
属性。例如,只能有一个默认 VPC,因此将该 VPC 指定为默认 VPC 就足够了。
ec2.Vpc.fromLookup(this, 'DefaultVpc', {
isDefault: true
});
您也可以使用该tags
属性 VPCs 按标签进行查询。在创建 Amazon VPC 时,您可以使用 AWS CloudFormation 或向其添加标签 AWS CDK。创建标签后,您可以随时使用 AWS Management Console AWS CLI、或 AWS SDK 编辑标签。除了您自己添加的任何标签外,还 AWS CDK 会自动将以下标签添加到 VPCs 其创建的所有标签中。
-
名称:VPC 的名称。
-
aws-cdk:subnet-name:子网的名称。
-
aws-cdk:subnet-type:子网类型:公有子网、私有子网或隔离子网。
ec2.Vpc.fromLookup(this, 'PublicVpc',
{tags: {'aws-cdk:subnet-type': "Public"}});
Vpc.fromLookup()
的结果缓存在项目的 cdk.context.json
文件中。(请参见 上下文值和 AWS CDK。) 将此文件提交到版本控制,这样您的应用程序就可以继续引用同一 Amazon VPC。即使您稍后更改了您的属性,从而导致选择 VPCs 了不同的 VPC,这也仍然有效。如果您在无法访问定义VPC的 AWS 账户(例如 CDK Pipelines)的环境中部署堆栈,这一点尤其重要。
尽管你可以在任何使用 AWS CDK 应用程序中定义的类似资源的地方使用外部资源,但你无法对其进行修改。例如,在外部 s3.Bucket
上调用 addToResourcePolicy
(Python:add_to_resource_policy
)不会执行任何操作。
资源物理名称
中资源的逻辑名称不同 AWS CloudFormation 于部署 AWS Management Console 后在中显示的资源名称 AWS CloudFormation。他们 AWS CDK 称这些姓氏为物理名称。
例如, AWS CloudFormation 可能使用逻辑 ID Stack2MyBucket4DD88B4F
和物理名称创建 Amazon S3 存储桶stack2MyBucket4dd88b4f-iuv1rbv9z3to
。
在创建代表资源的构造时,您可以使用属性 Name 指定物理<resourceType>
名称。以下示例创建了物理名称为 amzn-s3-demo-bucket
的 Amazon S3 存储桶。
const bucket = new s3.Bucket(this, 'MyBucket', {
bucketName: 'amzn-s3-demo-bucket',
});
为资源分配物理名称有一些缺点 AWS CloudFormation。最重要的是,如果资源已分配了物理名称,则对需要替换资源的已部署资源进行任何更改(例如更改创建后不可变的资源属性)都将失败。如果您最终处于这种状态,则唯一的解决方案是删除 AWS CloudFormation 堆栈,然后重新部署 AWS CDK 应用程序。有关详细信息,请参阅 AWS CloudFormation 文档。
在某些情况下,例如在创建具有跨环境引用的 AWS CDK 应用程序时,需要物理名称 AWS CDK 才能正常运行。在这些情况下,如果你不想费心自己想出一个真实的名字,你可以让它给你起 AWS CDK 名字。为此,请使用特殊值 PhysicalName.GENERATE_IF_NEEDED
,如下所示。
const bucket = new s3.Bucket(this, 'MyBucket', {
bucketName: core.PhysicalName.GENERATE_IF_NEEDED,
});
传递唯一资源标识符
应尽可能通过引用来传递资源,如上节中所述。但是,在某些情况下,您别无选择,只能通过资源的某个属性来引用该资源。以下是使用案例示例:
-
当你使用低级 AWS CloudFormation 资源时。
-
当您需要向 AWS CDK 应用程序的运行时组件公开资源时,例如通过环境变量引用 Lambda 函数时。
这些标识符可用作资源的属性,如下所示。
bucket.bucketName lambdaFunc.functionArn securityGroup.groupArn
以下示例说明如何将生成的存储桶名称传递给 AWS Lambda 函数。
const bucket = new s3.Bucket(this, 'Bucket');
new lambda.Function(this, 'MyLambda', {
// ...
environment: {
BUCKET_NAME: bucket.bucketName,
},
});
在资源之间授予权限
更高级别的结构通过提供简单的、基于意图 APIs 的表达权限要求来实现最低权限权限。例如,许多 L2 构造都提供了授权方法,您可以使用这些方法向实体(例如 IAM 角色或用户)授予使用资源的权限,而无需手动创建 IAM 权限声明。
以下示例创建了权限以允许 Lambda 函数的执行角色读取对象并将其写入特定 Amazon S3 存储桶。如果 Amazon S3 存储桶使用 AWS KMS 密钥加密,则此方法还会向 Lambda 函数的执行角色授予使用该密钥进行解密的权限。
if (bucket.grantReadWrite(func).success) {
// ...
}
授权方法会返回一个 iam.Grant
对象。使用 Grant
对象的 success
属性来确定是否有效应用了授权(例如,其可能尚未应用于外部资源)。您也可以使用 Grant
对象的 assertSuccess
(Python:assert_success
)方法来强制执行授权已成功应用。
如果特定的用例没有可用的特定授权方法,则可以使用通用的授权方法,通过指定的操作列表来定义新的授权。
以下示例显示了如何授予 Lambda 函数对 Amazon DynamoDB CreateBackup
操作的访问权限。
table.grant(func, 'dynamodb:CreateBackup');
许多资源(例如 Lambda 函数)都需要在执行代码时承担角色。配置属性让您能够指定 iam.IRole
。如果未指定角色,则该函数会自动创建一个专门用于此用途的角色。然后您可以对资源使用授权方法,以向该角色添加语句。
授予方法是使用较低级别构建的, APIs 用于处理 IAM 策略。策略被建模为PolicyDocument对象。使用 addToRolePolicy
方法(Python:add_to_role_policy
)将语句直接添加到角色(或构造的附加角色),或者使用 addToResourcePolicy
(Python:add_to_resource_policy
)方法将语句添加到资源的策略(例如 Bucket
策略)中。
资源指标和警报
许多资源会发出可用于设置监控仪表板和警报的 CloudWatch 指标。更高级别的构造具备指标方法,允许您访问指标而无需查找要使用的正确名称。
以下示例显示了如何定义当 Amazon SQS 队列的 ApproximateNumberOfMessagesNotVisible
超过 100 时的警报。
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,
// ...
});
如果没有针对特定指标的方法,则可以使用通用指标方法来手动指定指标名称。
也可以将指标添加到 CloudWatch 仪表板中。请参阅 CloudWatch。
网络流量
在许多情况下,您必须启用网络权限才能使应用程序正常运行,例如当计算基础设施需要访问持久层时。建立或侦听连接的资源会暴露支持流量的方法,包括设置安全组规则或网络 ACLs。
IConnectable资源有一个connections
属性,即网络流量规则配置的网关。
您可以使用 allow
方法让数据能够在给定的网络路径上流动。以下示例启用与网络的 HTTPS 连接以及来自 Amazon A EC2 uto Scaling 组的传入连接fleet2
。
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());
某些资源具有与之关联的默认端口。示例包括公有端口上负载均衡器的侦听器,以及数据库引擎接受 Amazon RDS 数据库实例连接的端口。在这种情况下,您可以实施严格的网络控制,而无需手动指定端口。为此,请使用 allowDefaultPortFrom
和 allowToDefaultPort
方法(Python:allow_default_port_from
、allow_to_default_port
)。
以下示例说明如何启用来自任意 IPV4 地址的连接,以及如何启用来自 Auto Scaling 组的连接以访问数据库。
listener.connections.allowDefaultPortFromAnyIpv4('Allow public access');
fleet.connections.allowToDefaultPort(rdsDatabase, 'Fleet can access database');
事件处理
有些资源可以充当事件源。使用 addEventNotification
方法(Python:add_event_notification
)将事件目标注册到资源发出的特定事件类型。除此之外,addXxxNotification
方法还提供了一种简单的方式来注册常见事件类型的处理程序。
以下示例显示了如何在将对象添加到 Amazon S3 存储桶时触发 Lambda 函数。
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));
删除策略
维护持久性数据的资源(例如数据库、Amazon S3 存储桶和 Amazon ECR 注册表)都具有删除策略。删除策略用于指示在包含持久对象的 AWS CDK
堆栈被销毁时是否删除这些对象。指定删除策略的值可通过 AWS CDK core
模块中的RemovalPolicy
枚举获得。
注意
除了持久存储数据的资源之外,其他资源还可能具有用于其他目的的 removalPolicy
。例如,Lambda 函数版本使用 removalPolicy
属性来确定是否在部署新版本时保留给定版本。与 Amazon S3 存储桶或 DynamoDB 表上的删除策略相比,这些策略具有不同的含义和默认值。
值 | 含义 |
---|---|
|
销毁堆栈时保留资源内容(默认)。该资源在堆栈中处于孤立状态,必须手动删除。如果您在资源仍然存在的情况下尝试重新部署堆栈,则您会因名称冲突而收到错误消息。 |
|
该资源将随堆栈一起被销毁。 |
AWS CloudFormation 不会移除包含文件的 Amazon S3 存储桶,即使其删除策略设置为。DESTROY
尝试这样做是 AWS CloudFormation 错误的。要在销毁存储桶之前从存储桶中 AWS CDK 删除所有文件,请将存储桶的autoDeleteObjects
属性设置为true
。
以下是创建 Amazon S3 存储桶的示例,其中 RemovalPolicy
为 DESTROY
且 autoDeleteOjbects
设置为 true
。
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
});
}
}
您也可以通过applyRemovalPolicy()
方法将移除策略直接应用于底层 AWS CloudFormation 资源。此方法适用于某些在其 L2 资源的 props 中没有 removalPolicy
属性的有状态资源。示例包括:
-
AWS CloudFormation 堆栈
-
Amazon Cognito 用户群体
-
Amazon DocumentDB 数据库实例
-
亚马逊 EC2 交易量
-
亚马逊 OpenSearch 服务域名
-
亚马逊 FSx 文件系统
-
Amazon SQS 队列
const resource = bucket.node.findChild('Resource') as cdk.CfnResource;
resource.applyRemovalPolicy(cdk.RemovalPolicy.DESTROY);
注意
AWS CDK's RemovalPolicy
翻译为 AWS CloudFormation's。DeletionPolicy
但是,中的默认设置 AWS CDK 是保留数据,这与 AWS CloudFormation 默认值相反。