CloudFormationネストスタックの作成について様々な疑問の答えを調べてみました。
「ネスト」とは
nest= いれ‐こ【入れ子/入れ▽籠】
同形で大きさの異なる器物を順に組み入れるように作ったもの。重箱や杯など。「―の箱」
身近な例だとマトリョーシカが入れ子です。
Excel関数でも
「=IF(OR(A2="",B2=""),"",IF(B2>=18,"成年","未成年"))」
↑のようなカッコの中にカッコが入る事をネスト(入れ子に)する。といいますね。
※ネストしすぎてSUBSTITUTE地獄になっている表もよくみます。
CloudFormationにおける「ネストスタック」とは
公式ドキュメントによれば、
ネストされたスタックは、他のスタックの一部として作成されたスタックです。
AWS::CloudFormation::Stack リソースを使用して別のスタック内に作成します。
Type: AWS::CloudFormation::Stackとして他のリソースと同じように表現出来る訳ですね。
ざっくり言うと、
Aスタックのテンプレートの中で「BっていうスタックとCっていうスタック作ってね!」
と書いてあって、
Bスタックのテンプレートには「VPCとSubnet作ってね!」
Cスタックのテンプレートには「EC2とSecurityGroup作ってね!」
のようにそれぞれに記述する事で、鎖で繋いだようにスタック同士を連結させて作る事が出来るというイメージです。
なので「スタックの数=テンプレートの数」になります。
複数のテンプレートをどのようにアップロードするのか次の章での説明になります。
スタック手順
こちらの記事には手順について以下のようにあります。
実際のスタックの作成作業は以下のようになります。
1.下位のテンプレートファイル3つをS3にアップロード
2.AWS CloudFormationのメニューから上位テンプレートファイルをアップロードする。
3.入力パラメータを入力し、スタックを作成する。
S3にルート以外のテンプレをUPするのですね。
ルートのテンプレのみ「ファイルを選択から」UPするという事のようです。(マネコンからであれば)
バケットへのアクセス許可は必要か。
オブジェクトURLを使って引っ張ってくる事が可能なので、
(それさえ有効であれば)特別な経路を作る必要も無いし、パブリックアクセスをすべてブロックにしていても問題ありません。
「バケットのリージョン・アカウントは同一である必要はあるか」という問いもオブジェクトURLを使っている訳ですから同じ回答になります。(実際にテスト済み)
S3の代替として外部リポジトリを利用可能か
これはテストしました。
Githubで試しましたが結果は、
「TemplateURL must be a supported URL.」となり失敗しました。
過去には(2018年3月観測時点)このエラー文は「TemplateURL must be an Amazon S3 URL」だったようです。参考
S3 オブジェクトURL以外にもサポートされるURLはあるのでしょうか。
作成完了後のコンソールの表示
親スタックはネスト無しのスタックと変わりませんが、
子スタックは「ネストされた」という文字で子スタックである事が見てとれるようになっています。
また親スタックの「リソース」や「イベント」タブに表示されるリソースは、
あくまでも「親スタック内に表現されているリソース」であり、
今回のように親スタックの中でEC2やSecurityGroupなどの普通のリソースを定義せず、子スタックだけを書いている場合、↑のような表示になります。
勿論、子スタック内では
このようになります。(出力、パラメータ、テンプレートも然りです。)
この章では最初の説明としてわかり易いよう「親」「子」という表現をしましたが、正式には一番上位のスタックは「ルートスタック」と表現されます。
「ネストの中でネスト」は実現可能か
言い換えればネストスタックという入れ子関係において、
「あるスタックの子として存在しているスタックが同時に別のスタックの親になり得るか」(=3世代以上のネストの実現可否)というのは疑問でした。
公式ドキュメントに以下のように図説されています。
なるほど。可能なのですね!
ただし先ほどのコンソールの「ネストされた」については3世代以上にした場合も、何世代目かが一目出来るアイコンやテキストは追加されませんでした。
後述しますが「ルートではない」事さえ一目でわかれば良い訳ですね。
ここでは試しに3世代のネストでテストしてみましたが、「スタックの情報」タブには、以下のようにルートと直親(一親等)のIDがそれぞれ表示されています。
スタックでパラメーターってどう使えばいいの?
子孫スタックへのパラメータの受け渡しは、ルートスタックが最初にスタック作成者にパラメーターで質問をして子スタックに渡す時はバトンのようにリレーする事が出来ました。
具体的には、
root_stack.yml
Parameters:
Template2ndGen:
Description: 2nd generation template Object URL
Type: String
Default: 2世代目のテンプレートのオブジェクトURLを入力してください。
Template3rdGen:
Description: 3rd generation template Object URL
Type: String
Default: 3世代目のテンプレートのオブジェクトURLを入力してください。
AnyString:
Description: Any string
Type: String
Default: 適当な文字列
Resources:
# 2世代目のスタックの作成
GEN2:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: !Ref Template2ndGen
Parameters:
Template3rdGen: !Ref Template3rdGen
AnyString: !Ref AnyString
gen2_stack.yml
Parameters:
Template3rdGen:
Type: String
Description: 3rdgeneration template Object URL
AnyString:
Type: String
Description: Any string
Resources:
# 3世代目のスタックの作成
GEN3:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: !Ref Template3rdGen
Parameters:
AnyString: !Ref AnyString
gen3_stack.yml
Parameters:
AnyString:
Type: String
Description: Any string
#[中略]...
Tags:
- Key: Name
Value: !Ref AnyString
...
のように橋渡し可能です。
※他に便利な方法があれば是非コメントなどで教えてください。
また、こちらの記事では、
リソース参照にはクロススタック参照(Export)を使わなくても良く、以下のコードのようにスタックのOutputを親テンプレートで参照することで実現します。
と説明されています。
スタックの一部リソースを更新したくなったらどうするか
特定のスタックオペレーション (例: スタックの更新) では、ネストされたスタック自体から直接実行するのではなく、ルートスタックから起動する必要があります。
「一番親から参照先のURLを変更するなり、同バケット内の同ファイルを上書きアップロードするなりしなさい」という事なのですね。
「ネストする事」はメリットなのか、アンチパターンなのか。
ネット上の記事をかなり探しましたが、この問題について誰かがはっきりと言及している文章を見つける事が出来ませんでした。
個人的には「分けたらなんか見やすそう」とは感じられていません。
1ファイル内の方がリソースの参照も簡単ですし、ファイル内をFで検索したり、同じ文字列をエディタ一括編集する際楽だったりメリットが多いはず(と思う)
2人以上でテンプレートを分担して作る事はあるでしょうか。
あったとしても結局1つのファイルにまとめればいい話のように思います。
今の所私にはわざわざS3バケットを作成して手動でファイルをアップして、ネストスタックにする事でドリフトや変更時の憂慮なども増えるように思いますし、デメリットが多いように思います。
(CFnに着手して8日目の所感ですので、まだ良さに気付けていないだけの可能性はあります。)
長くなりましたが、最後に番外編です。
そもそもS3に手動で下位ファイルをUPしたくない。
先にテンプレでUPしてから「DependsOn」出来ないかです。
こちらには
CloudFormationを介してファイルをアップロードすることはできません。CFNがローカルファイルシステムにアクセスできないため、サポートされていません。
と答えている方がいました。
一方で、こちらの記事にはcloudformation packageコマンド使用する事で可能そうである記載を見つけましたが、今回の主題からは外れる為、ここだけはまたの機会にしようと思います。
以上でした
ありがとうございました。
Discussion