

# スタックリファクタリング
<a name="stack-refactoring"></a>

スタックリファクタリングを使用すると、既存のリソースプロパティとデータを維持しながら CloudFormation スタック内のリソースを再編成できます。スタック間でのリソースの移動、大きなスタックの小さなスタックへの分割、または複数スタックの 1 つのスタックへの統合が可能です。

**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 は空のスタックをサポートしません。リファクタリングによってスタックがリソースのない状態になる場合は、まずそのスタックに少なくとも 1 つのリソースを追加してから [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. **[説明]** では、スタックのリファクタリングを識別するのに役立つ説明を入力します。その後、**[Next]** を選択します。

1. [スタック 1] で、以下を行います。

   1. **[既存のスタックのテンプレートを更新する]** または **[新しいスタックを作成する]** を選択します。

      **[既存のスタックのテンプレートを更新する]** を選択した場合は、リストから既存のスタックを選択します。または、**[スタック ARN を入力する]** を選択して、既存のスタックの ARN を入力します。

      **[新しいスタックを作成する]** を選択した場合は、**[スタック名]** で新しいスタックの名前を指定します。

   1. **[既存のテンプレートをリファクタリングされたテンプレートに置き換える]** で、**[Amazon S3 URL]** または **[テンプレートファイルをアップロードする]** を選択して、スタック 1 で必要なテンプレートをアップロードします。

   1. [**次へ**] を選択します。

1. [スタック 2] で、以下を行います。

   1. **[既存のスタックのテンプレートを更新する]** または **[新しいスタックを作成する]** を選択します。

      **[既存のスタックのテンプレートを更新する]** を選択した場合は、リストから既存のスタックを選択します。または、**[スタック ARN を入力する]** を選択して、既存のスタックの ARN を入力します。

      **[新しいスタックを作成する]** を選択した場合は、**[スタック名]** で新しいスタックの名前を指定します。

   1. **既存のテンプレートをリファクタリングされたテンプレートに置き換える]** で、**[Amazon S3 URL]** または **[テンプレートファイルをアップロードする]** を選択して、スタック 2 で必要なテンプレートをアップロードします。

   1. [**次へ**] を選択します。

1. **[論理リソース ID の名前変更を指定する]** ページで、表示されたリソースを正しい論理 ID にマッピングすることで、CloudFormation がスタックのリファクタリング方法を知っていることを確認します。スタックリファクタリングの一部として、リソースの論理 ID が変更された場合は、ソーススタック名、元の論理 ID、送信先スタック名、および名前が変更された論理 ID を指定して、名前の変更方法を指定する必要があります。場合によっては、CloudFormation コンソールによってリソースマッピングが自動的に検出され、先に進む前に、事前に入力されたリソースマッピングが正しいことを確認できます。

1. [**次へ**] を選択します。

1. **[確認して実行する]** ページで、前のステップで選択したすべての内容を確認し、すべてが正しくセットアップされていることを確認します。

1. スタックをリファクタリングする準備ができたら、**[スタックリファクタリングを実行]** を選択します。

## スタックをリファクタリングする (AWS CLI)
<a name="stack-refactoring-cli"></a>

スタックリファクタリングの AWS CLI コマンドには以下が含まれます。
+ 計画された変更を検証してプレビューを生成するための [create-stack-refactor](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)。
+ リファクタリングの実行中に CloudFormation が各スタックとリソースに対して実行する特定のアクションのプレビューを表示するための [list-stack-refactor-actions](https://docs.aws.amazon.com/cli/latest/reference/cloudformation/list-stack-refactor-actions.html)。

AWS CLI を使用してスタックをリファクタリングするには、以下の手順を実行します。

**スタックをリファクタリングするには**

1. [create-stack-refactor](https://docs.aws.amazon.com/cli/latest/reference/cloudformation/create-stack-refactor.html) コマンドを使用して、リファクタリングするスタックのスタック名と更新されたテンプレートを指定します。新しいスタックがまだ存在しない場合は、CloudFormation が新しいスタックを作成できるようにする `--enable-stack-creation` オプションを含めます。

   ```
   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"
   }
   ```

   テンプレートの検証中に競合が検出された場合は (次のステップで確認できます)、[create-stack-refactor](https://docs.aws.amazon.com/cli/latest/reference/cloudformation/create-stack-refactor.html) コマンドを `--resource-mappings` オプションとともに使用します。

   ```
   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`