tl;dr

最近, ちょこちょこ CloudFormation を生で使う機会があって, Terraform における plan のような, 適用される変更内容を事前に確認する方法があると嬉しいなと思いながら, update stack を繰り返しておりました. ところが, 2 年くらい前に既に Change Sets という機能が追加されていたことを今更ながらに知ることになり, iret に始末書や辞表提出事案なんぢゃないかと震えが止まらない状況です.

変更セットを実行して AWS CloudFormation スタックを更新する方法について説明します。それにより、スタックを更新する前に AWS CloudFormation が実行する変更をプレビューできます。

docs.aws.amazon.com

はい.

awscli でざっくり Change Sets

CloudFormation における Change Sets とは

下図はドキュメント より引用させて頂いております.

https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/images/update-stack-changesets-diagram.png

  1. 変更内容を Change Set として登録
  2. 変更内容を確認
  3. 変更内容を適用

こんな感じです.

ちなみに, Changeset という言葉については, CloudFormation の専門用語ではなく, 以下のようにバージョン管理システムで利用されている概念のようなものです.

Changeset – Wikipedia

ということで, とあるスタック (oreno-debug-stack) を Change Sets を使って, 出来るだけ安全にスタックを更新する流れを AWS CLI で実行した例を記載します.

$ aws --version
aws-cli/1.14.64 Python/2.7.13 Darwin/15.6.0 botocore/1.9.17

尚, awscli のバージョンは上記の通りとなっております.

create-change-set

スタックの変更内容は以下の通りとなります.

  • IAM Policy の変更
  • EC2 に付与されているセキュリティグループを変更 (セキュリティグループをデタッチ)

oreno-stack-update という名前で Change Set を作成しちゃいます.

aws --region=ap-northeast-1 \
  cloudformation create-change-set \
    --stack-name=debug-oreno-stack \
    --template-body=file://debug/template.json \
    --capabilities CAPABILITY_IAM \
    --change-set-name=oreno-stack-update

以下のようなレスポンスが返ってきます.

{
    "StackId": "arn:aws:cloudformation:ap-northeast-1:123456789012:stack/debug-oreno-stack/29cb59a0-31be-11e8-974c-500c44f24c1e",
    "Id": "arn:aws:cloudformation:ap-northeast-1:123456789012:changeSet/oreno-stack-update/c1a1391d-629d-4fd9-b380-94c967a1f4f3"
}

当然, この時点ではスタックの更新は行われていません.

list-change-sets

作成した Change Set 一覧を確認したいと思います.

aws --region=ap-northeast-1 \
  cloudformation list-change-sets \
  --stack-name=debug-oreno-stack

以下のようなレスポンスが返ってきます.

{
    "Summaries": [
        {
            "StackId": "arn:aws:cloudformation:ap-northeast-1:123456789012:stack/debug-oreno-stack/29cb59a0-31be-11e8-974c-500c44f24c1e",
            "Status": "CREATE_COMPLETE",
            "ChangeSetName": "oreno-stack-update",
            "CreationTime": "2018-03-27T14:09:58.046Z",
            "StackName": "debug-oreno-stack",
            "ExecutionStatus": "AVAILABLE",
            "ChangeSetId": "arn:aws:cloudformation:ap-northeast-1:123456789012:changeSet/oreno-stack-update/7d652b96-0647-4b57-a515-aa3d47a860d6"
        }
    ]
}

describe-change-set

作成した Change Set の詳細を確認したいと思います.

aws --region=ap-northeast-1 \
  cloudformation describe-change-set \
    --stack-name=debug-oreno-stack \
    --change-set-name=oreno-stack-update

以下のようなレスポンスが返ってきます.

{
    "StackId": "arn:aws:cloudformation:ap-northeast-1:123456789012:stack/debug-oreno-stack/29cb59a0-31be-11e8-974c-500c44f24c1e",
    "Status": "CREATE_COMPLETE",
    "ChangeSetName": "update4",
    "Parameters": [
        {
            "ParameterValue": "ami-ceafcba8",
            "ParameterKey": "AMIID"
        },
... 略 ...
        },
        {
            "ParameterValue": "debug",
            "ParameterKey": "Env"
        }
    ],
    "Changes": [
        {
            "ResourceChange": {
                "ResourceType": "AWS::ElasticLoadBalancingV2::TargetGroup",
                "PhysicalResourceId": "arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:targetgroup/oreno-debug-alb-target/8089ef37c60e58a3",
                "Details": [
                    {
                        "CausingEntity": "APP01",
                        "ChangeSource": "ResourceReference",
                        "Evaluation": "Dynamic",
                        "Target": {
                            "Attribute": "Properties",
                            "Name": "Targets",
                            "RequiresRecreation": "Never"
                        }
                    }
                ],
                "Action": "Modify",
                "Scope": [
                    "Properties"
                ],
                "LogicalResourceId": "ALBTarget",
                "Replacement": "False"
            },
            "Type": "Resource"
        },
        {
            "ResourceChange": {
                "ResourceType": "AWS::EC2::Instance",
                "PhysicalResourceId": "i-xxxxxxxxxxxxxxx",
                "Details": [
                    {
                        "ChangeSource": "DirectModification",
                        "Evaluation": "Static",
                        "Target": {
                            "Attribute": "Properties",
                            "Name": "SecurityGroupIds",
                            "RequiresRecreation": "Conditionally"
                        }
                    }
                ],
                "Action": "Modify",
                "Scope": [
                    "Properties"
                ],
                "LogicalResourceId": "APP01",
                "Replacement": "Conditional"
            },
            "Type": "Resource"
        }
    ],
    "CreationTime": "2018-03-27T14:09:58.046Z",
    "Capabilities": [
        "CAPABILITY_IAM"
    ],
    "StackName": "debug-oreno-stack",
    "NotificationARNs": [],
    "ExecutionStatus": "AVAILABLE",
    "ChangeSetId": "arn:aws:cloudformation:ap-northeast-1:123456789012:changeSet/update4/7d652b96-0647-4b57-a515-aa3d47a860d6",
    "RollbackConfiguration": {}
}

注目するのは, Action キーに定義されている値です. ここはスタック更新によって, リソースにどのような処理が行われるかが定義されるようです. 以下の三つのパターンがあり, まさに Remove が定義されている場合には注意が必要だと思います.

  • Add
  • Modify
  • Remove

また, Changes キーに定義されている値についても注目です. これらがスタックを更新することで, 変更されるリソースを確認することが出来ます. 注目は Replacement キーの値で, これは RequiresRecreation キーの値と Evaluation キーの値の組み合わせにより, TrueFalse 及び Conditional の何れか定義されるようです.

The ResourceChange structure describes the resource and the action that AWS CloudFormation will perform on it if you execute this change set.

docs.aws.amazon.com

execute-change-set

登録した Change Set を実行 (スタック更新) します.

aws --region=ap-northeast-1 \
  cloudformation execute-change-set \  
    --stack-name=debug-oreno-stack \
    --change-set-name=oreno-stack-update

レスポンスは残念ながらありません. update スタックと同じなので, 更新の状況はマネジメントコンソールから確認するか, waiter でポーリングする必要があるのかなと考えています.

delete-change-set

登録済みの Change Set を削除します.

aws --region=ap-northeast-1 \
  cloudformation delete-change-set \  
    --stack-name=debug-oreno-stack \
    --change-set-name=oreno-stack-update

レスポンスは残念ながらありません. これは delete-stack とは異なるはずなので, コマンドの実行後に list-change-sets あたりで削除されていることを確認したいと思います.

ちょっとした疑問

複数 Change Set を登録した場合の挙動

以下のように, 複数の Change Set をうっかり登録してしまった…

  1. 最初の Change Set
  2. 二番目の Change Set

この場合, どのような挙動になったかというと…

  • 二番目の Change Set に最初の Chnage Set がマージされていた
  • 最初の Change Set を適用したら二番目の Change Set が無効 (削除) された (複数 Change Set が登録されている場合, 何れか 1 つの Change Set が execute された時点で残りの Change Set は削除されるような挙動)

フムフム.

全てのパターンにおいて, 上記のような状態になるか断言は出来ないが, 実際の運用時には注意したい点かもしれない.

以上

以下の文章は, こちらより一部引用させて頂きました.

今後はこうしたミスを再びおこすことがないよう、担当者間で二重チェックをする等、細心の注意をはらう所存でございます。
二度とこのようなことのないよう誓約するあかしとして本書を提出いたします。
誠にに申し訳ございませんでした。

というような文書を書くことが無いように, 使える機能はちゃんと使って, 安心安全な CloudFormation 運用を心がけたいものです.

元記事はこちら

2 年前から利用出来る CloudFormation の Change Sets を今更知ったので始末書を提出いたします