这是 AWS CDK v2 开发者指南。旧版 CDK v1 于 2022 年 6 月 1 日进入维护阶段,并于 2023 年 6 月 1 日终止支持。
本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
在部署 AWS 云开发工具包 (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-pathconstruct-IDunique-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 堆栈合成。