

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

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

# 配置和执行 CDK 堆栈合成
<a name="configure-synth"></a>

在部署 AWS 云开发工具包 (AWS CDK) 堆栈之前，必须先对其进行合成。*堆栈合成*是从 CDK 堆栈生成 AWS CloudFormation 模板和部署构件的过程。模板和构件称为*云程序集*。部署云程序集后即可在 AWS 上预置资源。有关部署的工作原理的更多信息，请参阅 [AWS CDK 部署的工作原理](deploy.md#deploy-how)。

## 合成和引导如何协同工作
<a name="configure-synth-bootstrap"></a>

为了正确部署 CDK 应用程序，合成过程中生成的 CloudFormation 模板必须正确指定引导过程中创建的资源。因此，引导和合成必须相辅相成，才能成功部署：
+ 引导是为 AWS CDK 部署设置 AWS 环境的一次性过程。它会在您的环境中配置 CDK 用于部署的特定 AWS 资源。这些资源通常被称为*引导资源*。有关引导的说明，请参阅[引导环境以用于 AWS CDK](bootstrapping-env.md)。
+ 合成过程中生成的 CloudFormation 模板包含有关要使用哪些引导资源的信息。在合成期间，CDK CLI 并不具体知道 AWS 环境是如何引导的。相反，CDK CLI 会根据您为每个 CDK 堆栈配置的合成器生成 CloudFormation 模板。要成功部署，合成器必须生成引用要使用的正确引导资源的 CloudFormation 模板。

CDK 自带能够协同工作的默认合成器和引导配置。如果您对其中一个进行自定义，则必须对另一个应用相关的自定义。

## 如何配置 CDK 堆栈合成
<a name="bootstrapping-synthesizers"></a>

您可以使用 [https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.Stack.html](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.Stack.html) 实例的 `synthesizer` 属性配置 CDK 堆栈合成。此属性指定如何合成 CDK 堆栈。您提供实现 [https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.IStackSynthesizer.html](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.IStackSynthesizer.html) 或 [https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.IReusableStackSynthesizer.html](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.IReusableStackSynthesizer.html) 的类的实例。每次将资源添加到堆栈或合成堆栈时，都会调用其方法。以下是在堆栈中使用此属性的基本示例：

**Example**  

```
new MyStack(this, 'MyStack', {
  // stack properties
  synthesizer: new DefaultStackSynthesizer({
    // synthesizer properties
  }),
});
```

```
new MyStack(this, 'MyStack', {
  // stack properties
  synthesizer: new DefaultStackSynthesizer({
    // synthesizer properties
  }),
});
```

```
MyStack(self, "MyStack",
    # stack properties
    synthesizer=DefaultStackSynthesizer(
        # synthesizer properties
))
```

```
new MyStack(app, "MyStack", StackProps.builder()
  // stack properties
  .synthesizer(DefaultStackSynthesizer.Builder.create()
    // synthesizer properties
    .build())
  .build();
)
```

```
new MyStack(app, "MyStack", new StackProps
// stack properties
{
    Synthesizer = new DefaultStackSynthesizer(new DefaultStackSynthesizerProps
    {
        // synthesizer properties
    })
});
```

```
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 堆栈配置合成器：

**Example**  

```
import { App, Stack, DefaultStackSynthesizer } from 'aws-cdk-lib';

const app = new App({
  // Configure for all stacks in this app
  defaultStackSynthesizer: new DefaultStackSynthesizer({
    /* ... */
  }),
});
```

```
const { App, Stack, DefaultStackSynthesizer } = require('aws-cdk-lib');

const app = new App({
  // Configure for all stacks in this app
  defaultStackSynthesizer: new DefaultStackSynthesizer({
    /* ... */
  }),
});
```

```
from aws_cdk import App, Stack, DefaultStackSynthesizer

app = App(
    default_stack_synthesizer=DefaultStackSynthesizer(
        # Configure for all stacks in this app
        # ...
    )
)
```

```
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()
        );
    }
}
```

```
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
                {
                    // ...
                })
            });
        }
    }
}
```

```
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](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.DefaultStackSynthesizer.html) `。如果您未配置合成器，则将使用此合成器。

如果您不修改引导，例如更改引导堆栈或模板，则不必修改堆栈合成。您甚至不必提供合成器。CDK 将使用默认 `DefaultStackSynthesizer` 类配置 CDK 堆栈合成，以便与引导堆栈正确交互。

## 如何合成 CDK 堆栈
<a name="configure-synth-stack"></a>

要合成 CDK 堆栈，请使用 AWS CDK 命令行界面 (AWS CDK CLI) 的 `cdk synth` 命令。有关此命令的更多信息，包括可与此命令一起使用的选项，请参阅 [cdk synthesize](ref-cli-cmd-synth.md)。

如果 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 将在部署前自动合成堆栈。

## 合成的默认工作原理
<a name="how-synth-default"></a><a name="how-synth-default-logical-ids"></a>

 **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 传递：  
**Example**  

------
#### [ 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`：  
**Example**  

------
#### [ 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 堆栈合成
<a name="bootstrapping-custom-synth"></a>

如果默认的 CDK 合成行为不符合您的需求，则可以自定义 CDK 合成。为此，您可以修改 `DefaultStackSynthesizer`、使用其他可用的内置合成器或创建自己的合成器。有关说明，请参阅[自定义 CDK 堆栈合成](customize-synth.md)。