这是 AWS CDK v2 开发者指南。旧版 CDK v1 于 2022 年 6 月 1 日进入维护阶段,并于 2023 年 6 月 1 日终止支持。
本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
AWS CDK 构造
构造是 C AWS loud Development Kit (AWS CDK) 应用程序的基本构建块。构造是应用程序中的一个组件,它代表一个或多个 AWS CloudFormation 资源及其配置。您可以通过导入和配置构造逐步构建应用程序。
导入和使用构造
构造是您从 AWS 构造库中导入到 CDK 应用程序中的类。您也可以创建和分发自己的构造,或者使用第三方开发人员创建的构造。
构造是构造编程模型(CPM)的一部分。它们可以与其他工具一起使用,例如 CDK for Terraform (CDKtf)、CDK for Kubernetes (CDK8s) 和。Projen
许多第三方也发布了与 AWS CDK 兼容的构造。访问 C onstru ct Hub,探索 AWS CDK 构建合作伙伴生态系统。
构造级别
构造库中的 AWS 构造分为三个级别。每个级别都提供不断提高的抽象级别。抽象越高,配置越容易,所需的专业知识也越少。抽象越低,可用的自定义越多,需要更多的专业知识。
- 1 级 (L1) 构造
-
L1 构造,也称为 CFN 资源,是最低级别的构造,不提供抽象。每个 L1 构造都直接映射到单个 AWS CloudFormation 资源。使用 L1 构造,您可以导入代表特定 AWS CloudFormation 资源的构造。然后,您可以在构造实例中定义资源的属性。
当您熟悉 AWS CloudFormation 并需要完全控制 AWS 资源属性的定义时,L1 结构非常适合使用。
在 AWS 构造库中,L1 构造以开头命名Cfn,后面是它所代表的 AWS CloudFormation 资源的标识符。例如,该CfnBucket构造是代表 AWS::S3::Bucket AWS CloudFormation 资源的 L1 构造。
L1 构造是由 AWS CloudFormation 资源规范生成的。如果资源存在于 AWS CloudFormation,则该资源将作为 L1 构造在 AWS CDK 中可用。新资源或属性可能需要长达一周的时间才能在 Construct Librar AWS y 中发布。有关更多信息,请参阅《 AWS CloudFormation 用户指南》中的AWS 资源和属性类型参考。
- 2 级 (L2) 构造
-
L2 构造,也称为精选构造,由 CDK 团队精心开发,通常是使用最广泛的构造类型。L2 构造直接映射到单个 AWS CloudFormation 资源,类似于 L1 构造。与 L1 构造相比,L2 构造通过直观的基于意图的 API 提供更高级别的抽象。L2 构造包括合理的默认属性配置、最佳实践安全策略,并为您生成大量样板代码和粘合逻辑。
L2 构造还为大多数资源提供助手方法,使定义属性、权限、资源之间基于事件的交互等变得更加简单快捷。其中许多功能也可以作为名为 Mixins 的独立构建块使用,可以使用该方法将其应用于 L1 和 L2 构造。.with()
s3.Bucket 类是 Amazon Simple Storage Service(Amazon S3)存储桶资源的 L2 构造示例。
AWS 构造库包含指定为稳定且可供生产使用的 L2 构造。对于正在开发的 L2 构造,它们被指定为实验性质,并在单独的模块中提供。
- 3 级 (L3) 构造
-
L3 构造,也称为模式,是最高级别的抽象。每个 L3 构造可以包含一组资源,这些资源配置为协同工作以完成应用程序中的特定任务或服务。L3 结构用于为应用程序中的特定用例创建整个 AWS 架构。
为了提供完整的系统设计或大型系统的重要组成部分,L3 构造可提供有主见的默认属性配置。它们围绕旨在解决问题和提供解决方案的特定方法而构建。通过 L3 构造,您可以用最少的输入和代码快速创建和配置多个资源。
该ecsPatterns.ApplicationLoadBalancedFargateService类是 L3 结构的示例,该结构表示在亚马逊弹性容器服务 (Amazon ECS) Service 集群上运行的 Fargate 服务,前面是应用程序负载均衡器。 AWS
与 L2 构造类似,可供生产使用的 L3 构造包含在构造库中。 AWS 正在开发的此类构造以单独的模块提供。
定义构造
合成
合成是通过构造定义更高级别抽象的关键模式。高级构造可以由任意数量的较低级别的构造合成。从自下而上的角度来看,您可以使用构造来组织要 AWS 部署的各个资源。您可以根据自身需求使用任何抽象和任意数量的级别。
通过合成,您可以定义可重用的组件,并像共享任何其他代码一样共享它们。例如,团队可以定义一种构造,用于实现公司对 Amazon DynamoDB 表的最佳实践,包括备份、全局复制、自动扩缩和监控。团队可以在内部与其他团队共享构造,也可以公开共享。
团队可以像使用任何其他库包一样使用构造。与任何其他代码库类似,库更新后,开发人员可以访问新版本的改进和错误修复。
初始化
构造是在扩展 Construct 基类的类中实现的。您可以通过实例化类定义构造。所有构造在初始化时都有三个参数:
-
作用域:构造的父级或所有者。这可以是堆栈或其他构造。作用域决定构造在构造树中的位置。通常,您必须传递 this(在 Python 中传递 self),它表示当前对象为作用域。
-
id:在此作用域内必须唯一的标识符。该标识符用作构造中定义的所有内容的命名空间。它用于生成唯一标识符,例如资源名称和 AWS CloudFormation 逻辑 IDs。
标识符只需要在作用域内唯一。这使您可以实例化和重用构造,而不必担心它们可能包含的构造和标识符,并且可以将构造组合成更高级别的抽象。此外,通过作用域,一次性引用一组构造成为可能。示例包括标记或指定将构造部署到的位置。
-
props:定义构造的初始配置的一组属性或关键字参数,视语言而定。更高级别的构造可提供更多的默认值,如果所有 prop 元素都是可选的,则可以完全省略 props 参数。
配置
大多数构造都接受定义构造配置的 name/value 集合props作为其第三个参数(或者在 Python 中为关键字参数)。以下示例定义了一个启用了 AWS 密钥管理服务 (AWS KMS) 加密和静态网站托管的存储桶。由于它没有显式指定加密密钥,因此 Bucket 构造会定义一个新的 kms.Key 并将其与存储桶相关联。
例
- TypeScript
-
new s3.Bucket(this, 'MyEncryptedBucket', {
encryption: s3.BucketEncryption.KMS,
websiteIndexDocument: 'index.html'
});
- JavaScript
-
new s3.Bucket(this, 'MyEncryptedBucket', {
encryption: s3.BucketEncryption.KMS,
websiteIndexDocument: 'index.html'
});
- Python
-
s3.Bucket(self, "MyEncryptedBucket", encryption=s3.BucketEncryption.KMS,
website_index_document="index.html")
- Java
-
Bucket.Builder.create(this, "MyEncryptedBucket")
.encryption(BucketEncryption.KMS_MANAGED)
.websiteIndexDocument("index.html").build();
- C#
-
new Bucket(this, "MyEncryptedBucket", new BucketProps
{
Encryption = BucketEncryption.KMS_MANAGED,
WebsiteIndexDocument = "index.html"
});
- Go
-
awss3.NewBucket(stack, jsii.String("MyEncryptedBucket"), &awss3.BucketProps{
Encryption: awss3.BucketEncryption_KMS,
WebsiteIndexDocument: jsii.String("index.html"),
})
与构造互动
构造是在扩展 Construct 基类的类中实现的。实例化构造后,构造对象会公开一组方法和属性,供您用于与该构造进行交互并将其作为对系统其他部分的引用传递。
AWS CDK 框架对构造没有任何限制 APIs 。作者可以定义他们想要的任何 API。但是, AWS 构造库中包含的 AWS 构造(例如s3.Bucket)遵循准则和常见模式。这为所有 AWS 资源提供了一致的体验。
大多数 AWS 结构都有一组授权方法,您可以使用这些方法向委托人授予该构造的 AWS 身份和访问管理 (IAM) 权限。以下示例会向 IAM 组 data-science 授予从 Amazon S3 存储桶 raw-data 中读取数据的权限。
例
- TypeScript
-
const rawData = new s3.Bucket(this, 'raw-data');
const dataScience = new iam.Group(this, 'data-science');
rawData.grants.read(dataScience);
- JavaScript
-
const rawData = new s3.Bucket(this, 'raw-data');
const dataScience = new iam.Group(this, 'data-science');
rawData.grants.read(dataScience);
- Python
-
raw_data = s3.Bucket(self, 'raw-data')
data_science = iam.Group(self, 'data-science')
raw_data.grants.read(data_science)
- Java
-
Bucket rawData = new Bucket(this, "raw-data");
Group dataScience = new Group(this, "data-science");
rawData.getGrants().read(dataScience);
- C#
-
var rawData = new Bucket(this, "raw-data");
var dataScience = new Group(this, "data-science");
rawData.Grants.Read(dataScience);
- Go
-
rawData := awss3.NewBucket(stack, jsii.String("raw-data"), nil)
dataScience := awsiam.NewGroup(stack, jsii.String("data-science"), nil)
rawData.Grants().Read(dataScience, nil)
另一种常见的模式是 AWS 构造根据其他地方提供的数据设置资源的一个属性。属性可以包括 Amazon 资源名称 (ARNs)、名称或 URLs。
以下代码定义了一个 AWS Lambda 函数,并通过环境变量中队列的 URL 将其与亚马逊简单队列服务 (Amazon SQS) Simple Queue Service 队列相关联。
例
- TypeScript
-
const jobsQueue = new sqs.Queue(this, 'jobs');
const createJobLambda = new lambda.Function(this, 'create-job', {
runtime: lambda.Runtime.NODEJS_18_X,
handler: 'index.handler',
code: lambda.Code.fromAsset('./create-job-lambda-code'),
environment: {
QUEUE_URL: jobsQueue.queueUrl
}
});
- JavaScript
-
const jobsQueue = new sqs.Queue(this, 'jobs');
const createJobLambda = new lambda.Function(this, 'create-job', {
runtime: lambda.Runtime.NODEJS_18_X,
handler: 'index.handler',
code: lambda.Code.fromAsset('./create-job-lambda-code'),
environment: {
QUEUE_URL: jobsQueue.queueUrl
}
});
- Python
-
jobs_queue = sqs.Queue(self, "jobs")
create_job_lambda = lambda_.Function(self, "create-job",
runtime=lambda_.Runtime.NODEJS_18_X,
handler="index.handler",
code=lambda_.Code.from_asset("./create-job-lambda-code"),
environment=dict(
QUEUE_URL=jobs_queue.queue_url
)
)
- Java
-
final Queue jobsQueue = new Queue(this, "jobs");
Function createJobLambda = Function.Builder.create(this, "create-job")
.handler("index.handler")
.code(Code.fromAsset("./create-job-lambda-code"))
.environment(java.util.Map.of( // Map.of is Java 9 or later
"QUEUE_URL", jobsQueue.getQueueUrl()))
.build();
- C#
-
var jobsQueue = new Queue(this, "jobs");
var createJobLambda = new Function(this, "create-job", new FunctionProps
{
Runtime = Runtime.NODEJS_18_X,
Handler = "index.handler",
Code = Code.FromAsset(@".\create-job-lambda-code"),
Environment = new Dictionary<string, string>
{
["QUEUE_URL"] = jobsQueue.QueueUrl
}
});
- Go
-
createJobLambda := awslambda.NewFunction(stack, jsii.String("create-job"), &awslambda.FunctionProps{
Runtime: awslambda.Runtime_NODEJS_18_X(),
Handler: jsii.String("index.handler"),
Code: awslambda.Code_FromAsset(jsii.String(".\\create-job-lambda-code"), nil),
Environment: &map[string]*string{
"QUEUE_URL": jsii.String(*jobsQueue.QueueUrl()),
},
})
有关 AWS 构造库中最常见的 API 模式的信息,请参阅资源和 AWS CDK。
使用 Mixins 添加功能
Mixin 是可组合功能,您可以使用该方法将其应用于任何构造。.with()Mixins 允许您为 L1 和 L2 构造添加功能,而不必使用不同的构造或编写低级代码。
例如,您可以在 Amazon S3 存储桶(无论是 L1 还是 L2CfnBucket)上启用版本控制并阻止公开访问:Bucket
例
- TypeScript
-
import * as cdk from 'aws-cdk-lib';
import * as s3 from 'aws-cdk-lib/aws-s3';
// Apply mixins to an L1 construct
new s3.CfnBucket(this, 'MyBucket')
.with(new s3.mixins.BucketVersioning())
.with(new s3.mixins.BucketBlockPublicAccess());
// Apply mixins to an L2 construct
new s3.Bucket(this, 'MyL2Bucket', { removalPolicy: cdk.RemovalPolicy.DESTROY })
.with(new s3.mixins.BucketAutoDeleteObjects());
- JavaScript
-
const cdk = require('aws-cdk-lib');
const s3 = require('aws-cdk-lib/aws-s3');
// Apply mixins to an L1 construct
new s3.CfnBucket(this, 'MyBucket')
.with(new s3.mixins.BucketVersioning())
.with(new s3.mixins.BucketBlockPublicAccess());
// Apply mixins to an L2 construct
new s3.Bucket(this, 'MyL2Bucket', { removalPolicy: cdk.RemovalPolicy.DESTROY })
.with(new s3.mixins.BucketAutoDeleteObjects());
- Python
-
import aws_cdk as cdk
import aws_cdk.aws_s3 as s3
# Apply mixins to an L1 construct
s3.CfnBucket(self, "MyBucket") \
.with_(s3.mixins.BucketVersioning()) \
.with_(s3.mixins.BucketBlockPublicAccess())
# Apply mixins to an L2 construct
s3.Bucket(self, "MyL2Bucket", removal_policy=cdk.RemovalPolicy.DESTROY) \
.with_(s3.mixins.BucketAutoDeleteObjects())
- Java
-
import software.amazon.awscdk.*;
import software.amazon.awscdk.services.s3.*;
// Apply mixins to an L1 construct
CfnBucket bucket = new CfnBucket(this, "MyBucket");
bucket.with(new BucketVersioning());
bucket.with(new BucketBlockPublicAccess());
// Apply mixins to an L2 construct
Bucket l2Bucket = Bucket.Builder.create(this, "MyL2Bucket")
.removalPolicy(RemovalPolicy.DESTROY)
.build();
l2Bucket.with(new BucketAutoDeleteObjects());
- C#
-
using Amazon.CDK;
using Amazon.CDK.AWS.S3;
// Apply mixins to an L1 construct
var bucket = new CfnBucket(this, "MyBucket");
bucket.With(new BucketVersioning());
bucket.With(new BucketBlockPublicAccess());
// Apply mixins to an L2 construct
var l2Bucket = new Bucket(this, "MyL2Bucket", new BucketProps
{
RemovalPolicy = RemovalPolicy.DESTROY
});
l2Bucket.With(new BucketAutoDeleteObjects());
- Go
-
bucket := awss3.NewCfnBucket(stack, jsii.String("MyBucket"), nil)
bucket.With(awss3.NewBucketVersioning())
bucket.With(awss3.NewBucketBlockPublicAccess())
l2Bucket := awss3.NewBucket(stack, jsii.String("MyL2Bucket"), &awss3.BucketProps{
RemovalPolicy: awscdk.RemovalPolicy_DESTROY,
})
l2Bucket.With(awss3.NewBucketAutoDeleteObjects())
Mixin 可通过每个服务模块的mixins命名空间获得(例如,s3.mixins)。每个 mixin 都以特定的资源类型为目标,并以该资源命名。当你将 mixin 应用于 L2 构造时,它会自动应用于底层 L1 资源。
有关 Mixins 的更多信息,请参阅 Mi x ins。
应用程序和堆栈构造
AWS 构造库中的App和Stack类是唯一的构造。与其他结构相比,它们不会自行配置 AWS 资源。但可用于为其他构造提供上下文。所有代表 AWS 资源的构造都必须在Stack构造的范围内直接或间接地定义。 Stack构造是在App构造的范围内定义的。
要了解有关 CDK 应用程序的更多信息,请参阅 AWS CDK 应用程序。要了解有关 CDK 堆栈的更多信息,请参阅 AWS CDK 堆栈简介。
以下示例会定义具有单个堆栈的应用程序。在堆栈中,L2 构造可用于配置 Amazon S3 存储桶资源。
例
- TypeScript
-
import { App, Stack, StackProps } from 'aws-cdk-lib';
import * as s3 from 'aws-cdk-lib/aws-s3';
class HelloCdkStack extends Stack {
constructor(scope: App, id: string, props?: StackProps) {
super(scope, id, props);
new s3.Bucket(this, 'MyFirstBucket', {
versioned: true
});
}
}
const app = new App();
new HelloCdkStack(app, "HelloCdkStack");
- JavaScript
-
const { App , Stack } = require('aws-cdk-lib');
const s3 = require('aws-cdk-lib/aws-s3');
class HelloCdkStack extends Stack {
constructor(scope, id, props) {
super(scope, id, props);
new s3.Bucket(this, 'MyFirstBucket', {
versioned: true
});
}
}
const app = new App();
new HelloCdkStack(app, "HelloCdkStack");
- Python
-
from aws_cdk import App, Stack
import aws_cdk.aws_s3 as s3
from constructs import Construct
class HelloCdkStack(Stack):
def __init__(self, scope: Construct, id: str, **kwargs) -> None:
super().__init__(scope, id, **kwargs)
s3.Bucket(self, "MyFirstBucket", versioned=True)
app = App()
HelloCdkStack(app, "HelloCdkStack")
- Java
-
HelloCdkStack.java 文件中定义的堆栈:
import software.constructs.Construct;
import software.amazon.awscdk.Stack;
import software.amazon.awscdk.StackProps;
import software.amazon.awscdk.services.s3.*;
public class HelloCdkStack extends Stack {
public HelloCdkStack(final Construct scope, final String id) {
this(scope, id, null);
}
public HelloCdkStack(final Construct scope, final String id, final StackProps props) {
super(scope, id, props);
Bucket.Builder.create(this, "MyFirstBucket")
.versioned(true).build();
}
}
HelloCdkApp.java 文件中定义的应用程序:
import software.amazon.awscdk.App;
import software.amazon.awscdk.StackProps;
public class HelloCdkApp {
public static void main(final String[] args) {
App app = new App();
new HelloCdkStack(app, "HelloCdkStack", StackProps.builder()
.build());
app.synth();
}
}
- C#
-
using Amazon.CDK;
using Amazon.CDK.AWS.S3;
namespace HelloCdkApp
{
internal static class Program
{
public static void Main(string[] args)
{
var app = new App();
new HelloCdkStack(app, "HelloCdkStack");
app.Synth();
}
}
public class HelloCdkStack : Stack
{
public HelloCdkStack(Construct scope, string id, IStackProps props=null) : base(scope, id, props)
{
new Bucket(this, "MyFirstBucket", new BucketProps { Versioned = true });
}
}
}
- Go
-
func NewHelloCdkStack(scope constructs.Construct, id string, props *HelloCdkStackProps) awscdk.Stack {
var sprops awscdk.StackProps
if props != nil {
sprops = props.StackProps
}
stack := awscdk.NewStack(scope, &id, &sprops)
awss3.NewBucket(stack, jsii.String("MyFirstBucket"), &awss3.BucketProps{
Versioned: jsii.Bool(true),
})
return stack
}
使用构造
使用 L1 构造
L1 构造直接映射到各个 AWS CloudFormation 资源。您必须提供资源所需的配置。
在本例中,我们使用 CfnBucket L1 构造创建一个 bucket 对象:
例
- TypeScript
-
const bucket = new s3.CfnBucket(this, "amzn-s3-demo-bucket", {
bucketName: "amzn-s3-demo-bucket"
});
- JavaScript
-
const bucket = new s3.CfnBucket(this, "amzn-s3-demo-bucket", {
bucketName: "amzn-s3-demo-bucket"
});
- Python
-
bucket = s3.CfnBucket(self, "amzn-s3-demo-bucket", bucket_name="amzn-s3-demo-bucket")
- Java
-
CfnBucket bucket = new CfnBucket.Builder().bucketName("amzn-s3-demo-bucket").build();
- C#
-
var bucket = new CfnBucket(this, "amzn-s3-demo-bucket", new CfnBucketProps
{
BucketName= "amzn-s3-demo-bucket"
});
- Go
-
awss3.NewCfnBucket(stack, jsii.String("amzn-s3-demo-bucket"), &awss3.CfnBucketProps{
BucketName: jsii.String("amzn-s3-demo-bucket"),
})
不是简单布尔值、字符串、数字或容器的构造属性在受支持的语言中的处理方式有所不同。
例
- TypeScript
-
const bucket = new s3.CfnBucket(this, "amzn-s3-demo-bucket", {
bucketName: "amzn-s3-demo-bucket",
corsConfiguration: {
corsRules: [{
allowedOrigins: ["*"],
allowedMethods: ["GET"]
}]
}
});
- JavaScript
-
const bucket = new s3.CfnBucket(this, "amzn-s3-demo-bucket", {
bucketName: "amzn-s3-demo-bucket",
corsConfiguration: {
corsRules: [{
allowedOrigins: ["*"],
allowedMethods: ["GET"]
}]
}
});
- Python
-
在 Python 中,这些属性由定义为 L1 构造内部类的类型表示。例如,CfnBucket 的可选属性 cors_configuration 需要一个 CfnBucket.CorsConfigurationProperty 类型的封装器。在本例中,我们将在一个 CfnBucket 实例上定义 cors_configuration。
bucket = CfnBucket(self, "amzn-s3-demo-bucket", bucket_name="amzn-s3-demo-bucket",
cors_configuration=CfnBucket.CorsConfigurationProperty(
cors_rules=[CfnBucket.CorsRuleProperty(
allowed_origins=["*"],
allowed_methods=["GET"]
)]
)
)
- Java
-
在 Java 中,这些属性由定义为 L1 构造内部类的类型表示。例如,CfnBucket 的可选属性 corsConfiguration 需要一个 CfnBucket.CorsConfigurationProperty 类型的封装器。在本例中,我们将在一个 CfnBucket 实例上定义 corsConfiguration。
CfnBucket bucket = CfnBucket.Builder.create(this, "amzn-s3-demo-bucket")
.bucketName("amzn-s3-demo-bucket")
.corsConfiguration(new CfnBucket.CorsConfigurationProperty.Builder()
.corsRules(Arrays.asList(new CfnBucket.CorsRuleProperty.Builder()
.allowedOrigins(Arrays.asList("*"))
.allowedMethods(Arrays.asList("GET"))
.build()))
.build())
.build();
- C#
-
在 C# 中,这些属性由定义为 L1 构造内部类的类型表示。例如,CfnBucket 的可选属性 CorsConfiguration 需要一个 CfnBucket.CorsConfigurationProperty 类型的封装器。在本例中,我们将在一个 CfnBucket 实例上定义 CorsConfiguration。
var bucket = new CfnBucket(this, "amzn-s3-demo-bucket", new CfnBucketProps
{
BucketName = "amzn-s3-demo-bucket",
CorsConfiguration = new CfnBucket.CorsConfigurationProperty
{
CorsRules = new object[] {
new CfnBucket.CorsRuleProperty
{
AllowedOrigins = new string[] { "*" },
AllowedMethods = new string[] { "GET" },
}
}
}
});
- Go
-
在 Go 中,这些类型是使用 L1 构造的名称、下划线和属性名称命名的。例如,CfnBucket 的可选属性 CorsConfiguration 需要一个 CfnBucket_CorsConfigurationProperty 类型的封装器。在本例中,我们将在一个 CfnBucket 实例上定义 CorsConfiguration。
awss3.NewCfnBucket(stack, jsii.String("amzn-s3-demo-bucket"), &awss3.CfnBucketProps{
BucketName: jsii.String("amzn-s3-demo-bucket"),
CorsConfiguration: &awss3.CfnBucket_CorsConfigurationProperty{
CorsRules: []awss3.CorsRule{
awss3.CorsRule{
AllowedOrigins: jsii.Strings("*"),
AllowedMethods: &[]awss3.HttpMethods{"GET"},
},
},
},
})
您不能将 L2 属性类型与 L1 构造一起使用,反之亦然。使用 L1 构造时,请务必使用为正在使用的 L1 构造定义的类型。请勿使用其他 L1 构造中的类型(有些可能具有相同的名称,但类型不同)。
目前,一些特定于语言的 API 引用在指向 L1 属性类型的路径中存在错误,或者根本没有记录这些类。我们希望尽快解决这个问题。同时,请记住,这些类型始终是与之一起使用的 L1 构造的内部类。
从其他构造中引用资源
在配置引用其他 AWS 资源的构造属性时,您有两个等效的选项:
使用字符串引用
您可以随时传递显式字符串值 ARNs,例如名称或其他资源标识符。这种方法适用于所有属性,对于复杂对象中的嵌套属性也是必需的。
以下示例使用 L1 构造 (CfnFunction) 创建 Lambda 函数,其角色使用 L2 构造 () 进行定义。Role角色的 ARN 将传递给该属性:role
例
- TypeScript
-
const role = new iam.Role(this, 'MyRole', {
assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),
managedPolicies: [
iam.ManagedPolicy.fromAwsManagedPolicyName(
'service-role/AWSLambdaBasicExecutionRole'
),
],
});
const myFunction = new lambda.CfnFunction(this, 'HelloWorldFunction', {
runtime: 'nodejs24.x',
role: role.roleArn, // Pass the ARN string explicitly
handler: 'index.handler',
code: {
zipFile: `
exports.handler = async function(event) {
return {
statusCode: 200,
body: JSON.stringify('Hello World!'),
};
};
`}
});
- JavaScript
-
const role = new iam.Role(this, 'MyRole', {
assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),
managedPolicies: [
iam.ManagedPolicy.fromAwsManagedPolicyName(
'service-role/AWSLambdaBasicExecutionRole'
)
]
});
const myFunction = new lambda.CfnFunction(this, "HelloWorldFunction", {
runtime: 'nodejs24.x',
role: role.roleArn, // Pass the ARN string explicitly
handler: 'index.handler',
code: {
zipFile: `
exports.handler = async function(event) {
return {
statusCode: 200,
body: JSON.stringify('Hello World!'),
};
};
`}
});
- Python
-
role = iam.Role(self, "MyRole",
assumed_by=iam.ServicePrincipal("lambda.amazonaws.com"),
managed_policies=[
iam.ManagedPolicy.from_aws_managed_policy_name(
"service-role/AWSLambdaBasicExecutionRole"
)
]
)
my_function = _lambda.CfnFunction(self, "HelloWorldFunction",
runtime="nodejs24.x",
role=role.role_arn, # Pass the ARN string explicitly
handler="index.handler",
code=_lambda.CfnFunction.CodeProperty(
zip_file=
"""
exports.handler = async function(event) {
return {
statusCode: 200,
body: JSON.stringify('Hello World!'),
};
};
"""
)
)
- Java
-
Role role = Role.Builder.create(this, "MyRole")
.assumedBy(new ServicePrincipal("lambda.amazonaws.com"))
.managedPolicies(Arrays.asList(
ManagedPolicy.fromAwsManagedPolicyName(
"service-role/AWSLambdaBasicExecutionRole"
)
))
.build();
CfnFunction myFunction = CfnFunction.Builder.create(this, "HelloWorldFunction")
.runtime("nodejs24.x")
.role(role.getRoleArn()) // Pass the ARN string explicitly
.handler("index.handler")
.code(CfnFunction.CodeProperty.builder()
.zipFile(
"exports.handler = async function(event) {" +
" return {" +
" statusCode: 200," +
" body: JSON.stringify('Hello World!')," +
" };" +
"};")
.build())
.build();
- C#
-
var role = new Role(this, "MyRole", new RoleProps
{
AssumedBy = new ServicePrincipal("lambda.amazonaws.com"),
ManagedPolicies = new[]
{
ManagedPolicy.FromAwsManagedPolicyName(
"service-role/AWSLambdaBasicExecutionRole"
)
}
});
var myFunction = new CfnFunction(this, "HelloWorldFunction", new CfnFunctionProps
{
Runtime = "nodejs24.x",
Role = role.RoleArn, // Pass the ARN string explicitly
Handler = "index.handler",
Code = new CfnFunction.CodeProperty
{
ZipFile = @"
exports.handler = async function(event) {
return {
statusCode: 200,
body: JSON.stringify('Hello World!'),
};
};
"
}
});
- Go
-
role := awsiam.NewRole(stack, jsii.String("MyRole"), &awsiam.RoleProps{
AssumedBy: awsiam.NewServicePrincipal(jsii.String("lambda.amazonaws.com"), nil),
ManagedPolicies: &[]awsiam.IManagedPolicy{
awsiam.ManagedPolicy_FromAwsManagedPolicyName(jsii.String("service-role/AWSLambdaBasicExecutionRole")),
},
})
myFunction := awslambda.NewCfnFunction(stack, jsii.String("HelloWorldFunction"), &awslambda.CfnFunctionProps{
Runtime: jsii.String("nodejs24.x"),
Role: role.RoleArn(), // Pass the ARN string explicitly
Handler: jsii.String("index.handler"),
Code: &awslambda.CfnFunction_CodeProperty{
ZipFile: jsii.String(`
exports.handler = async function(event) {
return {
statusCode: 200,
body: JSON.stringify('Hello World!'),
};
};
`),
},
})
使用对象引用
对于选定的属性,您可以直接传递构造对象,而不必手动提取其属性。对对象引用的支持因属性而异,并且随着时间的推移可能会随着新属性的添加而扩大。
当您在构造中传递对象引用时props,CDK 会将其解析为相应的字符串值(例如 ARN、名称或其他标识符)。如果您稍后访问构造实例上的相应属性,则会看到此已解析的字符串值,而不是原始对象引用。
对象引用仅适用于构造的顶级属性。复杂对象中的嵌套属性需要明确的字符串值。
以下示例显示了相同的 Lambda 函数,但使用的是角色对象而不是角色的 ARN 字符串:
例
- TypeScript
-
const role = new iam.Role(this, 'MyRole', {
assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),
managedPolicies: [
iam.ManagedPolicy.fromAwsManagedPolicyName(
'service-role/AWSLambdaBasicExecutionRole'
),
],
});
const myFunction = new lambda.CfnFunction(this, 'HelloWorldFunction', {
runtime: 'nodejs24.x',
role: role, // CDK resolves to role ARN automatically
handler: 'index.handler',
code: {
zipFile: `
exports.handler = async function(event) {
return {
statusCode: 200,
body: JSON.stringify('Hello World!'),
};
};
`}
});
// After creation, myFunction.role contains the resolved ARN string
- JavaScript
-
const role = new iam.Role(this, 'MyRole', {
assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),
managedPolicies: [
iam.ManagedPolicy.fromAwsManagedPolicyName(
'service-role/AWSLambdaBasicExecutionRole'
)
]
});
const myFunction = new lambda.CfnFunction(this, "HelloWorldFunction", {
runtime: 'nodejs24.x',
role: role, // CDK resolves to role ARN automatically
handler: 'index.handler',
code: {
zipFile: `
exports.handler = async function(event) {
return {
statusCode: 200,
body: JSON.stringify('Hello World!'),
};
};
`}
});
// After creation, myFunction.role contains the resolved ARN string
- Python
-
role = iam.Role(self, "MyRole",
assumed_by=iam.ServicePrincipal("lambda.amazonaws.com"),
managed_policies=[
iam.ManagedPolicy.from_aws_managed_policy_name(
"service-role/AWSLambdaBasicExecutionRole"
)
]
)
my_function = _lambda.CfnFunction(self, "HelloWorldFunction",
runtime="nodejs24.x",
role=role, # CDK resolves to role ARN automatically
handler="index.handler",
code=_lambda.CfnFunction.CodeProperty(
zip_file=
"""
exports.handler = async function(event) {
return {
statusCode: 200,
body: JSON.stringify('Hello World!'),
};
};
"""
)
)
# After creation, my_function.role contains the resolved ARN string
- Java
-
Role role = Role.Builder.create(this, "MyRole")
.assumedBy(new ServicePrincipal("lambda.amazonaws.com"))
.managedPolicies(Arrays.asList(
ManagedPolicy.fromAwsManagedPolicyName(
"service-role/AWSLambdaBasicExecutionRole"
)
))
.build();
CfnFunction myFunction = CfnFunction.Builder.create(this, "HelloWorldFunction")
.runtime("nodejs24.x")
.role(role) // CDK resolves to role ARN automatically
.handler("index.handler")
.code(CfnFunction.CodeProperty.builder()
.zipFile(
"exports.handler = async function(event) {" +
" return {" +
" statusCode: 200," +
" body: JSON.stringify('Hello World!')," +
" };" +
"};")
.build())
.build();
// After creation, myFunction.getRole() contains the resolved ARN string
- C#
-
var role = new Role(this, "MyRole", new RoleProps
{
AssumedBy = new ServicePrincipal("lambda.amazonaws.com"),
ManagedPolicies = new[]
{
ManagedPolicy.FromAwsManagedPolicyName(
"service-role/AWSLambdaBasicExecutionRole"
)
}
});
var myFunction = new CfnFunction(this, "HelloWorldFunction", new CfnFunctionProps
{
Runtime = "nodejs24.x",
Role = role, // CDK resolves to role ARN automatically
Handler = "index.handler",
Code = new CfnFunction.CodeProperty
{
ZipFile = @"
exports.handler = async function(event) {
return {
statusCode: 200,
body: JSON.stringify('Hello World!'),
};
};
"
}
});
// After creation, myFunction.Role contains the resolved ARN string
- Go
-
role := awsiam.NewRole(stack, jsii.String("MyRole"), &awsiam.RoleProps{
AssumedBy: awsiam.NewServicePrincipal(jsii.String("lambda.amazonaws.com"), nil),
ManagedPolicies: &[]awsiam.IManagedPolicy{
awsiam.ManagedPolicy_FromAwsManagedPolicyName(jsii.String("service-role/AWSLambdaBasicExecutionRole")),
},
})
myFunction := awslambda.NewCfnFunction(stack, jsii.String("HelloWorldFunction"), &awslambda.CfnFunctionProps{
Runtime: jsii.String("nodejs24.x"),
Role: role, // CDK resolves to role ARN automatically
Handler: jsii.String("index.handler"),
Code: &awslambda.CfnFunction_CodeProperty{
ZipFile: jsii.String(`
exports.handler = async function(event) {
return {
statusCode: 200,
body: JSON.stringify('Hello World!'),
};
};
`),
},
})
// After creation, *myFunction.Role() contains the resolved ARN string
使用 L2 构造
在以下示例中,我们通过从 Bucket L2 构造中创建对象来定义 Amazon S3 存储桶:
例
- TypeScript
-
import * as s3 from 'aws-cdk-lib/aws-s3';
// "this" is HelloCdkStack
new s3.Bucket(this, 'MyFirstBucket', {
versioned: true
});
- JavaScript
-
const s3 = require('aws-cdk-lib/aws-s3');
// "this" is HelloCdkStack
new s3.Bucket(this, 'MyFirstBucket', {
versioned: true
});
- Python
-
import aws_cdk.aws_s3 as s3
# "self" is HelloCdkStack
s3.Bucket(self, "MyFirstBucket", versioned=True)
- Java
-
import software.amazon.awscdk.services.s3.*;
public class HelloCdkStack extends Stack {
public HelloCdkStack(final Construct scope, final String id) {
this(scope, id, null);
}
public HelloCdkStack(final Construct scope, final String id, final StackProps props) {
super(scope, id, props);
Bucket.Builder.create(this, "MyFirstBucket")
.versioned(true).build();
}
}
- C#
-
using Amazon.CDK.AWS.S3;
// "this" is HelloCdkStack
new Bucket(this, "MyFirstBucket", new BucketProps
{
Versioned = true
});
- Go
-
import (
"github.com/aws/aws-cdk-go/awscdk/v2/awss3"
"github.com/aws/jsii-runtime-go"
)
// stack is HelloCdkStack
awss3.NewBucket(stack, jsii.String("MyFirstBucket"), &awss3.BucketProps{
Versioned: jsii.Bool(true),
})
MyFirstBucket不是 AWS CloudFormation 创建的存储桶的名称。它是在 CDK 应用程序的上下文中赋予新构造的逻辑标识符。PhysicalNam e 值将用于命名资源。 AWS CloudFormation
使用第三方构造
C@@ onstruct Hub 是一种资源 AWS,可帮助您发现来自第三方和开源 CDK 社区的其他构造。
编写自己的构造
除了使用现有构造之外,您还可以编写自己的构造,让任何人在其应用程序中使用。 AWS CDK 中的所有构造都是相等的。构造库中的 AWS 构造与通过NPM、Maven或PyPI发布的第三方库中的构造相同。发布到公司内部包存储库的构造也将按相同方式处理。
要声明新构造,请在 constructs 包中创建一个扩展 Construct 基类的类,然后遵循初始化程序参数的模式。
以下示例展示了如何声明代表 Amazon S3 存储桶的构造。每当有用户向 S3 存储桶中上传文件时,该存储桶都会发送 Amazon Simple Notification Service(Amazon SNS)通知。
例
- TypeScript
-
export interface NotifyingBucketProps {
prefix?: string;
}
export class NotifyingBucket extends Construct {
constructor(scope: Construct, id: string, props: NotifyingBucketProps = {}) {
super(scope, id);
const bucket = new s3.Bucket(this, 'bucket');
const topic = new sns.Topic(this, 'topic');
bucket.addObjectCreatedNotification(new s3notify.SnsDestination(topic),
{ prefix: props.prefix });
}
}
- JavaScript
-
class NotifyingBucket extends Construct {
constructor(scope, id, props = {}) {
super(scope, id);
const bucket = new s3.Bucket(this, 'bucket');
const topic = new sns.Topic(this, 'topic');
bucket.addObjectCreatedNotification(new s3notify.SnsDestination(topic),
{ prefix: props.prefix });
}
}
module.exports = { NotifyingBucket }
- Python
-
class NotifyingBucket(Construct):
def __init__(self, scope: Construct, id: str, *, prefix=None):
super().__init__(scope, id)
bucket = s3.Bucket(self, "bucket")
topic = sns.Topic(self, "topic")
bucket.add_object_created_notification(s3notify.SnsDestination(topic),
s3.NotificationKeyFilter(prefix=prefix))
- Java
-
public class NotifyingBucket extends Construct {
public NotifyingBucket(final Construct scope, final String id) {
this(scope, id, null, null);
}
public NotifyingBucket(final Construct scope, final String id, final BucketProps props) {
this(scope, id, props, null);
}
public NotifyingBucket(final Construct scope, final String id, final String prefix) {
this(scope, id, null, prefix);
}
public NotifyingBucket(final Construct scope, final String id, final BucketProps props, final String prefix) {
super(scope, id);
Bucket bucket = new Bucket(this, "bucket");
Topic topic = new Topic(this, "topic");
if (prefix != null)
bucket.addObjectCreatedNotification(new SnsDestination(topic),
NotificationKeyFilter.builder().prefix(prefix).build());
}
}
- C#
-
public class NotifyingBucketProps : BucketProps
{
public string Prefix { get; set; }
}
public class NotifyingBucket : Construct
{
public NotifyingBucket(Construct scope, string id, NotifyingBucketProps props = null) : base(scope, id)
{
var bucket = new Bucket(this, "bucket");
var topic = new Topic(this, "topic");
bucket.AddObjectCreatedNotification(new SnsDestination(topic), new NotificationKeyFilter
{
Prefix = props?.Prefix
});
}
}
- Go
-
type NotifyingBucketProps struct {
awss3.BucketProps
Prefix *string
}
func NewNotifyingBucket(scope constructs.Construct, id *string, props *NotifyingBucketProps) awss3.Bucket {
var bucket awss3.Bucket
if props == nil {
bucket = awss3.NewBucket(scope, jsii.String(*id+"Bucket"), nil)
} else {
bucket = awss3.NewBucket(scope, jsii.String(*id+"Bucket"), &props.BucketProps)
}
topic := awssns.NewTopic(scope, jsii.String(*id+"Topic"), nil)
if props == nil {
bucket.AddObjectCreatedNotification(awss3notifications.NewSnsDestination(topic))
} else {
bucket.AddObjectCreatedNotification(awss3notifications.NewSnsDestination(topic), &awss3.NotificationKeyFilter{
Prefix: props.Prefix,
})
}
return bucket
}
NotifyingBucket 构造不是继承自 Bucket,而是继承自 Construct。我们使用组合而不是继承,以将 Amazon S3 存储桶和 Amazon SNS 主题捆绑在一起。通常,在开发 AWS CDK 构造时,组合比继承更受青睐。
NotifyingBucket 构造函数具有典型的构造签名:scope、id 和 props。最后一个参数 props 是可选的(获取默认值 {}),因为所有 props 都是可选的。(Construct 基类不带 props 参数。) 例如,您可以在应用程序中定义不带 props 的此构造的实例:
例
- TypeScript
-
new NotifyingBucket(this, 'MyNotifyingBucket');
- JavaScript
-
new NotifyingBucket(this, 'MyNotifyingBucket');
- Python
-
NotifyingBucket(self, "MyNotifyingBucket")
- Java
-
new NotifyingBucket(this, "MyNotifyingBucket");
- C#
-
new NotifyingBucket(this, "MyNotifyingBucket");
- Go
-
NewNotifyingBucket(stack, jsii.String("MyNotifyingBucket"), nil)
或者您可以使用 props(在 Java 中使用附加参数)指定要筛选的路径前缀,例如:
例
- TypeScript
-
new NotifyingBucket(this, 'MyNotifyingBucket', { prefix: 'images/' });
- JavaScript
-
new NotifyingBucket(this, 'MyNotifyingBucket', { prefix: 'images/' });
- Python
-
NotifyingBucket(self, "MyNotifyingBucket", prefix="images/")
- Java
-
new NotifyingBucket(this, "MyNotifyingBucket", "/images");
- C#
-
new NotifyingBucket(this, "MyNotifyingBucket", new NotifyingBucketProps
{
Prefix = "/images"
});
- Go
-
NewNotifyingBucket(stack, jsii.String("MyNotifyingBucket"), &NotifyingBucketProps{
Prefix: jsii.String("images/"),
})
通常,您还需要在构造中公开一些属性或方法。在构造后面隐藏一个话题并不是很有用,因为构造的用户无法订阅它。添加 topic 属性可让使用者访问内部主题,如以下示例所示:
例
- TypeScript
-
export class NotifyingBucket extends Construct {
public readonly topic: sns.Topic;
constructor(scope: Construct, id: string, props: NotifyingBucketProps) {
super(scope, id);
const bucket = new s3.Bucket(this, 'bucket');
this.topic = new sns.Topic(this, 'topic');
bucket.addObjectCreatedNotification(new s3notify.SnsDestination(this.topic), { prefix: props.prefix });
}
}
- JavaScript
-
class NotifyingBucket extends Construct {
constructor(scope, id, props) {
super(scope, id);
const bucket = new s3.Bucket(this, 'bucket');
this.topic = new sns.Topic(this, 'topic');
bucket.addObjectCreatedNotification(new s3notify.SnsDestination(this.topic), { prefix: props.prefix });
}
}
module.exports = { NotifyingBucket };
- Python
-
class NotifyingBucket(Construct):
def __init__(self, scope: Construct, id: str, *, prefix=None, **kwargs):
super().__init__(scope, id)
bucket = s3.Bucket(self, "bucket")
self.topic = sns.Topic(self, "topic")
bucket.add_object_created_notification(s3notify.SnsDestination(self.topic),
s3.NotificationKeyFilter(prefix=prefix))
- Java
-
public class NotifyingBucket extends Construct {
public Topic topic = null;
public NotifyingBucket(final Construct scope, final String id) {
this(scope, id, null, null);
}
public NotifyingBucket(final Construct scope, final String id, final BucketProps props) {
this(scope, id, props, null);
}
public NotifyingBucket(final Construct scope, final String id, final String prefix) {
this(scope, id, null, prefix);
}
public NotifyingBucket(final Construct scope, final String id, final BucketProps props, final String prefix) {
super(scope, id);
Bucket bucket = new Bucket(this, "bucket");
topic = new Topic(this, "topic");
if (prefix != null)
bucket.addObjectCreatedNotification(new SnsDestination(topic),
NotificationKeyFilter.builder().prefix(prefix).build());
}
}
- C#
-
public class NotifyingBucket : Construct
{
public readonly Topic topic;
public NotifyingBucket(Construct scope, string id, NotifyingBucketProps props = null) : base(scope, id)
{
var bucket = new Bucket(this, "bucket");
topic = new Topic(this, "topic");
bucket.AddObjectCreatedNotification(new SnsDestination(topic), new NotificationKeyFilter
{
Prefix = props?.Prefix
});
}
}
- Go
-
要在 Go 中实现此目的,我们需要一点额外的操作。原始 NewNotifyingBucket 函数返回了 awss3.Bucket。我们将需要通过创建 NotifyingBucket 构造扩展 Bucket,以包含 topic 成员。然后,函数将返回此类型。
type NotifyingBucket struct {
awss3.Bucket
topic awssns.Topic
}
func NewNotifyingBucket(scope constructs.Construct, id *string, props *NotifyingBucketProps) NotifyingBucket {
var bucket awss3.Bucket
if props == nil {
bucket = awss3.NewBucket(scope, jsii.String(*id+"Bucket"), nil)
} else {
bucket = awss3.NewBucket(scope, jsii.String(*id+"Bucket"), &props.BucketProps)
}
topic := awssns.NewTopic(scope, jsii.String(*id+"Topic"), nil)
if props == nil {
bucket.AddObjectCreatedNotification(awss3notifications.NewSnsDestination(topic))
} else {
bucket.AddObjectCreatedNotification(awss3notifications.NewSnsDestination(topic), &awss3.NotificationKeyFilter{
Prefix: props.Prefix,
})
}
var nbucket NotifyingBucket
nbucket.Bucket = bucket
nbucket.topic = topic
return nbucket
}
现在,使用者可以订阅该主题,例如:
例
- TypeScript
-
const queue = new sqs.Queue(this, 'NewImagesQueue');
const images = new NotifyingBucket(this, '/images');
images.topic.addSubscription(new sns_sub.SqsSubscription(queue));
- JavaScript
-
const queue = new sqs.Queue(this, 'NewImagesQueue');
const images = new NotifyingBucket(this, '/images');
images.topic.addSubscription(new sns_sub.SqsSubscription(queue));
- Python
-
queue = sqs.Queue(self, "NewImagesQueue")
images = NotifyingBucket(self, prefix="Images")
images.topic.add_subscription(sns_sub.SqsSubscription(queue))
- Java
-
NotifyingBucket images = new NotifyingBucket(this, "MyNotifyingBucket", "/images");
images.topic.addSubscription(new SqsSubscription(queue));
- C#
-
var queue = new Queue(this, "NewImagesQueue");
var images = new NotifyingBucket(this, "MyNotifyingBucket", new NotifyingBucketProps
{
Prefix = "/images"
});
images.topic.AddSubscription(new SqsSubscription(queue));
- Go
-
queue := awssqs.NewQueue(stack, jsii.String("NewImagesQueue"), nil)
images := NewNotifyingBucket(stack, jsii.String("MyNotifyingBucket"), &NotifyingBucketProps{
Prefix: jsii.String("/images"),
})
images.topic.AddSubscription(awssnssubscriptions.NewSqsSubscription(queue, nil))
了解详情
以下视频全面概述了 CDK 构造,并说明了如何在 CDK 应用程序中使用它们。