重构 CDK 代码时保留已部署的资源 - AWS Cloud Development Kit (AWS CDK) v2

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

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

重构 CDK 代码时保留已部署的资源

重要

CDK 重构目前为预览版,可能会发生变化。

借助 C AWS loud Development Kit (AWS CDK) 重构,您可以重构您的 CDK 代码,例如重命名构造、在堆栈之间移动资源以及重组应用程序,同时保留已部署的资源而不是替换它们。此功能可帮助您保持良好的软件工程最佳实践,而不会导致意外的资源替换。

什么是具有资源保留的 CDK 重构?

部署 CDK 应用程序时,会根据资源的逻辑 IDs来 AWS CloudFormation 识别资源。 AWS CDK IDs 根据构造 ID 及其在构造树中的路径生成这些逻辑。如果您更改构造的 ID 或将其移至代码中的其他位置, AWS CloudFormation 通常会将其解释为请求创建新资源并删除旧资源。对于数据库、存储桶或队列等有状态资源,这种替换可能会导致服务中断或数据丢失。

CDK 重构通过以下方式解决此问题:

  • 检测代码中资源何时被移动或重命名。

  • 使用 AWS CloudFormation的重构功能来保留底层的物理资源。

  • 在 IDs 不替换实际资源的情况下更新逻辑。

  • 维护堆栈中资源之间的引用。

您可以使用 CDK CLI cdk refactor 命令或 CDK 工具包库的 refactor 操作来执行 CDK 重构。本指南主要讨论 CLI 方法,但基本原则适用于这两种方法。有关使用工具包库的信息,请参阅使用 CDK 工具包库执行编程操作

重要

重构操作必须单独执行,与其他操作(例如,添加新资源、删除资源或修改资源属性)分开执行。

如果您需要添加、删除或修改资源以及重构,则应首先单独部署这些更改,然后使用重构来重组您的资源。

CDK 重构的好处

CDK 重构为 CDK 开发者提供了以下好处 AWS :

  • 改进代码组织:重命名结构并重组 CDK 应用程序的结构,而无需替换资源。

  • 创建可重用组件:将重复代码提取为可重用的 L3 构造,同时保留已部署的资源。

  • 增强架构分离:在堆栈之间移动资源,以更好地隔离应用程序的不同部分。

  • 防止意外替换资源:避免在重命名构造时意外重新创建资源。

  • 缓解第三方库更改:保护您的应用程序,以免您所依赖的构造库中的逻辑 ID 发生更改。

  • 应用软件工程最佳实践:在不影响已部署基础设施的情况下重构代码。

CDK CLI cdk refactor 命令的工作原理

重要

您必须对使用此功能的所有命令提供 --unstable=refactor 选项。

首先,部署初始 CDK 应用程序以在 AWS 账户中建立基准资源。重构 CDK 代码(例如,重命名构造或在堆栈之间移动资源)后,使用 cdk refactor 命令开始重构已部署资源的过程。

当您运行重构命令时,CDK CLI 会将当前代码与已部署状态进行比较,从而检测本地更改。它验证您的 CDK 应用程序是否包含与已部署状态完全相同的资源集,只是它们在构造树中的位置不同。然后,CDK CLI 会生成一个重构计划来将旧资源位置映射到新位置。CDK CLI 会向您显示建议的更改,并在您确认后,使用 AWS CloudFormation其重构 API 更新资源的逻辑 IDs 而无需替换它们。

在后台,CDK CLI 通过比较资源的属性和依赖项来确定哪些资源已移动,识别功能等效但在构造树中的路径不同的资源。如果检测到任何资源添加、删除或修改,则重构操作将被拒绝并显示一条错误消息。

重构 CDK 代码时保留资源的示例

在此示例中,我们使用 CDK CLI cdk refactor 命令重构 CDK 代码,同时保留已部署的资源。

我们的示例 CDK 应用程序由包含 S3 存储桶、 CloudFront 分配和 Lambda 函数的单个堆栈组成。构造树的结构如下:

App └─ MyStack ├─ Bucket ├─ Distribution └─ Function

下面是我们的应用程序代码示例:

const app = new cdk.App(); const myStack = new cdk.Stack(app, 'MyStack'); const bucket = new s3.Bucket(myStack, 'Bucket'); const distribution = new cloudfront.Distribution(myStack, 'Distribution', { defaultBehavior: { origin: new origins.S3Origin(bucket) } }); const function = new lambda.Function(myStack, 'Function', { // function properties }); // Synthesize the app app.synth();

现在,假设您想重构此代码来实现以下目的:

  1. 将存储桶从 Bucket 重命名为更具描述性的 WebsiteOrigin

  2. 将存储桶和分配移动到新的 WebStack 堆栈。

重构后,构造树将如下所示:

App ├─ WebStack │ ├─ WebsiteOrigin │ └─ Distribution └─ MyStack └─ Function

重构后的代码如下:

// Refactored structure const app = new cdk.App(); // New WebStack with the bucket and distribution const webStack = new cdk.Stack(app, 'WebStack'); const bucket = new s3.Bucket(webStack, 'WebsiteOrigin'); const distribution = new cloudfront.Distribution(webStack, 'Distribution', { defaultBehavior: { origin: new origins.S3Origin(bucket) } }); // Original MyStack with just the function const myStack = new cdk.Stack(app, 'MyStack'); const function = new lambda.Function(myStack, 'Function', { // function properties }); // Synthesize the app app.synth();

如果没有 CDK 重构,这些更改将 AWS CloudFormation 导致创建新资源并删除旧资源,因为逻辑 IDs 会发生变化:

  • MyStack/Bucket/Resource 会变为 WebStack/WebsiteOrigin/Resource

  • MyStack/Distribution/Resource 会变为 WebStack/Distribution/Resource

通过 CDK 重构,CDK CLI 可以检测到这些路径变化,并使用其重构功能 AWS CloudFormation来保留底层资源。运行 cdk refactor 后,CLI 会显示它将进行的更改:

$ cdk refactor The following resources were moved or renamed: ┌───────────────────────────────┬───────────────────────────────┬───────────────────────────────────┐ │ Resource Type │ Old Construct Path │ New Construct Path │ ├───────────────────────────────┼───────────────────────────────┼───────────────────────────────────┤ │ AWS::S3::Bucket │ MyStack/Bucket/Resource │ WebStack/WebsiteOrigin/Resource │ ├───────────────────────────────┼───────────────────────────────┼───────────────────────────────────┤ │ AWS::CloudFront::Distribution │ MyStack/Distribution/Resource │ WebStack/Distribution/Resource │ └───────────────────────────────┴───────────────────────────────┴───────────────────────────────────┘ Do you wish refactor these resources (y/n)?

输入 y 确认后,CDK CLI 会显示重构操作的进度:

Refactoring... ✅ Stack refactor complete

确认后,CDK CLI 将运行重构操作,保留这两个资源,同时更新其逻辑 IDs 以匹配您的新代码结构。

cdk diff 命令的输出也会显示相同映射,按堆栈进行组织:

Stack MyStack Resources [-] AWS::S3::Bucket Bucket Bucket1234567 destroy (OR move to WebStack.WebsiteOrigin1234567 via refactoring) [-] AWS::CloudFront::Distribution Distribution Distribution1234567 destroy (OR move to WebStack.Distribution1234567) ... Stack WebStack Resources [+] AWS::S3::Bucket WebsiteOrigin WebsiteOrigin1234567 (OR move from MyStack.Bucket1234567) [+] AWS::CloudFront::Distribution Distribution Distribution1234567 (OR move from MyStack.Distribution1234567) ...

开始使用 CDK 重构

要开始重构,请完成下面的先决条件:

使用最新模板引导环境

CDK 重构在引导堆栈中需要新权限。为确保您拥有必要的权限,请使用最新模板引导您的环境:

cdk bootstrap

有关引导的更多信息,请参阅 AWS CDK 的引导环境

安装最新的 CDK CLI 版本

CDK 重构需要最新版本的 CDK CLI。为了确保您拥有最新版本,请运行以下命令:

npm install -g aws-cdk

有关详细的安装说明,请参阅开始使用 AWS CDK

使用覆盖文件来解决重构中的歧义

CDK CLI 会根据您的代码与已部署资源的比较结果自动计算所有资源映射。大多数情况下,这种自动检测效果很好,但有时 CLI 可能会遇到它自己无法解决的歧义。要为 CDK CLI 提供指导,请使用覆盖文件。

创建覆盖文件以解决歧义

覆盖文件是一个 JSON 文件,用于在 CDK CLI 无法确定资源的重构解析时提供映射。该文件包含按环境组织的资源映射:

{ "environments": [ { "account": "123456789012", "region": "us-east-2", "resources": { "StackA.OldName": "StackB.NewName", "StackC.Foo": "StackC.Bar" } } ] }

在此文件中:

  • environments 数组包含一个或多个带有账户和区域信息的环境条目。

  • 在每个环境内,resources 对象都包含映射。

  • 键表示当前位置,格式为 <stack name>.<logical ID>

  • 值表示新位置,格式相同。

要将覆盖文件与 CDK CLI 一起使用,请运行以下命令:

cdk refactor --override-file=overrides.json

跨多个环境重构堆栈

一个 CDK 应用程序可以包含部署到不同环境(AWS 账户和区域)的多个堆栈。在重构此类应用程序期间,为了保留资源,CDK CLI 会以特定方式处理环境:

  • CLI 会按环境对堆栈进行分组,并在每个环境中分别执行重构。

  • 重构期间,您可以在堆栈之间移动资源,但所有参与移动的堆栈必须位于同一环境中。

  • 尝试跨环境移动资源将导致错误。

这种行为可确保资源保留在其原始 AWS 账户和区域内,这是必要的,因为 CloudFormation 资源无法在账户或区域边界之间实际移动。

例如,如果您的 CDK 应用程序针对开发环境和生产环境都定义了堆栈,则重构操作将在每个环境中独立执行。资源可以在开发环境或生产环境内的堆栈之间移动,但不能从开发环境移动到生产环境,反之亦然。

处理需要替换的资源

某些 CDK 构造依赖于 CloudFormation的资源替换行为作为其设计的一部分。例如,API Gateway 的 Deployment 和 Lambda 的 Version 构造都旨在当资源属性发生变化时创建新资源。

重构时,请勿进行任何会导致资源替换的更改。否则,CDK CLI 可能会检测到并保留这些资源。这意味着需要替换的资源必须与重构操作分开处理。

要正确管理需要替换的资源,请执行以下操作:

  1. 首先,部署您的应用程序,根据需要替换这些资源。

  2. 然后,分别执行重构操作来重新组织代码。

这种两步法确保需要替换的资源得到正确处理,同时还能让您从其他资源的 CDK 重构中受益。

一般注意事项和限制

在 CDK 重构期间保留资源时,请记住以下注意事项:

  • 环境约束:资源只能在同一环境内的不同堆栈之间移动。不支持跨环境移动。

  • 歧义:如果您同时重命名多个相同的资源,CDK CLI 可能无法自动确定正确的映射。在这些情况下,您需要使用覆盖文件提供显式映射。

  • 引导要求:要在重构期间保留资源,您需要将引导堆栈更新到包含必要权限的最新版本。

  • 排除某些构造:某些构造(例如 API Gateway 的 Deployment 和 Lambda 的 Version)依赖于资源替换,因此会自动从重构中排除。

使用管道进行重构 CI/CD

要在 CI/CD 管道中使用重构功能,您需要能够将 CDK CLI 作为管道的一部分运行。以下是将重构集成到工作流程中的 CI/CD 一些重要注意事项。

在 CI/CD 中使用重构的先决条件

您必须能够在您的 CI/CD 环境中使用 CDK CLI 才能从此功能中受益。

将重构集成到管线工作流中

如果您在 CI/CD 管道中使用 CLI 进行部署,则脚本通常如下所示:

... cdk deploy <stack filter> ...

如果要将重构纳入工作流,下面是一个基本示例:

... cdk refactor <stack filter> cdk deploy <stack filter> ...

您也可以将重构作为管线中的一个单独步骤。

处理重构失败

请注意,如果您的代码在重构的同时还包含实际的资源修改,则 cdk refactor 将会失败。由于您在管线中自动调用了重构,因此需要处理潜在失败:

# Allow refactoring to fail but continue the pipeline cdk refactor <stack filter> || true cdk deploy <stack filter>

或者,您可能需要确保在成功完成重构之前不要进行任何部署:

# Only deploy if refactoring succeeds cdk refactor <stack filter> && cdk deploy <stack filter>
CI/CD 环境最佳实践

要在管道中 CI/CD 有效地使用重构,请执行以下操作:

  • 将重构与其他变更分开:请记住,重构操作必须与资源的添加、删除或修改分开。在您的管线中,请考虑为重构采用专用的提交和部署。

  • 适当使用覆盖文件:请注意,CDK CLI 仅将覆盖文件用作解决歧义情况的备用方案。

  • 无需--force在管道中使用:在管道等 CI/CD 非交互式环境中,CDK 重构命令会自动执行而不提示确认。--force 选项仅在交互式环境中需要。

相关资源

有关 CDK CLI cdk refactor 命令的选项和参数的信息,请参阅 cdk refactor

要开始使用 CDK 工具包库的 refactor 操作,请参阅使用 CDK 工具包库执行编程操作