排查 AWS CDK 引导问题 - AWS Cloud Development Kit (AWS CDK) v2

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

排查 AWS CDK 引导问题

使用 AWS Cloud Development Kit (AWS CDK) 引导环境时排查常见问题。

有关引导的简介,请参阅 AWS CDK 引导

有关引导的说明,请参阅引导环境以用于 AWS CDK

使用默认模板进行引导时,您会收到有关 Amazon S3 存储桶的“CREATE_FAILED”错误

将 AWS CDK 命令行界面(CDK CLI)cdk bootstrap 命令与默认引导模板结合使用进行引导时,您会收到以下错误:

CREATE_FAILED | AWS::S3::Bucket | BucketName already exists

在排查问题之前,请确保您使用的是最新版本的 CDK CLI。

  • 要检查版本,请运行 cdk --version

  • 要安装最新版本,请运行 npm install -g aws-cdk

安装最新版本后,请再次尝试引导环境。如果您仍然收到相同的错误,请继续进行问题排查。

常见原因

当您引导环境时,AWS CDK 会生成引导资源的物理 ID。有关更多信息,请参阅 在引导期间中创建的资源 ID

与其他引导资源不同,Amazon S3 存储桶名称是全局名称。这意味着,每个存储桶名称在分区内的所有 AWS 区域 中的所有 AWS 账户 之间必须是唯一的。有关更多信息,请参阅《Amazon S3 用户指南》中的存储桶概览。因此,导致此错误的最常见原因是作为存储桶名称生成的物理 ID 已经存在于分区中的某个位置。这可能存在于您的账户或其他账户中。

下面是存储桶名称示例:cdk-hnb659fds-assets-012345678910-us-west-1。虽然不太可能,但由于名称中包含限定符和账户 ID,Amazon S3 存储桶的此名称可能会被其他 AWS 账户 使用。由于存储桶名称是全局范围的,因此如果同一分区中的其他账户使用存储桶名称,则无法使用该名称。最有可能的是,您的账户的某个位置存在同名的存储桶。这可能位于您尝试引导的区域,也可能位于其他区域。

通常,解决方案是在您的账户中找到此存储桶并确定如何处理它,或者自定义引导以创建不同名称的引导资源。

解决方案

首先,确定 AWS 账户 中是否存在同名的存储桶。使用具有有效权限的 AWS 身份在您的账户中查找 Amazon S3 存储桶,您可以通过以下方式执行此操作:

  • 使用 AWS Command Line Interface(AWS CLI)aws s3 ls 命令查看所有存储桶的列表。

  • 使用 Amazon S3 控制台 查找您的账户中每个区域的存储桶名称。

如果存在同名存储桶,请确定该存储桶是否正被使用。如果该存储桶未被使用,请考虑删除该存储桶,然后尝试再次引导环境。

如果存在同名存储桶,而您不想将其删除,请确定该存储桶是否已与您的账户中的引导堆栈关联。您可能需要检查多个区域。Amazon S3 存储桶名称中的区域并不一定意味着存储桶位于该区域。要检查存储桶是否与 CDKToolkit 引导堆栈关联,您可以为每个区域执行以下任一操作:

  • 使用 AWS CLI aws cloudformation describe-stack-resources --stack-name CDKToolkit --region Region 命令查看引导堆栈中的资源并检查存储桶是否已列出。

  • AWS CloudFormation 控制台中,找到 CDKToolkit 堆栈。然后,在资源选项卡上,检查存储桶是否存在。

如果存储桶与引导堆栈关联,请确定引导堆栈是否位于您尝试引导的同一区域中。如果是,则说明您的环境已引导,您应该能够开始使用 CDK 将应用程序部署到您的环境中。如果 Amazon S3 存储桶与其他区域中的引导堆栈关联,则需要确定要执行的操作。可能的解决方案包括重命名现有 Amazon S3 存储桶、删除当前未使用的 Amazon S3 存储桶,或者为您尝试创建的 Amazon S3 存储桶使用新名称。

如果您的账户中找不到同名 Amazon S3 存储桶,则该存储桶可能存在于其他账户中。要解决这个问题,您需要自定义引导,以便为所有引导资源或仅为 Amazon S3 存储桶创建新名称。要为所有引导资源创建新名称,可以修改限定符。要仅为 Amazon S3 存储桶创建新名称,您可以提供新的存储桶名称。

要自定义引导,您可以将选项与 CDK CLI cdk bootstrap 命令结合使用或通过修改引导模板。有关说明,请参阅 自定义 AWS CDK 引导

如果您自定义引导,则需要对合成应用相同的更改,然后才能正确部署应用程序。有关说明,请参阅 自定义 CDK 堆栈合成

例如,您可以使用 cdk bootstrap 提供新的限定符:

$ cdk bootstrap --qualifier abcde0123

以下是通过此修改创建的 Amazon S3 存储桶名称示例:cdk-abcde0123-assets-012345678910-us-west-1。在引导期间创建的所有引导资源都将使用此限定符。

开发 CDK 应用程序时,您必须在合成器中指定自定义限定符。这有助于 CDK 在合成和部署期间识别引导资源。以下是为堆栈实例自定义默认合成器的示例:

TypeScript
new MyStack(this, 'MyStack', { synthesizer: new DefaultStackSynthesizer({ qualifier: 'abcde0123', }), });
JavaScript
new MyStack(this, 'MyStack', { synthesizer: new DefaultStackSynthesizer({ qualifier: 'abcde0123', }), })
Python
MyStack(self, "MyStack", synthesizer=DefaultStackSynthesizer( qualifier="abcde0123" ))
Java
new MyStack(app, "MyStack", StackProps.builder() .synthesizer(DefaultStackSynthesizer.Builder.create() .qualifier("abcde0123") .build()) .build();
C#

new MyStack(app, "MyStack", new StackProps { Synthesizer = new DefaultStackSynthesizer(new DefaultStackSynthesizerProps { Qualifier = "abcde0123" }) });
Go
func NewMyStack(scope constructs.Construct, id string, props *MyStackProps) awscdk.Stack { var sprops awscdk.StackProps if props != nil { sprops = props.StackProps } stack := awscdk.NewStack(scope, &id, &sprops) synth := awscdk.NewDefaultStackSynthesizer(&awscdk.DefaultStackSynthesizerProps{ Qualifier: jsii.String("abcde0123"), }) stack.SetSynthesizer(synth) return stack }

您也可以在 CDK 项目的 cdk.json 文件中指定新的限定符:

{ "app": "...", "context": { "@aws-cdk/core:bootstrapQualifier": "abcde0123" } }

要仅修改 Amazon S3 存储桶名称,您可以使用 --bootstrap-bucket-name 选项。以下是 示例:

$ cdk bootstrap --bootstrap-bucket-name 'my-new-bucket-name'

开发 CDK 应用程序时,您必须在合成器中指定新的存储桶名称。以下是为堆栈实例自定义默认合成器的示例:

TypeScript
new MyStack(this, 'MyStack', { synthesizer: new DefaultStackSynthesizer({ fileAssetsBucketName: 'my-new-bucket-name', }), });
JavaScript
new MyStack(this, 'MyStack', { synthesizer: new DefaultStackSynthesizer({ fileAssetsBucketName: 'my-new-bucket-name', }), })
Python
MyStack(self, "MyStack", synthesizer=DefaultStackSynthesizer( file_assets_bucket_name='my-new-bucket-name' ))
Java
new MyStack(app, "MyStack", StackProps.builder() .synthesizer(DefaultStackSynthesizer.Builder.create() .fileAssetsBucketName("my-new-bucket-name") .build()) .build();
C#

new MyStack(app, "MyStack", new StackProps { Synthesizer = new DefaultStackSynthesizer(new DefaultStackSynthesizerProps { FileAssetsBucketName = "my-new-bucket-name" }) });
Go
func NewMyStack(scope constructs.Construct, id string, props *MyStackProps) awscdk.Stack { var sprops awscdk.StackProps if props != nil { sprops = props.StackProps } stack := awscdk.NewStack(scope, &id, &sprops) synth := awscdk.NewDefaultStackSynthesizer(&awscdk.DefaultStackSynthesizerProps{ FileAssetsBucketName: jsii.String("my-new-bucket-name"), }) stack.SetSynthesizer(synth) return stack }

预防

我们建议您主动引导计划使用的每个 AWS 环境。有关更多信息,请参阅 何时引导环境。特别是针对 Amazon S3 存储桶命名问题,这将在每个 AWS 环境中创建 Amazon S3 存储桶,并防止他人使用 Amazon S3 存储桶名称。