

# 堆栈重构
<a name="stack-refactoring"></a>

通过堆栈重构，可以重新组织 CloudFormation 堆栈中的资源，同时保留现有资源属性和数据。您可以在堆栈之间移动资源，将大堆栈拆分为小堆栈，或将多个堆栈合并为一个堆栈。

**Topics**
+ [堆栈重构的工作原理](#stack-refactoring-overview)
+ [堆栈重构注意事项](#stack-refactoring-considerations)
+ [先决条件](#stack-refactoring-prerequisites)
+ [重构堆栈（控制台）](#stack-refactoring-console)
+ [重构堆栈（AWS CLI）](#stack-refactoring-cli)
+ [资源限制](#stack-refactoring-resource-limitations)

## 堆栈重构的工作原理
<a name="stack-refactoring-overview"></a>

重构堆栈涉及下列阶段：

1. **评估当前基础设施** – 检查现有 CloudFormation 堆栈和资源，以确定堆栈重构的机会。

1. **规划重构** – 定义应如何组织资源。应注意相关依赖项、命名惯例和操作限制。这些因素可能会影响 CloudFormation 稍后进行的验证。

1. **确定目标堆栈** – 决定要将资源重构到哪些堆栈。您可以在至少 2 个堆栈（使用控制台）和最多 5 个堆栈（使用 AWS CLI）之间移动资源。资源可以在嵌套堆栈之间移动。

1. **更新模板** – 更改 CloudFormation 模板以反映计划的更改，例如在模板之间移动资源定义。在此过程中，您可以重命名逻辑 ID。

1. **创建堆栈重构** – 提供要重构的堆栈名称和模板列表。

1. **检查重构影响并解决任何冲突** – CloudFormation 验证您提供的模板并检查跨堆栈依赖项、存在标签更新问题的资源类型以及资源逻辑 ID 冲突。

   如果验证成功，CloudFormation 将生成执行期间发生的重构操作的预览。

   如果验证失败，请解决已发现的问题并重试。对于冲突，请提供资源逻辑 ID 映射，显示冲突资源的源和目标。

1. **执行重构** – 确认更改符合重构目标后，完成堆栈重构。

1. **监控** – 跟踪执行状态以确保操作成功完成。

## 堆栈重构注意事项
<a name="stack-refactoring-considerations"></a>

在重构堆栈时，请记住以下几点：
+ 堆栈重构仅限于重新整理现有资源。在重构过程中，您无法创建或删除资源、修改资源配置，也无法更改或添加新的参数、条件或映射关系。要进行这些更改，请先更新您的堆栈，然后再执行堆栈重构。
+ 您不能将同一资源重构到多个堆栈。
+ 您无法重构引用源堆栈和目标堆栈之间的值不同的伪参数的资源，例如 `AWS::StackName`。
+ CloudFormation 不支持空堆栈。如果重构会导致堆栈没有资源，则必须先向堆栈添加至少一个资源，然后再运行 [create-stack-refactor](https://docs.aws.amazon.com/cli/latest/reference/cloudformation/create-stack-refactor.html)。这可以是像 `AWS::SNS::Topic` 或 `AWS::CloudFormation::WaitCondition` 这样的简单资源。例如：

  ```
  Resources:
    MySimpleSNSTopic:
      Type: AWS::SNS::Topic
      Properties:
        DisplayName: MySimpleTopic
  ```
+ 无论策略允许或拒绝什么，堆栈重构都不支持附加了堆栈策略的堆栈。

## 先决条件
<a name="stack-refactoring-prerequisites"></a>

要重构堆栈，您必须已经创建了修订后的模板。

使用 [get-template](https://docs.aws.amazon.com/cli/latest/reference/cloudformation/get-template.html) 命令检索要重构的堆栈的 CloudFormation 模板。

```
aws cloudformation get-template --stack-name Stack1
```

拥有模板后，请使用您选择的集成式开发环境 (IDE) 对其进行更新，以便使用所需的结构和资源组织。

## 重构堆栈（控制台）
<a name="stack-refactoring-console"></a>

使用以下过程通过控制台重构堆栈。

**要重构堆栈**

1. 登录到 AWS 管理控制台 并打开 CloudFormation 控制台 [https://console.aws.amazon.com/cloudformation](https://console.aws.amazon.com/cloudformation/)。

1. 在屏幕顶部的导航栏中，选择您的堆栈所在的 AWS 区域。

1. 在左侧导航窗格中，选择**堆栈重构**。

1. 在**堆栈重构**页面上，选择**启动堆栈重构**。

1. 对于**描述**，提供一段描述，以帮助您确定您的堆栈重构。然后选择**下一步**。

1. 对于堆栈 1，请执行以下操作：

   1. 选择**更新现有堆栈的模板**或**创建新堆栈**。

      如果您选择了**更新现有堆栈的模板**，则从列表中选择一个现有堆栈。或者选择**输入堆栈 ARN**，以输入现有堆栈的 ARN。

      如果您选择了**创建新堆栈**，请在**堆栈名称**中提供新堆栈的名称。

   1. 在**用重构后的模板替换现有模板**下，选择 **Amazon S3 URL** 或**上传模板文件**，为堆栈 1 上传所需的模板。

   1. 选择**下一步**。

1. 对于堆栈 2，请执行以下操作：

   1. 选择**更新现有堆栈的模板**或**创建新堆栈**。

      如果您选择了**更新现有堆栈的模板**，则从列表中选择一个现有堆栈。或者选择**输入堆栈 ARN**，以输入现有堆栈的 ARN。

      如果您选择了**创建新堆栈**，请在**堆栈名称**中提供新堆栈的名称。

   1. 在**用重构后的模板替换现有模板**下，选择 **Amazon S3 URL** 或**上传模板文件**，为堆栈 2 上传所需的模板。

   1. 选择**下一步**。

1. 在**指定逻辑资源 ID 重命名**页面上，确保 CloudFormation 知道如何通过将所显示的任何资源映射到正确的逻辑 ID 来实现对栈的重构操作。在堆栈重构的过程中，如果更改了任何资源的逻辑 ID，则需要通过提供源堆栈名称、原始逻辑 ID、目标堆栈名称和重命名的逻辑 ID 来指定其重命名方式。在某些情况下，CloudFormation 控制台可能会自动识别资源映射，您只需在继续操作前确认预填好的资源映射正确即可。

1. 选择**下一步**。

1. 在**审核并执行**页面上，审核前面的步骤中所做的所有选择，并确认所有设置都已正确完成。

1. 准备好重构堆栈时，请选择**执行堆栈重构**。

## 重构堆栈（AWS CLI）
<a name="stack-refactoring-cli"></a>

用于堆栈重构的 AWS CLI 命令包括：
+ [create-stack-refactory](https://docs.aws.amazon.com/cli/latest/reference/cloudformation/create-stack-refactor.html)，验证和生成计划更改的预览。
+ [describe-stack-refactor](https://docs.aws.amazon.com/cli/latest/reference/cloudformation/describe-stack-refactor.html)，检索堆栈重构操作的状态和详细信息。
+ [execute-stack-refactor](https://docs.aws.amazon.com/cli/latest/reference/cloudformation/execute-stack-refactor.html)，完成经过验证的堆栈重构操作。
+ [list-stack-refactors](https://docs.aws.amazon.com/cli/latest/reference/cloudformation/list-stack-refactors.html)，列出您账户中的所有堆栈重构操作及其当前状态和基本信息。
+ [list-stack-refactor-actions](https://docs.aws.amazon.com/cli/latest/reference/cloudformation/list-stack-refactor-actions.html)，显示重构执行期间 CloudFormation 将对每个堆栈和资源执行的特定操作的预览。

使用以下过程通过 AWS CLI 重构堆栈。

**要重构堆栈**

1. 使用 [create-stack-refactor](https://docs.aws.amazon.com/cli/latest/reference/cloudformation/create-stack-refactor.html) 命令，为要重构的堆栈提供堆栈名称和更新的模板。包括 `--enable-stack-creation` 选项以允许 CloudFormation 创建新堆栈（如果它们尚不存在）。

   ```
   aws cloudformation create-stack-refactor \
     --stack-definitions \
       StackName=Stack1,TemplateBody@=file://template1-updated.yaml \
       StackName=Stack2,TemplateBody@=file://template2-updated.yaml \
     --enable-stack-creation
   ```

   该命令会返回 `StackRefactorId`，您将在后续步骤中使用它。

   ```
   {
       "StackRefactorId": "9c384f70-4e07-4ed7-a65d-fee5eb430841"
   }
   ```

   如果在模板验证期间检测到冲突（您可以在下一步中确认），请使用带有 `--resource-mappings` 选项的 [create-stack-refactor](https://docs.aws.amazon.com/cli/latest/reference/cloudformation/create-stack-refactor.html) 命令。

   ```
   aws cloudformation create-stack-refactor \
     --stack-definitions \
       StackName=Stack1,TemplateBody@=file://template1-updated.yaml \
       StackName=Stack2,TemplateBody@=file://template2-updated.yaml \
     --enable-stack-creation \ 
     --resource-mappings file://resource-mapping.json
   ```

   下面是一个 `resource-mapping.json` 示例文件。

   ```
   [
       {
           "Source": {
               "StackName": "Stack1",
               "LogicalResourceId": "MySNSTopic"
           },
           "Destination": {
               "StackName": "Stack2",
               "LogicalResourceId": "MyLambdaSNSTopic"
           }
       }
   ]
   ```

1. 使用 [describe-stack-refactor](https://docs.aws.amazon.com/cli/latest/reference/cloudformation/describe-stack-refactor.html) 命令确保 `Status` 为 `CREATE_COMPLETE`。这确认验证是否已完成。

   ```
   aws cloudformation describe-stack-refactor \
     --stack-refactor-id 9c384f70-4e07-4ed7-a65d-fee5eb430841
   ```

   输出示例：

   ```
   {
       "StackRefactorId": "9c384f70-4e07-4ed7-a65d-fee5eb430841",
       "StackIds": [
           "arn:aws:cloudformation:us-east-1:123456789012:stack/Stack1/3e6a1ff0-94b1-11f0-aa6f-0a88d2e03acf",
           "arn:aws:cloudformation:us-east-1:123456789012:stack/Stack2/5da91650-94b1-11f0-81cf-0a23500e151b"
       ],
       "ExecutionStatus": "AVAILABLE",
       "Status": "CREATE_COMPLETE"
   }
   ```

1. 使用 [list-stack-refactor-actions](https://docs.aws.amazon.com/cli/latest/reference/cloudformation/list-stack-refactor-actions.html) 命令预览将执行的特定操作。

   ```
   aws cloudformation list-stack-refactor-actions \
     --stack-refactor-id 9c384f70-4e07-4ed7-a65d-fee5eb430841
   ```

   输出示例：

   ```
   {
       "StackRefactorActions": [
           {
               "Action": "MOVE",
               "Entity": "RESOURCE",
               "PhysicalResourceId": "MyTestLambdaRole",
               "Description": "No configuration changes detected.",
               "Detection": "AUTO",
               "TagResources": [],
               "UntagResources": [],
               "ResourceMapping": {
                   "Source": {
                       "StackName": "arn:aws:cloudformation:us-east-1:123456789012:stack/Stack1/3e6a1ff0-94b1-11f0-aa6f-0a88d2e03acf",
                       "LogicalResourceId": "MyLambdaRole"
                   },
                   "Destination": {
                       "StackName": "arn:aws:cloudformation:us-east-1:123456789012:stack/Stack2/5da91650-94b1-11f0-81cf-0a23500e151b",
                       "LogicalResourceId": "MyLambdaRole"
                   }
               }
           },
           {
               "Action": "MOVE",
               "Entity": "RESOURCE",
               "PhysicalResourceId": "MyTestFunction",
               "Description": "Resource configuration changes will be validated during refactor execution.",
               "Detection": "AUTO",
               "TagResources": [
                   {
                       "Key": "aws:cloudformation:stack-name",
                       "Value": "Stack2"
                   },
                   {
                       "Key": "aws:cloudformation:logical-id",
                       "Value": "MyFunction"
                   },
                   {
                       "Key": "aws:cloudformation:stack-id",
                       "Value": "arn:aws:cloudformation:us-east-1:123456789012:stack/Stack2/5da91650-94b1-11f0-81cf-0a23500e151b"
                   }
               ],
               "UntagResources": [
                   "aws:cloudformation:stack-name",
                   "aws:cloudformation:logical-id",
                   "aws:cloudformation:stack-id"
               ],
               "ResourceMapping": {
                   "Source": {
                       "StackName": "arn:aws:cloudformation:us-east-1:123456789012:stack/Stack1/3e6a1ff0-94b1-11f0-aa6f-0a88d2e03acf",
                       "LogicalResourceId": "MyFunction"
                   },
                   "Destination": {
                       "StackName": "arn:aws:cloudformation:us-east-1:123456789012:stack/Stack2/5da91650-94b1-11f0-81cf-0a23500e151b",
                       "LogicalResourceId": "MyFunction"
                   }
               }
           }
       ]
   }
   ```

1. 检查并确认更改后，使用 [execute-stack-refactor](https://docs.aws.amazon.com/cli/latest/reference/cloudformation/execute-stack-refactor.html) 命令完成堆栈重构操作。

   ```
   aws cloudformation execute-stack-refactor \
     --stack-refactor-id 9c384f70-4e07-4ed7-a65d-fee5eb430841
   ```

1. 使用 [describe-stack-refactor](https://docs.aws.amazon.com/cli/latest/reference/cloudformation/describe-stack-refactor.html) 命令监视执行状态。

   ```
   aws cloudformation describe-stack-refactor \
     --stack-refactor-id 9c384f70-4e07-4ed7-a65d-fee5eb430841
   ```

   输出示例：

   ```
   {
       "StackRefactorId": "9c384f70-4e07-4ed7-a65d-fee5eb430841",
       "StackIds": [
           "arn:aws:cloudformation:us-east-1:123456789012:stack/Stack1/3e6a1ff0-94b1-11f0-aa6f-0a88d2e03acf",
           "arn:aws:cloudformation:us-east-1:123456789012:stack/Stack2/5da91650-94b1-11f0-81cf-0a23500e151b"
       ],
       "ExecutionStatus": "SUCCEEDED",
       "Status": "COMPLETE"
   }
   ```

## 资源限制
<a name="stack-refactoring-resource-limitations"></a>
+ 堆栈重构仅支持 `provisioningType` 为 `FULLY_MUTABLE` 的资源类型，您可以使用 [describe-type](https://docs.aws.amazon.com/cli/latest/reference/cloudformation/describe-type.html) 命令进行检查。
+ CloudFormation 将在重构创建期间验证资源资格，并在 [describe-stack-refactor](https://docs.aws.amazon.com/cli/latest/reference/cloudformation/describe-stack-refactor.html) 命令的输出中报告任何不受支持的资源。
+ 以下资源不支持堆栈重构：
  + `AWS::ACMPCA::Certificate`
  + `AWS::ACMPCA::CertificateAuthority`
  + `AWS::ACMPCA::CertificateAuthorityActivation`
  + `AWS::ApiGateway::BasePathMapping`
  + `AWS::ApiGateway::Method`
  + `AWS::AppConfig::ConfigurationProfile`
  + `AWS::AppConfig::Deployment`
  + `AWS::AppConfig::Environment`
  + `AWS::AppConfig::Extension`
  + `AWS::AppConfig::ExtensionAssociation`
  + `AWS::AppStream::DirectoryConfig`
  + `AWS::AppStream::StackFleetAssociation`
  + `AWS::AppStream::StackUserAssociation`
  + `AWS::AppStream::User`
  + `AWS::BackupGateway::Hypervisor`
  + `AWS::CertificateManager::Certificate`
  + `AWS::CloudFormation::CustomResource`
  + `AWS::CloudFormation::Macro`
  + `AWS::CloudFormation::WaitCondition`
  + `AWS::CloudFormation::WaitConditionHandle`
  + `AWS::CodeDeploy::DeploymentGroup`
  + `AWS::CodePipeline::CustomActionType`
  + `AWS::Cognito::UserPoolRiskConfigurationAttachment`
  + `AWS::Cognito::UserPoolUICustomizationAttachment`
  + `AWS::Cognito::UserPoolUserToGroupAttachment`
  + `AWS::Config::ConfigRule`
  + `AWS::Config::ConfigurationRecorder`
  + `AWS::Config::DeliveryChannel`
  + `AWS::DataBrew::Dataset`
  + `AWS::DataBrew::Job`
  + `AWS::DataBrew::Project`
  + `AWS::DataBrew::Recipe`
  + `AWS::DataBrew::Ruleset`
  + `AWS::DataBrew::Schedule`
  + `AWS::DataZone::DataSource`
  + `AWS::DataZone::Environment`
  + `AWS::DataZone::EnvironmentBlueprintConfiguration`
  + `AWS::DataZone::EnvironmentProfile`
  + `AWS::DataZone::Project`
  + `AWS::DataZone::SubscriptionTarget`
  + `AWS::DirectoryService::MicrosoftAD`
  + `AWS::DynamoDB::GlobalTable`
  + `AWS::EC2::CustomerGateway`
  + `AWS::EC2::EIP`
  + `AWS::EC2::LaunchTemplate`
  + `AWS::EC2::NetworkInterfacePermission`
  + `AWS::EC2::PlacementGroup`
  + `AWS::EC2::SpotFleet`
  + `AWS::EC2::VPCDHCPOptionsAssociation`
  + `AWS::EC2::VolumeAttachment`
  + `AWS::EMR::Cluster`
  + `AWS::EMR::InstanceFleetConfig`
  + `AWS::EMR::InstanceGroupConfig`
  + `AWS::ElastiCache::CacheCluster`
  + `AWS::ElastiCache::ReplicationGroup`
  + `AWS::ElastiCache::SecurityGroup`
  + `AWS::ElastiCache::SecurityGroupIngress`
  + `AWS::ElasticBeanstalk::ConfigurationTemplate`
  + `AWS::ElasticLoadBalancing::LoadBalancer`
  + `AWS::ElasticLoadBalancingV2::ListenerCertificate`
  + `AWS::Elasticsearch::Domain`
  + `AWS::FIS::ExperimentTemplate`
  + `AWS::Glue::Schema`
  + `AWS::GuardDuty::IPSet`
  + `AWS::GuardDuty::PublishingDestination`
  + `AWS::GuardDuty::ThreatIntelSet`
  + `AWS::IAM::AccessKey`
  + `AWS::IAM::UserToGroupAddition`
  + `AWS::ImageBuilder::Component`
  + `AWS::IoT::PolicyPrincipalAttachment`
  + `AWS::IoT::ThingPrincipalAttachment`
  + `AWS::IoTFleetWise::Campaign`
  + `AWS::IoTWireless::WirelessDeviceImportTask`
  + `AWS::Lambda::EventInvokeConfig`
  + `AWS::Lex::BotVersion`
  + `AWS::M2::Application`
  + `AWS::MSK::Configuration`
  + `AWS::MSK::ServerlessCluster`
  + `AWS::Maester::DocumentType`
  + `AWS::MediaTailor::Channel`
  + `AWS::NeptuneGraph::PrivateGraphEndpoint`
  + `AWS::Omics::AnnotationStore`
  + `AWS::Omics::ReferenceStore`
  + `AWS::Omics::SequenceStore`
  + `AWS::OpenSearchServerless::Collection`
  + `AWS::OpsWorks::App`
  + `AWS::OpsWorks::ElasticLoadBalancerAttachment`
  + `AWS::OpsWorks::Instance`
  + `AWS::OpsWorks::Layer`
  + `AWS::OpsWorks::Stack`
  + `AWS::OpsWorks::UserProfile`
  + `AWS::OpsWorks::Volume`
  + `AWS::PCAConnectorAD::Connector`
  + `AWS::PCAConnectorAD::DirectoryRegistration`
  + `AWS::PCAConnectorAD::Template`
  + `AWS::PCAConnectorAD::TemplateGroupAccessControlEntry`
  + `AWS::Panorama::PackageVersion`
  + `AWS::QuickSight::Theme`
  + `AWS::RDS::DBSecurityGroup`
  + `AWS::RDS::DBSecurityGroupIngress`
  + `AWS::Redshift::ClusterSecurityGroup`
  + `AWS::Redshift::ClusterSecurityGroupIngress`
  + `AWS::RefactorSpaces::Environment`
  + `AWS::RefactorSpaces::Route`
  + `AWS::RefactorSpaces::Service`
  + `AWS::RoboMaker::RobotApplication`
  + `AWS::RoboMaker::SimulationApplication`
  + `AWS::Route53::RecordSet`
  + `AWS::Route53::RecordSetGroup`
  + `AWS::SDB::Domain`
  + `AWS::SageMaker::InferenceComponen`
  + `AWS::ServiceCatalog::PortfolioPrincipalAssociation`
  + `AWS::ServiceCatalog::PortfolioProductAssociation`
  + `AWS::ServiceCatalog::PortfolioShare`
  + `AWS::ServiceCatalog::TagOptionAssociation`
  + `AWS::ServiceCatalogAppRegistry::AttributeGroupAssociation`
  + `AWS::ServiceCatalogAppRegistry::ResourceAssociation`
  + `AWS::StepFunctions::StateMachineVersion`
  + `AWS::Synthetics::Canary`
  + `AWS::VoiceID::Domain`
  + `AWS::WAF::ByteMatchSet`
  + `AWS::WAF::IPSet`
  + `AWS::WAF::Rule`
  + `AWS::WAF::SizeConstraintSet`
  + `AWS::WAF::SqlInjectionMatchSet`
  + `AWS::WAF::WebACL`
  + `AWS::WAF::XssMatchSet`
  + `AWS::WAFv2::IPSet`
  + `AWS::WAFv2::RegexPatternSet`
  + `AWS::WAFv2::RuleGroup`
  + `AWS::WAFv2::WebACL`
  + `AWS::WorkSpaces::Workspace`