스택 리팩터링 - AWS CloudFormation

스택 리팩터링

스택 리팩터링을 사용하면 기존 리소스 속성 및 데이터를 유지하면서 CloudFormation 스택에서 리소스를 재구성할 수 있습니다. 스택 간에 리소스를 이동하거나, 대형 스택을 더 작은 스택으로 분할하거나, 여러 스택을 하나의 스택으로 결합할 수 있습니다.

스택 리팩터링 작동 방식

스택 리팩터링에는 다음 단계가 포함됩니다.

  1. 현재 인프라 평가 - 기존 CloudFormation 스택 및 리소스를 검토하여 스택 리팩터링 기회를 식별합니다.

  2. 리팩터링 계획 - 리소스를 구성하는 방법을 정의합니다. 종속 항목, 이름 지정 규칙 및 운영 제한을 고려합니다. 나중에 CloudFormation 검증에 영향을 미칠 수 있습니다.

  3. 대상 스택 결정 - 리소스를 리팩터링할 스택을 결정합니다. 최소 2개 스택에서 최대 5개 스택 간에 리소스를 이동할 수 있습니다. 중첩 스택 사이에서 리소스를 이동할 수 있습니다.

  4. 템플릿 업데이트 - 템플릿 사이에서 리소스 정의를 이동하는 등 계획된 변경 사항을 반영하도록 CloudFormation 템플릿을 변경합니다. 이 프로세스 중에 논리적 ID의 이름을 바꿀 수 있습니다.

  5. 스택 리팩터링 생성 - 리팩터링하려는 스택 이름 및 템플릿의 목록을 제공합니다.

  6. 리팩터링 영향 검토 및 충돌 해결 - CloudFormation은 사용자가 제공하는 템플릿을 검증하고 스택 간 종속성, 태그 업데이트 문제가 있는 리소스 유형 및 리소스 논리적 ID 충돌을 확인합니다.

    검증이 성공하면 CloudFormation은 실행 중에 발생할 리팩터링 작업의 미리 보기를 생성합니다.

    검증이 실패하면 식별된 문제를 해결하고 다시 시도합니다. 충돌이 있는 경우 충돌하는 리소스의 소스 및 대상을 보여주는 리소스 논리적 ID 매핑을 제공합니다.

  7. 리팩터링 실행 - 변경 사항이 리팩터링 목표에 부합하는지 확인한 후 스택 리팩터링을 완료합니다.

  8. 모니터링 - 실행 상태를 추적하여 작업이 성공적으로 완료되는지 확인합니다.

스택 리팩터링 고려 사항

스택을 리팩터링할 때 다음 사항에 유의하세요.

  • 리팩터링 작업에서는 새 리소스 생성, 리소스 삭제 또는 리소스 구성 변경을 허용하지 않습니다.

  • 스택 리팩터링 중에는 새 파라미터, 조건 또는 매핑을 변경하거나 추가할 수 없습니다. 가능한 해결 방법은 리팩터링을 수행하기 전에 스택을 업데이트하는 것입니다.

  • 동일한 리소스를 여러 스택으로 리팩터링할 수 없습니다.

  • AWS::StackName과 같이 소스 스택과 대상 스택 간에 값이 다른 가상 파라미터를 참조하는 리소스는 리팩터링할 수 없습니다.

  • CloudFormation은 빈 스택을 지원하지 않습니다. 리팩터링으로 인해 스택에 리소스가 없게 되는 경우 create-stack-refactor를 실행하기 전에 먼저 해당 스택에 리소스를 하나 이상 추가해야 합니다. 이는 AWS::SNS::Topic 또는 AWS::CloudFormation::WaitCondition과 같은 간단한 리소스일 수 있습니다. 예:

    Resources: MySimpleSNSTopic: Type: AWS::SNS::Topic Properties: DisplayName: MySimpleTopic
  • 스택 리팩터링은 정책이 허용 또는 거부하는 대상과 관계없이 스택 정책이 연결된 스택을 지원하지 않습니다.

스택 리팩터링을 위한 AWS CLI 명령

스택 리팩터링을 위한 AWS CLI 명령은 다음과 같습니다.

  • create-stack-refactor: 계획된 변경 사항을 검증하고 미리 보기를 생성합니다.

  • describe-stack-refactor: 스택 리팩터링 작업의 상태 및 세부 정보를 검색합니다.

  • execute-stack-refactor: 검증된 스택 리팩터링 작업을 완료합니다.

  • get-template: 기존 스택의 템플릿을 검색합니다.

  • list-stack-refactors: 계정의 모든 스택 리팩터링 작업을 현재 상태 및 기본 정보와 함께 나열합니다.

  • list-stack-refactor-actions: CloudFormation이 리팩터링 실행 중에 각 스택 및 리소스에서 수행할 특정 작업에 대한 미리 보기를 표시합니다.

AWS CLI을 사용하여 스택 리팩터링

AWS CLI를 사용하여 스택을 생성하려면 다음 절차를 따릅니다.

  1. get-template 명령을 사용하여 리팩터링하려는 스택의 CloudFormation 템플릿을 검색합니다.

    aws cloudformation get-template --stack-name Stack1

    템플릿이 있으면 선택한 통합 개발 환경(IDE)을 사용하여 원하는 구조 및 리소스 구성을 사용하도록 템플릿을 업데이트합니다.

  2. create-stack-refactor 명령을 사용하고 리팩터링할 스택의 스택 이름과 업데이트된 템플릿을 제공합니다. 새 스택이 아직 없는 경우 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 명령을 --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" } } ]
  3. describe-stack-refactor 명령을 사용하여 StatusCREATE_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" }
  4. list-stack-refactor-actions 명령을 사용하여 실행할 특정 작업을 미리 봅니다.

    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" } } } ] }
  5. 변경 사항을 검토하고 확인한 후 execute-stack-refactor 명령을 사용하여 스택 리팩터링 작업을 완료합니다.

    aws cloudformation execute-stack-refactor \ --stack-refactor-id 9c384f70-4e07-4ed7-a65d-fee5eb430841
  6. describe-stack-refactor 명령을 사용하여 실행 상태를 모니터링합니다.

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

리소스 제한 사항

  • 스택 리팩터링은 provisioningTypeFULLY_MUTABLE인 리소스 유형만 지원하며, describe-type 명령을 사용하여 이를 확인할 수 있습니다.

  • CloudFormation은 리팩터링 생성 중에 리소스 자격을 검증하고 describe-stack-refactor 명령의 출력에서 지원되지 않는 모든 리소스를 보고합니다.

  • 다음 리소스는 스택 리팩터링에서 지원되지 않습니다.

    • 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::LaunchTemplate

    • AWS::EC2::NetworkInterfacePermission

    • 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::InferenceComponent

    • 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