重构 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 工具包库的操作执行 CDK 重构。refactor本指南主要讨论 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 代码的同时保留已部署的资源。cdk refactor

我们的示例 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 可能无法自动确定正确的映射。在这些情况下,您需要使用覆盖文件提供显式映射。

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

  • 某些结构被排除在外:某些构造(例如 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会失败。由于你在管道中自动调用 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 工具包库执行编程操作