这是 AWS CDK v2 开发者指南。较旧的 CDK v1 于 2022 年 6 月 1 日进入维护阶段,并于 2023 年 6 月 1 日终止支持。
本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
在部署 AWS Cloud Development Kit (AWS CDK) 堆栈之前,必须先对其进行合成。堆栈合成是从 CDK 堆栈生成 AWS CloudFormation 模板和部署构件的过程。模板和构件称为云程序集。部署云程序集后即可在 AWS 上预置资源。有关部署的工作原理的更多信息,请参阅 AWS CDK 部署的工作原理。
为了正确部署 CDK 应用程序,合成过程中生成的 CloudFormation 模板必须正确指定引导过程中创建的资源。因此,引导和合成必须相辅相成,才能成功部署:
-
引导是为 AWS CDK 部署设置 AWS 环境的一次性过程。它会在您的环境中配置 CDK 用于部署的特定 AWS 资源。这些资源通常被称为引导资源。有关引导的说明,请参阅引导您的环境以用于 AWS CDK。
-
合成过程中生成的 CloudFormation 模板包含有关要使用哪些引导资源的信息。在合成期间,CDK CLI 并不具体知道 AWS 环境是如何引导的。相反,CDK CLI 会根据您为每个 CDK 堆栈配置的合成器生成 CloudFormation 模板。要成功部署,合成器必须生成引用要使用的正确引导资源的 CloudFormation 模板。
CDK 自带能够协同工作的默认合成器和引导配置。如果您对其中一个进行自定义,则必须对另一个应用相关的自定义。
如何配置 CDK 堆栈合成
您可以使用 Stack
实例的 synthesizer
属性配置 CDK 堆栈合成。此属性指定如何合成 CDK 堆栈。您提供实现 IStackSynthesizer
或 IReusableStackSynthesizer
的类的实例。每次将资源添加到堆栈或合成堆栈时,都会调用其方法。以下是在堆栈中使用此属性的基本示例:
- TypeScript
-
new MyStack(this, 'MyStack', {
// stack properties
synthesizer: new DefaultStackSynthesizer({
// synthesizer properties
}),
});
- JavaScript
-
new MyStack(this, 'MyStack', {
// stack properties
synthesizer: new DefaultStackSynthesizer({
// synthesizer properties
}),
});
- Python
-
MyStack(self, "MyStack",
# stack properties
synthesizer=DefaultStackSynthesizer(
# synthesizer properties
))
- Java
-
new MyStack(app, "MyStack", StackProps.builder()
// stack properties
.synthesizer(DefaultStackSynthesizer.Builder.create()
// synthesizer properties
.build())
.build();
- C#
-
new MyStack(app, "MyStack", new StackProps
// stack properties
{
Synthesizer = new DefaultStackSynthesizer(new DefaultStackSynthesizerProps
{
// synthesizer properties
})
});
- Go
-
func main() {
app := awscdk.NewApp(nil)
NewMyStack(app, "MyStack", &MyStackProps{
StackProps: awscdk.StackProps{
Synthesizer: awscdk.NewDefaultStackSynthesizer(&awscdk.DefaultStackSynthesizerProps{
// synthesizer properties
}),
},
})
app.Synth(nil)
}
您还可以使用 App
实例的 defaultStackSynthesizer
属性为 CDK 应用程序中的所有 CDK 堆栈配置合成器:
- TypeScript
-
import { App, Stack, DefaultStackSynthesizer } from 'aws-cdk-lib';
const app = new App({
// Configure for all stacks in this app
defaultStackSynthesizer: new DefaultStackSynthesizer({
/* ... */
}),
});
- JavaScript
-
const { App, Stack, DefaultStackSynthesizer } = require('aws-cdk-lib');
const app = new App({
// Configure for all stacks in this app
defaultStackSynthesizer: new DefaultStackSynthesizer({
/* ... */
}),
});
- Python
-
from aws_cdk import App, Stack, DefaultStackSynthesizer
app = App(
default_stack_synthesizer=DefaultStackSynthesizer(
# Configure for all stacks in this app
# ...
)
)
- Java
-
import software.amazon.awscdk.App;
import software.amazon.awscdk.Stack;
import software.amazon.awscdk.DefaultStackSynthesizer;
public class Main {
public static void main(final String[] args) {
App app = new App(AppProps.builder()
// Configure for all stacks in this app
.defaultStackSynthesizer(DefaultStackSynthesizer.Builder.create().build())
.build()
);
}
}
- C#
-
using Amazon.CDK;
using Amazon.CDK.Synthesizers;
namespace MyNamespace
{
sealed class Program
{
public static void Main(string[] args)
{
var app = new App(new AppProps
{
// Configure for all stacks in this app
DefaultStackSynthesizer = new DefaultStackSynthesizer(new DefaultStackSynthesizerProps
{
// ...
})
});
}
}
}
- Go
-
package main
import (
"github.com/aws/aws-cdk-go/awscdk/v2"
"github.com/aws/constructs-go/constructs/v10"
"github.com/aws/jsii-runtime-go"
)
func main() {
defer jsii.Close()
app := awscdk.NewApp(&awscdk.AppProps{
// Configure for all stacks in this app
DefaultStackSynthesizer: awscdk.NewDefaultStackSynthesizer(&awscdk.DefaultStackSynthesizerProps{
// ...
}),
})
}
AWS CDK 默认使用 DefaultStackSynthesizer
。如果您未配置合成器,则将使用此合成器。
如果您不修改引导,例如更改引导堆栈或模板,则不必修改堆栈合成。您甚至不必提供合成器。CDK 将使用默认 DefaultStackSynthesizer
类配置 CDK 堆栈合成,以便与引导堆栈正确交互。
要合成 CDK 堆栈,请使用 AWS CDK 命令行界面(AWS CDK CLI)的 cdk synth
命令。有关此命令的更多信息,包括可与此命令一起使用的选项,请参阅 cdk synthesize。
如果 CDK 应用程序包含单个堆栈,或者要合成所有堆栈,则无需提供 CDK 堆栈名称作为参数。默认情况下,CDK CLI 会将 CDK 堆栈合成到 AWS CloudFormation 模板中。每个堆栈的 json
格式的模板将保存到 cdk.out
目录中。如果您的应用程序包含单个堆栈,则会将 yaml
格式的模板打印到 stdout
中。以下是示例:
$
cdk synth
Resources:
CDKMetadata:
Type: AWS::CDK::Metadata
Properties:
Analytics: v2:deflate64:H4sIAAAAAAAA/unique-identifier
Metadata:
aws:cdk:path: CdkAppStack/CDKMetadata/Default
Condition: CDKMetadataAvailable
...
如果 CDK 应用程序包含多个堆栈,则可以提供堆栈的逻辑 ID 以合成单个堆栈。以下是 示例:
$
cdk synth MyStackName
如果您没有合成堆栈并运行 cdk deploy
,CDK CLI 将在部署前自动合成堆栈。
合成的默认工作原理
AWS CloudFormation 模板中生成的逻辑 ID
合成 CDK 堆栈以生成 CloudFormation 模板时,逻辑 ID 是从以下源生成的,格式为 <construct-path><construct-ID><unique-hash>
:
-
构造路径:指向 CDK 应用程序中构造的完整路径。此路径不包括 L1 构造的 ID(始终为 Resource
或 Default
)以及它所属的顶级堆栈的 ID。
-
构造 ID:实例化构造时作为第二个参数提供的 ID。
-
唯一哈希值:AWS CDK 会使用确定性哈希算法生成 8 个字符的唯一哈希值。此唯一哈希值有助于确保模板中的逻辑 ID 值是唯一的。此哈希值生成的确定性行为可确保每次执行合成时,为每个构造生成的逻辑 ID 值保持不变。只有在您修改特定的构造值(例如构造的 ID 或其路径)时,哈希值才会改变。
逻辑 ID 最多可包含 255 个字符。因此,如有必要,AWS CDK 将截断构造路径和构造 ID,以保持在该限制之内。
以下是定义 Amazon Simple Storage Service(Amazon S3)存储桶的示例构造。在本例中,我们将 myBucket
作为构造的 ID 传递:
- TypeScript
-
import * as cdk from 'aws-cdk-lib';
import { Construct} from 'constructs';
import * as s3 from 'aws-cdk-lib/aws-s3';
export class MyCdkAppStack extends cdk.Stack {
constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// Define the S3 bucket
new s3.Bucket(this, 'myBucket', {
versioned: true,
removalPolicy: cdk.RemovalPolicy.DESTROY,
});
}
}
- JavaScript
-
const cdk = require('aws-cdk-lib');
const s3 = require('aws-cdk-lib/aws-s3');
class MyCdkAppStack extends cdk.Stack {
constructor(scope, id, props) {
super(scope, id, props);
new s3.Bucket(this, 'myBucket', {
versioned: true,
removalPolicy: cdk.RemovalPolicy.DESTROY,
});
}
}
module.exports = { MyCdkAppStack }
- Python
-
import aws_cdk as cdk
from constructs import Construct
from aws_cdk import Stack
from aws_cdk import aws_s3 as s3
class MyCdkAppStack(Stack):
def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
s3.Bucket(self, 'MyBucket',
versioned=True,
removal_policy=cdk.RemovalPolicy.DESTROY
)
- Java
-
package com.myorg;
import software.constructs.Construct;
import software.amazon.awscdk.Stack;
import software.amazon.awscdk.StackProps;
import software.amazon.awscdk.services.s3.Bucket;
import software.amazon.awscdk.services.s3.BucketProps;
import software.amazon.awscdk.RemovalPolicy;
public class MyCdkAppStack extends Stack {
public MyCdkAppStack(final Construct scope, final String id) {
this(scope, id, null);
}
public MyCdkAppStack(final Construct scope, final String id, final StackProps props) {
super(scope, id, props);
Bucket.Builder.create(this, "myBucket")
.versioned(true)
.removalPolicy(RemovalPolicy.DESTROY)
.build();
}
}
- C#
-
using Amazon.CDK;
using Constructs;
using Amazon.CDK.AWS.S3;
namespace MyCdkApp
{
public class MyCdkAppStack : Stack
{
public MyCdkAppStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props)
{
new Bucket(this, "myBucket", new BucketProps
{
Versioned = true,
RemovalPolicy = RemovalPolicy.DESTROY
});
}
}
}
- Go
-
package main
import (
"github.com/aws/aws-cdk-go/awscdk/v2"
"github.com/aws/aws-cdk-go/awscdk/v2/awss3"
"github.com/aws/constructs-go/constructs/v10"
"github.com/aws/jsii-runtime-go"
)
type MyCdkAppStackProps struct {
awscdk.StackProps
}
func NewMyCdkAppStack(scope constructs.Construct, id string, props *MyCdkAppStackProps) awscdk.Stack {
var sprops awscdk.StackProps
if props != nil {
sprops = props.StackProps
}
stack := awscdk.NewStack(scope, &id, &sprops)
awss3.NewBucket(stack, jsii.String("myBucket"), &awss3.BucketProps{
Versioned: jsii.Bool(true),
RemovalPolicy: awscdk.RemovalPolicy_DESTROY,
})
return stack
}
// ...
运行 cdk synth
时,会生成格式为 myBucketunique-hash
的逻辑 ID。以下是生成的 AWS CloudFormation 模板中此资源的示例:
Resources:
myBucket5AF9C99B:
Type: AWS::S3::Bucket
Properties:
VersioningConfiguration:
Status: Enabled
UpdateReplacePolicy: Delete
DeletionPolicy: Delete
Metadata:
aws:cdk:path: S3BucketAppStack/myBucket/Resource
下面是名为 Bar
的自定义构造的示例,它会定义 Amazon S3 存储桶。Bar
构造在其路径中包含自定义构造 Foo
:
- TypeScript
-
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as s3 from 'aws-cdk-lib/aws-s3';
// Define the Bar construct
export class Bar extends Construct {
constructor(scope: Construct, id: string) {
super(scope, id);
// Define an S3 bucket inside of Bar
new s3.Bucket(this, 'Bucket', {
versioned: true,
removalPolicy: cdk.RemovalPolicy.DESTROY,
} );
}
}
// Define the Foo construct
export class Foo extends Construct {
constructor(scope: Construct, id: string) {
super(scope, id);
// Create an instance of Bar inside Foo
new Bar(this, 'Bar');
}
}
// Define the CDK stack
export class MyCustomAppStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// Instantiate Foo construct in the stack
new Foo(this, 'Foo');
}
}
- JavaScript
-
const cdk = require('aws-cdk-lib');
const s3 = require('aws-cdk-lib/aws-s3');
const { Construct } = require('constructs');
// Define the Bar construct
class Bar extends Construct {
constructor(scope, id) {
super(scope, id);
// Define an S3 bucket inside of Bar
new s3.Bucket(this, 'Bucket', {
versioned: true,
removalPolicy: cdk.RemovalPolicy.DESTROY,
});
}
}
// Define the Foo construct
class Foo extends Construct {
constructor(scope, id) {
super(scope, id);
// Create an instance of Bar inside Foo
new Bar(this, 'Bar');
}
}
// Define the CDK stack
class MyCustomAppStack extends cdk.Stack {
constructor(scope, id, props) {
super(scope, id, props);
// Instantiate Foo construct in the stack
new Foo(this, 'Foo');
}
}
module.exports = { MyCustomAppStack }
- Python
-
import aws_cdk as cdk
from constructs import Construct
from aws_cdk import (
Stack,
aws_s3 as s3,
RemovalPolicy,
)
# Define the Bar construct
class Bar(Construct):
def __init__(self, scope: Construct, id: str) -> None:
super().__init__(scope, id)
# Define an S3 bucket inside of Bar
s3.Bucket(self, 'Bucket',
versioned=True,
removal_policy=RemovalPolicy.DESTROY
)
# Define the Foo construct
class Foo(Construct):
def __init__(self, scope: Construct, id: str) -> None:
super().__init__(scope, id)
# Create an instance of Bar inside Foo
Bar(self, 'Bar')
# Define the CDK stack
class MyCustomAppStack(Stack):
def __init__(self, scope: Construct, id: str, **kwargs) -> None:
super().__init__(scope, id, **kwargs)
# Instantiate Foo construct in the stack
Foo(self, 'Foo')
- Java
-
In my-custom-app/src/main/java/com/myorg/Bar.java
:
package com.myorg;
import software.constructs.Construct;
import software.amazon.awscdk.services.s3.Bucket;
import software.amazon.awscdk.services.s3.BucketProps;
import software.amazon.awscdk.RemovalPolicy;
public class Bar extends Construct {
public Bar(final Construct scope, final String id) {
super(scope, id);
// Define an S3 bucket inside Bar
Bucket.Builder.create(this, "Bucket")
.versioned(true)
.removalPolicy(RemovalPolicy.DESTROY)
.build();
}
}
In my-custom-app/src/main/java/com/myorg/Foo.java
:
package com.myorg;
import software.constructs.Construct;
public class Foo extends Construct {
public Foo(final Construct scope, final String id) {
super(scope, id);
// Create an instance of Bar inside Foo
new Bar(this, "Bar");
}
}
In my-custom-app/src/main/java/com/myorg/MyCustomAppStack.java
:
package com.myorg;
import software.constructs.Construct;
import software.amazon.awscdk.Stack;
import software.amazon.awscdk.StackProps;
public class MyCustomAppStack extends Stack {
public MyCustomAppStack(final Construct scope, final String id, final StackProps props) {
super(scope, id, props);
// Instantiate Foo construct in the stack
new Foo(this, "Foo");
}
// Overload constructor in case StackProps is not provided
public MyCustomAppStack(final Construct scope, final String id) {
this(scope, id, null);
}
}
- C#
-
using Amazon.CDK;
using Constructs;
using Amazon.CDK.AWS.S3;
namespace MyCustomApp
{
// Define the Bar construct
public class Bar : Construct
{
public Bar(Construct scope, string id) : base(scope, id)
{
// Define an S3 bucket inside Bar
new Bucket(this, "Bucket", new BucketProps
{
Versioned = true,
RemovalPolicy = RemovalPolicy.DESTROY
});
}
}
// Define the Foo construct
public class Foo : Construct
{
public Foo(Construct scope, string id) : base(scope, id)
{
// Create an instance of Bar inside Foo
new Bar(this, "Bar");
}
}
// Define the CDK Stack
public class MyCustomAppStack : Stack
{
public MyCustomAppStack(Construct scope, string id, StackProps props = null) : base(scope, id, props)
{
// Instantiate Foo construct in the stack
new Foo(this, "Foo");
}
}
}
- Go
-
package main
import (
"github.com/aws/aws-cdk-go/awscdk/v2"
"github.com/aws/aws-cdk-go/awscdk/v2/awss3"
"github.com/aws/constructs-go/constructs/v10"
"github.com/aws/jsii-runtime-go"
)
// Define the Bar construct
type Bar struct {
constructs.Construct
}
func NewBar(scope constructs.Construct, id string) constructs.Construct {
bar := constructs.NewConstruct(scope, &id)
// Define an S3 bucket inside Bar
awss3.NewBucket(bar, jsii.String("Bucket"), &awss3.BucketProps{
Versioned: jsii.Bool(true),
RemovalPolicy: awscdk.RemovalPolicy_DESTROY,
})
return bar
}
// Define the Foo construct
type Foo struct {
constructs.Construct
}
func NewFoo(scope constructs.Construct, id string) constructs.Construct {
foo := constructs.NewConstruct(scope, &id)
// Create an instance of Bar inside Foo
NewBar(foo, "Bar")
return foo
}
// Define the CDK Stack
type MyCustomAppStackProps struct {
awscdk.StackProps
}
func NewMyCustomAppStack(scope constructs.Construct, id string, props *MyCustomAppStackProps) awscdk.Stack {
stack := awscdk.NewStack(scope, &id, &props.StackProps)
// Instantiate Foo construct in the stack
NewFoo(stack, "Foo")
return stack
}
// Define the CDK App
func main() {
app := awscdk.NewApp(nil)
NewMyCustomAppStack(app, "MyCustomAppStack", &MyCustomAppStackProps{
StackProps: awscdk.StackProps{},
})
app.Synth(nil)
}
运行 cdk synth
时,会生成格式为 FooBarBucketunique-hash
的逻辑 ID。以下是生成的 AWS CloudFormation 模板中此资源的示例:
Resources:
FooBarBucketBA3ED1FA:
Type: AWS::S3::Bucket
Properties:
VersioningConfiguration:
Status: Enabled
UpdateReplacePolicy: Delete
DeletionPolicy: Delete
# ...
自定义 CDK 堆栈合成
如果默认的 CDK 合成行为不符合您的需求,则可以自定义 CDK 合成。为此,您可以修改 DefaultStackSynthesizer
、使用其他可用的内置合成器或创建自己的合成器。有关说明,请参阅 自定义CDK堆栈合成。