tl;dr
最近, ちょこちょこ CloudFormation を生で使う機会があって, Terraform における plan
のような, 適用される変更内容を事前に確認する方法があると嬉しいなと思いながら, update stack を繰り返しておりました. ところが, 2 年くらい前に既に Change Sets という機能が追加されていたことを今更ながらに知ることになり, iret に始末書や辞表提出事案なんぢゃないかと震えが止まらない状況です.
docs.aws.amazon.com
はい.
awscli でざっくり Change Sets
CloudFormation における Change Sets とは
下図はドキュメント より引用させて頂いております.
- 変更内容を Change Set として登録
- 変更内容を確認
- 変更内容を適用
こんな感じです.
ちなみに, Changeset という言葉については, CloudFormation の専門用語ではなく, 以下のようにバージョン管理システムで利用されている概念のようなものです.
ということで, とあるスタック (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
キーの値の組み合わせにより, True
と False
及び Conditional
の何れか定義されるようです.
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 をうっかり登録してしまった…
- 最初の Change Set
- 二番目の Change Set
この場合, どのような挙動になったかというと…
- 二番目の Change Set に最初の Chnage Set がマージされていた
- 最初の Change Set を適用したら二番目の Change Set が無効 (削除) された (複数 Change Set が登録されている場合, 何れか 1 つの Change Set が execute された時点で残りの Change Set は削除されるような挙動)
フムフム.
全てのパターンにおいて, 上記のような状態になるか断言は出来ないが, 実際の運用時には注意したい点かもしれない.
以上
以下の文章は, こちらより一部引用させて頂きました.
今後はこうしたミスを再びおこすことがないよう、担当者間で二重チェックをする等、細心の注意をはらう所存でございます。
二度とこのようなことのないよう誓約するあかしとして本書を提出いたします。
誠にに申し訳ございませんでした。
というような文書を書くことが無いように, 使える機能はちゃんと使って, 安心安全な CloudFormation 運用を心がけたいものです.
元記事はこちら
「2 年前から利用出来る CloudFormation の Change Sets を今更知ったので始末書を提出いたします」