インフラやクラウドの専門というわけではないのですがそろそろIaC周りもちゃんと勉強しておきたい・・・という感じなのでAWSのCloudFormationについて入門しつつ復習として記事にまとめておきます。
※とりあえず最初ということでごく基本的なところを中心に記事を書いていきます。
注意事項と前記事までの振り返り
本記事の処理を動かすとEC2関係などで色々と追加になったり起動したりします。その辺はリソースの停止や削除などをしないとお金がかかったりしてくる可能性があるためご注意ください。
また、本記事は6記事目となります。前回までの内容を踏襲していく形となっているのでご注意ください。
1記事目:
2記事目:
3記事目:
4記事目:
5記事目:
※以前先行して一部出力関係の部分は触れたので重複しているところも本記事にトピックをまとめるために触れていきます。
本記事で触れること
前記事までに少し出力(Outputs
)関係について触れましたが、その辺りを詳しく触れていくのとその値のエクスポートや別のYAMLテンプレートのファイルから参照したりなどをしていこうと思います。
出力値設定の基本
4記事目辺りにある程度触れた感じとなりますが復習的に触れておきます。
出力はOutputs
というセクションに定義することで何らかリソースの属性値などの値の出力を行えます。
内容を確認したりすることができるのに加えて出力値をエクスポートすることで他のテンプレートファイルから参照したりすることもできます。
書き方としては以下のようになります。
Outputs:
<出力値の論理名>:
Value: <設定する値>
例えばRef
関数でEC2インスタンスの論理名を指定するとインスタンスIDが返ってくるので、そちらの値を出力値として指定したい場合には以下のようになります。
Outputs:
MyEC2InstanceId:
Value: !Ref MyEC2Instance
YAMLテンプレートに組み込んで変更セットを作成して試してみます。
AWSTemplateFormatVersion: "2010-09-09"
Resources:
MyEC2Instance:
Type: AWS::EC2::Instance
Properties:
ImageId: ami-0590f3a1742b17914
InstanceType: t3.nano
Outputs:
MyEC2InstanceId:
Value: !Ref MyEC2Instance
反映した変更セットは更新のイベントなどが完了すると出力タブにてOutputs
セクションで指定した出力値の対象のキーと値が確認できます(直後ではイベント完了後に一度リロードしないと反映されないかもしれません)。
リソースの属性値を出力に設定する
以下の以前の組み込み関数の記事のFn::GetAtt
関数の節でも触れましたが、各リソースの属性値をFn::GetAtt
で取得できるため取得結果の値をOutputs
セクションにて設定することができます。
サポートされている属性名などに関しては以下の公式ページから対象のサービスのリンクを選択していってアクセスできるページにてFn::Ref
関数とFn::GetAtt
関数で取れる値と属性名、内容の説明などが確認できます。
たとえばEC2インスタンスのページであればFn::GetAtt
関数の内容は以下のようになっていることを確認できます。
例としてAvailability Zoneの値を出力に設定する場合YAMLテンプレートは以下のようになります(!GetAtt <リソースの論理名>.<ドキュメント上に記載がある属性名>
といった形になります)。
AWSTemplateFormatVersion: "2010-09-09"
Resources:
MyEC2Instance:
Type: AWS::EC2::Instance
Properties:
ImageId: ami-0590f3a1742b17914
InstanceType: t3.nano
Outputs:
MyEC2InstanceAz:
Value: !GetAtt MyEC2Instance.AvailabilityZone
変更セットを作成・反映して確認してみます。
更新のイベントが終わってから出力タブを確認するとFn::GetAtt
関数で取得した値(MyEC2Instance.AvailabilityZone
)が出力値として設定されていることを確認できます。
出力をエクスポートする
Outputs
などの設定値に対してExport
のキーを追加すると対象の値をエクスポートすることができます。エクスポートした値は他のYAMLテンプレートなどから参照ができるようになります。
Export
キーの中にはName
キーを指定して出力値の名前(他のテンプレートなどから参照する時に使用する名前)の設定が必要になります。
書き方としては以下のようになります。
Export:
Name: <設定する名前>
これを対象のOutputs
内の値に追加します。インスタンスのAvailabilityZoneの値をエクスポートする形だと以下のようになります(出力名はOutputs
部分の論理名と同じMyEC2InstanceAZ
としましたが、Outputs
のところで設定した論理名とずれていても使えます)。
AWSTemplateFormatVersion: "2010-09-09"
Resources:
MyEC2Instance:
Type: AWS::EC2::Instance
Properties:
ImageId: ami-0590f3a1742b17914
InstanceType: t3.nano
Outputs:
MyEC2InstanceAz:
Value: !GetAtt MyEC2Instance.AvailabilityZone
Export:
Name: MyEC2InstanceAZ
変更セットを反映して出力タブの部分を見てみるとap-northeast-1d
というAvailabilityZoneの値が出力されていることが確認できます。
また、Export
が設定されている場合にはエクスポートメニュー内でも値が確認できるようになります。CloudFormationの左のサイドメニューにあるエクスポートを選択します。
エクスポートの画面ではExport
で指定した名前や対象の値、関連するスタック情報などが表示されます。
エクスポートした値の他のスタックからの参照とFn::ImportValue
関数
エクスポートした値を別のYAMLテンプレートによるスタックで参照してみましょう。
別のYAMLファイルを作成し、シンプルなEC2インスタンスの記述を行います。事前にエクスポートした値はFn::ImportValue
関数を使うことで参照することができます。
Fn::ImportValue: <Exportで事前に指定した名前>
といった書き方になります。短縮系では!ImportValue <Exportで事前に指定した名前>
となります。
新しく追加するYAMLテンプレートのEC2インスタンスのAvailabilityZoneの属性部分でこのFn::ImportValue
関数を使うと以下のようになります。
AWSTemplateFormatVersion: "2010-09-09"
Resources:
MySecondEC2Instance:
Type: AWS::EC2::Instance
Properties:
ImageId: ami-0590f3a1742b17914
InstanceType: t3.nano
AvailabilityZone: !ImportValue MyEC2InstanceAZ
新しいスタックとして作成するため変更セットではなくスタックの作成から対応をしていきます。
スタックの名前はmy-second-ec2-instance
としました。
作成処理が終わるまで待ちます。
完了後にEC2インスタンスのページにアクセスしてみると2つ目のインスタンスが作成されていることが確認できます。また、アベイラビリティゾーンの部分を見てみると!ImportValue
関数で参照した値が設定されているので2つとも同じap-northeast-1d
の値が設定されていることが確認できます。
エクスポートした値を利用する際の注意点
ドキュメントを見たり他のエクスポートに関して以下のような注意点があるようです。
※自信がない点もあるためある程度は後の節で試してみようと思います。
- AWSアカウントごとにエクスポートする値の名前を一意にする必要があります。アカウントを複数プロジェクトとかで共有している場合とかは配慮が必要かもしれません。
- 異なるリージョン間ではエクスポートした値を
Fn::ImportValue
関数で利用することはできません。参照したい場合にはリージョンを合わせておく必要があります。 - 別のスタックがエクスポートした値を
Fn::ImportValue
関数などで参照している場合、エクスポートした値の削除が効かなかったりするケースがあります。恐らく削除したい場合には先に参照しているスタック側で参照を消すなどの対応が必要になります。 - ドキュメントには「別のスタックによって参照されている出力値を変更または削除することはできません。」と書かれており、参照されている出力値に関しても変更が効きません。
試しに他から参照されている、エクスポートの記述があるスタックを削除してみる
ドキュメントなどには参照されていると削除が効かないと書かれていたので試しに削除してみてエラーになることを確認します。
現在2つのスタックがあり、Outputs
やExport
を設定している1つ目のスタックの方を削除します。
対象のスタックを選択して削除ボタンを押します。
上部に変な感じの日本語になっていますがメッセージが表示されました。しかしスタックが消えていません。エラーメッセージとかも表示されない・・・?気配がしています(これは少々分かりづらい気配が・・・)。
どうやら対象のスタックのページに行ってイベントとかのタブを見るのが無難なようです。こちらを見るとDELETE_IN_PROGRESS
とかのイベントが発行されていることが確認できます。しかしUPDATE_COMPLETE
になりつつもExport MyEC2InstanceAZ cannot be deleted as it is in use by my-second-ec2-instance
というメッセージが出ておりエクスポートの値がmy-second-ec2-instance
のスタックで使われているから削除できないよ、といったメッセージが表示されています。どうやら情報としてはこちらを見ればOKそうです。
試しにエクスポートする値を更新してみる
エクスポートした値が外部から参照されていると、対象のエクスポートした値を別の値に変更できなくなるとドキュメントに書かれています。どんな感じなのか実際に試してみます。
まずは1つ目のスタックのYAMLテンプレートでAvailabilityZone: ap-northeast-1a
というAZの指定をべたで追加しています(この辺のハードコーディングは良くないとは思いますが検証なため一旦OKとします)。現在このスタックではap-northeast-1c
にAZがなっているので変更がかかる想定です。
AWSTemplateFormatVersion: "2010-09-09"
Resources:
MyEC2Instance:
Type: AWS::EC2::Instance
Properties:
ImageId: ami-0590f3a1742b17914
InstanceType: t3.nano
AvailabilityZone: ap-northeast-1a
Outputs:
MyEC2InstanceAz:
Value: !GetAtt MyEC2Instance.AvailabilityZone
Export:
Name: MyEC2InstanceAZ
変更セットを反映してみたらExport MyEC2InstanceAZ cannot be updated as it is in use by my-second-ec2-instance
というエラーメッセージと共に変更が失敗しました。
やはり他のスタックで参照していると値の更新も効かなくなるようです。割と不便と言えば不便・・・には感じますが、インフラでそこまで頻繁に更新がかからないので運用的に大丈夫というところでしょうか・・・?
更新したくなった場合にはどうすべきか?という点なのですがAWSのドキュメントによると、
- エクスポートされた出力値をインポートしているスタックを検索する
-
Fn::ImportValue
関数でインポートしている箇所を、実際の現在エクスポートされている値でべた書きで上書きしてスタックへ変更を反映する - エクスポートしている値を更新する
といった手順を踏めば良いようです。
必要に応じて値のべた書きにした箇所をFn::ImportValue
関数を利用する形に戻せば元通りとなります。
検証で使ったスタックやリソースの削除を行っておく
ここまでで複数のスタックを使ったエクスポートとインポートに対する検証が出来たので2つ目のスタックを削除しておきます(EC2インスタンスなども追加になっておりコストもかかるので)。
2つ目のスタックでは値のエクスポートなどはしていないので正常に削除が通りました。
EC2インスタンスのページを確認してみてもインスタンスが1つのみ残っていることを確認できます。
参考文献・参考サイト・参考講座まとめ