配置和执行CDK堆栈合成 - AWS Cloud Development Kit (AWS CDK) v2

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

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

配置和执行CDK堆栈合成

在部署堆 AWS Cloud Development Kit (AWS CDK) 栈之前,必须先对其进行合成。堆栈合成是从堆CDK栈中生成 AWS CloudFormation 模板和部署工件的过程。模板和工件被称为云组件。云组件是用来配置资源的部署 AWS。有关部署工作原理的更多信息,请参阅AWS CDK 部署的工作原理

合成和引导如何协同工作

为了使您的CDK应用程序正确部署,合成期间生成的 CloudFormation 模板必须正确指定引导期间创建的资源。因此,引导和综合必须相辅相成,部署才能成功:

  • 引导是设置部署 AWS 环境的一次性过程。 AWS CDK 它在您的环境中配置CDK用于部署的特定 AWS 资源。这些资源通常被称为引导资源。有关引导的说明,请参阅。引导您的环境以用于 AWS CDK

  • CloudFormation 综合过程中生成的模板包含有关要使用哪些引导程序资源的信息。在合成过程中,CDKCLI 不知道你的 AWS 环境是如何被引导的。相反,CDKCLI 根据您为每个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) }

您还可以使用实例的defaultStackSynthesizer属性为CDK应用程序中的所有CDK堆栈配置合成器:App

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堆栈名称作为参数。默认情况下,CDKCLI 会将你的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 将在部署前自动合成您的堆栈。

默认情况下合成的工作原理

IDs在您的 AWS CloudFormation 模板中逻辑生成

当你合成CDK堆栈以生成 CloudFormation 模板时,逻辑IDs是从以下来源生成的,格式为 <construct-path><construct-ID><unique-hash>:

  • 构造路径-CDK 应用程序中构造的完整路径。此路径不包括 L1 构造的 ID(始终为ResourceDefault)以及它所属的顶级堆栈的 ID。

  • 构造 ID — 您在实例化构造时作为第二个参数提供的 ID。

  • 唯一哈希 — 使用确定性哈希算法 AWS CDK 生成 8 个字符的唯一哈希。这种唯一的哈希值有助于确保模板中的逻辑 ID 值是唯一的。此哈希生成的确定性行为可确保每次执行合成时,为每个构造生成的逻辑 ID 值保持不变。只有在您修改特定的构造值(例如构造的 ID 或其路径)时,哈希值才会改变。

逻辑IDs的最大长度为 255 个字符。因此,如有必要, AWS CDK 将截断构造路径和构造 ID,以保持在该限制之内。

以下是定义亚马逊简单存储服务 (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 synthmyBucketunique-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 synthFooBarBucketunique-hash会生成格式为的逻辑 ID。以下是生成的 AWS CloudFormation 模板中此资源的示例:

Resources: FooBarBucketBA3ED1FA: Type: AWS::S3::Bucket Properties: VersioningConfiguration: Status: Enabled UpdateReplacePolicy: Delete DeletionPolicy: Delete # ...

自定义CDK堆栈合成

如果默认CDK合成行为不符合您的需求,则可以自定义CDK合成。为此,您可以修改DefaultStackSynthesizer、使用其他可用的内置合成器或创建自己的合成器。有关说明,请参阅 自定义CDK堆栈合成