CloudFormationでテンプレートを書く際にパラメータは使っていますか?
テンプレートの柔軟性、汎用性を高め、テンプレートの真骨頂である横展開をスムーズに行うためには使わない手はないですね。
今回は、AWS固有のパラメータタイプの紹介と、ハマりやすい落とし穴・対応方法について紹介します。
AWS固有のパラメータタイプとは
AWS固有のパラメータタイプとは、スタック作成時のパラメータ入力画面において「特定のリストをドロップダウン形式で選択できるようにしてくれる仕組み」を実現するためのパラメータタイプです。パラメータタイプにはString
、Number
などがありますが、それの拡張版にあたる存在、と考えると分かりやすいです。
どんなのがあるの?
ホントは先に「どこで使うの?」というところを紹介したいところではあるのですが、どんなものがあるのかを先に紹介したほうがみなさんのイメージが広がると思いますので、自分がよく使っているタイプの上位5傑をチョイスして先にご紹介です。すべてのリストは公式ドキュメントを参照してください。
List
AWS::EC2::Subnet::Id
AWS::EC2::VPC::Id
AWS::EC2::AvailabilityZone::Name
List
「ああ、こういうものがマネジメントコンソールでのパラメータ指定画面で選べるようになるのか」というのがなんとなーくお分かりいただけるかと思います。
どんなふうに使えるの?
List
で囲まれているものとそうでないものがありますね。List
で囲まれていないものは単一選択、囲まれているものは複数選択としてマネジメントコンソールのページがレンダリングされます。百聞は一見に如かず。
単一選択型の画面イメージ (AWS::EC2::SecurityGroup::Id
)
複数選択型の画面イメージ(List
)
それぞれを選択した結果
落とし穴1:文字列型とリスト型を間違える
リソースプロパティで参照する際も、ドキュメント上でString
として指定されている場合は文字列型のパラメータを、[ String, ... ]
として指定されている場合は文字列型のパラメータを[]
で囲むか、リスト型のパラメータをそれぞれ指定する必要があります。慣れないうちはよく間違えるポイントです。
OKパターン
AWS::EC2::SecurityGroup
リソースのSourceSecurityGroupId
プロパティに単一文字列型のパラメータを展開しています。
{ "Parameters": { "SecurityGroupId": { "Type": "AWS::EC2::SecurityGroup::Id" } }, "Resources": { "SecurityGroup": { "Type": "AWS::EC2::SecurityGroup", "Properties": { "SecurityGroupIngress": { "IpProtocol": "-1", "SourceSecurityGroupId": { "Ref": "SecurityGroupId" } } } } } }
今度はAWS::EC2::Instance
リソースです。SecurityGroupIds
プロパティはリスト型のパラメータを取りますが、テンプレート側でリスト指定の[]
を補ったうえで、その中に単一文字列型のパラメータを展開しています。
{ "Parameters": { "SecurityGroupId": { "Type": "AWS::EC2::SecurityGroup::Id" } }, "Resources": { "Instance": { "Type": "AWS::EC2::Instance", "Properties": { "SecurityGroupIds": [ { "Ref": "SecurityGroupId" } ] } } } }
同じくSecurityGroupIds
プロパティですが、先ほどと違い、パラメータ側ですでにリスト化されていますので、テンプレート側でリスト指定の[]
を補う必要はなく、直接リスト型のパラメータを展開しています。
{ "Parameters": { "SecurityGroupIds": { "Type": "List<AWS::EC2::SecurityGroup::Id>" } }, "Resources": { "Instance": { "Type": "AWS::EC2::Instance", "Properties": { "SecurityGroupIds": { "Ref": "SecurityGroupIds" } } } } }
NGパターン
AWS::EC2::Instance
リソースのSecurityGroupIds
はリスト型のパラメータを取りますが、単一文字列型のパラメータを渡してしまっています。
{ "Parameters": { "SecurityGroupId": { "Type": "AWS::EC2::SecurityGroup::Id" } }, "Resources": { "Instance": { "Type": "AWS::EC2::Instance", "Properties": { "SecurityGroups": { "Ref": "SecurityGroupId" } } } } }
該当部分は下記のように展開されます。リスト型を求められているにもかかわらず文字列型を渡してしまったのでエラーになります。
"SecurityGroups": "sg-12345678"
同じくSecurityGroupIds
プロパティですが、パラメータ側ですでにリスト化されているにもかかわらず、リスト型を指定する[]
を補った中にリスト型のパラメータを渡してしまっています。
{ "Parameters": { "SecurityGroupIds": { "Type": "List<AWS::EC2::SecurityGroup::Id>" } }, "Resources": { "Instance": { "Type": "AWS::EC2::Instance", "Properties": { "SecurityGroups": [ { "Ref": "SecurityGroupIds" } ] } } } }
該当部分は下記のように展開されます。リスト型の中にリスト型が入っている、というおかしな状況になっています。
"SecurityGroups": [ [ "sg-12345678" ] ]
落とし穴2:ユーザが指定しない場合の挙動
便利に見えるパラメータタイプですが、出来上がったテンプレートを使ってスタックを作成する際にもちょっとした落とし穴があります。
「未指定時にはパラメータ変数そのものが定義されない」という点です。せっかくパラメータを選べるようにはしたものの、テンプレートの利用者(=スタックの作成者)がそれを指定してくれない、もしくは指定し忘れた、というケースが多いですね。
次のテンプレートを見てみてください。
{ "Parameters": { "SecurityGroupId": { "Type": "AWS::EC2::SecurityGroup::Id" } }, "Conditions": { "EmptySecurityGroup": { "Fn::Equals": [ { "Ref": "SecurityGroupId" }, "" ] } } }
一見行けそうに見えますよね?確かにパラメータが未指定であってもスタックの作成リクエストは行えるのですが、実際にはスタック作成後のイベントで下記のようなメッセージが表示され、スタックの作成もしくは更新がロールバックされます。
Parameter validation failed: parameter value for parameter name {パラメータ名} does not exist. Rollback requested by user.
「じゃあデフォルト値を指定すれば大丈夫なんじゃないの?」と考えたそこのあなた。
やってみましょう。
{ "Parameters": { "SecurityGroupId": { "Type": "AWS::EC2::SecurityGroup::Id", "Default": "" } }, "Conditions": { "EmptySecurityGroup": { "Fn::Equals": [ { "Ref": "SecurityGroupId" }, "" ] } } }
いい考えではあるんですが、だめなんです...。同じエラーが出ます。いずれにしても、(本当は利用者側の指定忘れなのに)「このテンプレートうまく動かないんですけどー」って文句を言われて悲しくなるパターンです。
送信前に未指定を阻止するためのアプローチとして適切なのは、AllowedPattern
属性を追加で指定して書式制約を設けてしまうことです。
{ "Parameters": { "SecurityGroupId": { "Type": "AWS::EC2::SecurityGroup::Id", "AllowedPattern": "^sg-[0-9a-z]+$", "ConstraintDescription": "Invalid Value" } }, "Conditions": { "EmptySecurityGroup": { "Fn::Equals": [ { "Ref": "SecurityGroupId" }, "" ] } } }
この制約を設けた場合であれば、スタックの作成指示が通る前にメッセージを出してくれます。(テンプレート例ではCostraintDescription
属性を追加指定していますので、エラー出力にもそこで指定したメッセージが表示されています。)
Parameter SecurityGroupId failed to satisfy constraint: Invalid Value
まとめ
今回はCloudFormationテンプレートのパラメータで指定可能な「AWS固有のパラメータタイプ」について紹介しました。他にもたくさんの便利機能が存在しますので、うまく活用して素敵なテンプレートづくりにいそしんでくださいませ。ではまた!
投稿者プロフィール
- 根っこはインフラ屋な古いおじさん。
最新の投稿
- AWS2024年11月1日【小ネタ】cfnresponseが見つからない?
- CloudFormation2024年10月23日スポットインスタンスな起動テンプレートのインスタンスサイズを可変にしたい
- AWS2023年11月14日DLQを積み重ねる
- SQS2023年10月2日1分より短いサイクルで定期的にLambdaを実行する