这是 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();
现在,假设你想将这段代码重构为:
-
将存储桶从重命名
Bucket
为更具描述性的WebsiteOrigin
存储桶。 -
将存储桶和发行版移至新
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 可能会检测并保留这些资源。这意味着设计为替换的资源必须与重构操作分开处理。
要正确管理设计为要替换的资源,请执行以下操作:
-
首先,部署您的应用程序以根据需要替换这些资源。
-
然后,分别执行重构操作以重新组织代码。
这种分为两步的方法可确保正确处理旨在替换的资源,同时仍然允许您从针对其他资源的 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 工具包库执行编程操作。