AWS CloudFormationのリソース依存をWaitConditionの代わりにCreationPolicyで実装する
ども、大瀧です。
全国数千人のCloudFormationマークアッパーの皆さんには既に常識かもしれませんが、CloudFormation内で処理待ちを実装するCreationPolicy
をWaitCondition
から移行する機会があったので、まとめてみたいと思います。
CloudFormationのリソース依存
CloudFormationはテンプレートに定義されるリソース同士の依存関係を自動で認識し、作成順序を調節する機能があります。この依存関係はテンプレートに明示でき、明示することでリソース作成のタイミングをユーザーが制御することもできます。例えばEC2同士でクラスタを組む場合に、スレーブノードがマスターノードに依存するので「先にマスターノードを作成してからスレーブノード作成に取りかかる」としたいことがあります。CloudFormationでは、DependsOn
属性をリソースに追加することで、以下のように依存関係を明示することができます。
SlaveリソースがMasterリソースに依存する定義
{ : "Resources": { "Master": { "Type": "AWS::EC2::Instance", : }, "Slave": { "Type": "AWS::EC2::Instance", "DependsOn": "Master", : } } }
これにより、リソースMaster
の作成の完了をもってSlave
の作成が開始します。ところが、一般的なクラスタウェアではマスターノードの起動後に初期処理があり、スレーブノードではその初期処理の完了を待たないとクラスタに参加できない、というのもよくある話です。リソース作成完了ではなく初期処理の完了を待つために、CloudFormationでは以下2通りの方法が用意されています。
- CreationPolicy属性
- WaitConditionリソース
元々は2. WaitConditionリソースのみだったのが後から1. CreationPolicy属性が追加され、ドキュメントによると、現在はCreationPolicy属性が推奨です。この2通りの方法について比較してみます。
WaitConditionリソースの場合
まずは旧来からあるWaitCondition(待機条件)での処理待ちを先ほどのテンプレートに追加してみます。WaitCondition
タイプとWaitConditionHandle
タイプの2つのリソースを追加し、Slave
リソースのDependsOn
属性をWaitCondition
に向けることで、Slave
リソースの作成を待機条件の完了まで待つようになります。
"Master": { "Type": "AWS::EC2::Instance", : }, "Slave": { "Type": "AWS::EC2::Instance", "DependsOn": "MasterWaitCondition", : }, "MasterWaitCondition": { "Type": "AWS::CloudFormation::WaitCondition", "DependsOn": "Master", "Properties": { "Handle": {"Ref": "MasterWaitHandle"}, "Timeout": "900" } }, "MasterWaitHandle": { "Type" : "AWS::CloudFormation::WaitConditionHandle" }
待機条件の完了はEC2インスタンスからCloudFormationのSignalResource APIに通知します。APIを簡単にコールするためのツールとしてcfn-signalユーティリティ *1が利用できます。
Linuxでのcfn-signalの実行例
"Master": { "Type": "AWS::EC2::Instance", "Properties": { : "UserData": {"Fn::Base64": {"Fn::Join": ["", [ "#!/bin/bash\n", "/opt/aws/bin/cfn-init -s ", {"Ref": "AWS::StackName"}, " -r Master ", " --region ", {"Ref": "AWS::Region"}, "\n", <ここに初期処理として任意のコマンドを書く> "/opt/aws/bin/cfn-signal -e 0 ", {"Ref": "MasterWaitHandle"}, "\n" ]]}} } }
CloudFormationはこの通知を受けると、待機条件を完了と判断します。通知が来ない場合は、待機条件のTimeout
属性の時間(秒数)だけ待った後リソースの作成失敗(CREATE_FAILED
)と判断しスタック作成失敗となります *2
CreationPolicy属性の場合
ではMaster
の初期処理待ちをCreationPolicy属性で記述してみます。Slave
リソースのDependsOn
属性はMaster
のままでMaster
リソースにCreationPolicy
属性を追加します。cfn-signalは構文が変わり、--resource
オプションに自身のリソース名を指定、cfn-initと同じくスタックID、リージョン名を添えます。
"Master": { "Type": "AWS::EC2::Instance", : "CreationPolicy": { "ResourceSignal": { "Timeout": "PT15M" } }, "Properties": { : "UserData": {"Fn::Base64": {"Fn::Join": ["", [ "#!/bin/bash\n", "/opt/aws/bin/cfn-init -s ", {"Ref": "AWS::StackName"}, " -r Master ", " --region ", {"Ref": "AWS::Region"}, "\n", <ここに初期処理として任意のコマンドを書く> "/opt/aws/bin/cfn-signal -e 0 --stack ", {"Ref": "AWS::StackName"}, " --resource Master ", " --region ", {"Ref": "AWS::Region"}, "\n" ]]}} } }, "Slave": { "Type": "AWS::EC2::Instance", "DependsOn": "Master", : }
WaitConditionリソースとの違いを以下に示します。
[良い点] DependsOnが他のリソースと同様に書ける
作成を待つリソースのDependsOn属性をWaitConditionリソースに向ける必要が無いため、直感的な記述が可能です。CreationPolicy属性を定義しない一般的なDependsOn属性の指定方法と合わせることができ、学習コストが多少下がります。
[良い点] TimeoutにISO8601形式が使える
WaitConditionリソースのタイムアウト値は秒数のみですが、CreationPolicy属性のTimeout
はISO8601のDurationの形式が利用できるため、直感的に時間指定できます。
[悪い点] 複数のチェックポイントは指定できない
処理待ちのタイミングを複数設定することは、CreationPolicy属性では対応できません。例えば、初期処理がDBのセットアップ、アプリケーションがあって、別のリソースでそれぞれ完了を待つという場合です。WaitConditionとWaitConditionHandlerを2つずつ定義し、DependsOnでそれぞれを向けることになります。
[悪い点] エラーメッセージをCloudFormationで取得できない
cfn-signalユーティリティには--data
オプションという、メッセージをCloudFormation APIに送信する機能があります。CreationPolicyでは指定できないため、-e
/--exit-code
オプションによる終了値のみ渡すことになります。
応用編 CreationPolicyとWaitConditionリソースの併用
ここまで2つを比較してきましたが、両方を組み合わせることも可能です。記述は複雑になりますが、前述の良い点、悪い点を上手く補完できるのであれば、検討するのも良いかも知れません。
"Slave": { "Type": "AWS::EC2::Instance", "DependsOn": "MasterWaitCondition", : }, "MasterWaitCondition": { "Type": "AWS::CloudFormation::WaitCondition", "Properties": { "Handle": {"Ref": "MasterWaitHandle"}, }, "CreationPolicy": { "ResourceSignal": { "Timeout": "PT15M" } } }, "MasterWaitHandle": { "Type" : "AWS::CloudFormation::WaitConditionHandle" }
まとめ
CloudFormationで処理待ちを明示するための方法2つ、CreationPolicy属性とWaitConditionリソースを比較してみました。
CreationPolicyを使うと、かなりすっきり記述することができるのでお奨めです。願わくば、cfn-init
/cfn-signal
のコマンドべた書きがもう少しなんとかできると良いのですけどね :P
Enjoy CloudFormation life!!
参考URL
- AWS::CloudFormation::WaitCondition - AWS CloudFormation
- CreationPolicy 属性 - AWS CloudFormation
- cfn-signal - AWS CloudFormation