View a markdown version of this page

配置和执行 CDK 堆栈合成 - AWS 云开发套件 (AWS CDK) v2

这是 AWS CDK v2 开发者指南。旧版 CDK v1 于 2022 年 6 月 1 日进入维护阶段,并于 2023 年 6 月 1 日终止支持。

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

配置和执行 CDK 堆栈合成

在部署 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 堆栈

要合成 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 堆栈合成。