AWS CDK 构造 - AWS Cloud Development Kit (AWS CDK) v2

这是 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 构造库中的AppStack类是唯一的构造。与其他结构相比,它们不会自行配置 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,例如名称或其他资源标识符

  • 对象引用:直接传递构造对象。这样就不必确定属性期望哪种标识符类型,CDK 会为您处理。

使用字符串引用

您可以随时传递显式字符串值 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 构造函数具有典型的构造签名:scopeidprops。最后一个参数 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 应用程序中使用它们。