LoginSignup
0
0

More than 1 year has passed since last update.

入門 AWS CloudFormation #4(組み込み関数編)

Last updated at Posted at 2023-02-07

インフラやクラウドの専門というわけではないのですがそろそろIaC周りもちゃんと勉強しておきたい・・・という感じなのでAWSのCloudFormationについて入門しつつ復習として記事にまとめておきます。

※とりあえず最初ということでごく基本的なところを中心に記事を書いていきます。

注意事項と前記事までの振り返り

本記事の処理を動かすとEC2関係などで色々と追加になったり起動したりします。その辺はリソースの停止や削除などをしないとお金がかかったりしてくる可能性があるためご注意ください。

また、本記事は4記事目となります。前回までの内容を踏襲していく形となっているのでご注意ください。

1記事目:

2記事目:

3記事目:

また、前回までの内容を踏まえYAMLのテンプレートは以下のような内容(EC2のごく基本的な設定)をベースに色々編集する形で進めていきます。

AWSTemplateFormatVersion: "2010-09-09"
Resources:
  MyFirstEC2Instance:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: ami-0590f3a1742b17914
      InstanceType: t2.nano

本記事で触れること

前記事までで少しだけ触れたCloudFormationの組み込み関数についてもっと内容を把握するために全体的に各関数などに触れていきます。以下の関数を対象とします。

  • Fn::GetAtt
  • Fn::FindInMap
  • Fn::Join
  • Fn::Split
  • Fn::Select
  • Fn::Sub
  • Fn::GetAZs

※組み込み関数の概要などに関しては前記事までで触れたので割愛します。

※あまり使う機会が無さそうな関数は割愛します。

※既に前の記事で触れたRef関数などは割愛します。

※後の記事で恐らく触れるかと思われる複数のスタックを使う場合やテンプレートのモジュール化をするケースなどに絡んだ関数はまだ触れません(Fn::ImportValueFn::Transformなど)。

※条件分岐の関数は別の記事で扱います。

また、関数による値の取得結果の確認などのためにOutputsの機能を軽くだけ触れて使っていったり、Mappingsの機能に関しても関数に合わせて少し触れていきます。

Outputs(出力)について

後の記事で詳しく触れるかもしれないため本記事では軽く触れるのみとなりますがOutputs関係についても説明しておきます(関数の値取得結果の確認などに使用します)。

OutputsというキーでYAML上で定義することで、CloudFormationのテンプレートの反映結果の値を一部出力することができます。

この出力値は確認として使えるだけでなく、他のテンプレートから参照したりすることもできます。

今回は値の確認のみで使用します。

最低限の書き方としては以下のように任意の論理名(今回はMyFirstEC2InstanceIdとしました)の指定とValueキーで出力したい値を指定します。

Outputs:
  MyFirstEC2InstanceId:
    Value: !Ref MyFirstEC2Instance

Ref関数でEC2インスタンスの論理名を指定すると値としてはインスタンスIDとなります。

YAML全体としては以下のようになっています。

AWSTemplateFormatVersion: "2010-09-09"
Resources:
  MyFirstEC2Instance:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: ami-0590f3a1742b17914
      InstanceType: t3.nano
Outputs:
  MyFirstEC2InstanceId:
    Value: !Ref MyFirstEC2Instance

試しに既存スタックに対して変更セットを作成・反映してみて挙動を確認してみます。

image.png

正常に処理が通りました。

Outputsの内容は出力タブに表示されるのでイベントタブから出力タブに切り替えます。更新処理完了後に出力タブでもリロードしないと結果が反映されないかもしれません。

キーにはYAML上で指定した論理名のMyFirstEC2InstanceId、値には対象のインスタンスのIDが設定されていることが確認できます。

image.png

一応EC2のインスタンスのページにアクセスしてインスタンス IDを確認してみます。

image.png

CloudFormationの出力結果のインスタンス IDと一致していることが確認できました。
本記事ではこの出力内容を確認用として使用していきます。

Fn::GetAtt関数

Fn::GetAtt関数は任意のリソースの特定の属性の値を取得します。短縮系では!GetAttとなります。

書き方としてはFn::GetAtt: [<対象リソースの論理名>, <属性名>]もしくは!GetAtt <対象リソースの論理名>.<属性名>となります。

属性名に関しては以下のドキュメントで対象のサービスを選択すると表示されるページのリンクを辿っていくと確認できます。

たとえばEC2インスタンスのAZを参照したい・・・という場合にはAmazon EC2 → AWS::EC2::Instanceと各リンクをクリックしていって表示されるページ内にあるReturn values節のFn::GetAtt部分の中からAZ関係を探して参照すればOKとなります。

image.png

もっと色々な属性が取れるかな?と思っていたら割と内容が限られている気配があります。欲しい属性が取れるようになっているかどうかは事前に確認しておいた方が良いかもしれません。

AZはAvailabilityZoneという属性名とドキュメントに書かれているため、YAML上ではValue: !GetAtt MyFirstEC2Instance.AvailabilityZoneという記述になります。

AWSTemplateFormatVersion: "2010-09-09"
Resources:
  MyFirstEC2Instance:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: ami-0590f3a1742b17914
      InstanceType: t3.nano
Outputs:
  MyFirstEC2Az:
    Value: !GetAtt MyFirstEC2Instance.AvailabilityZone

試しに変更セットを作成して反映してみます。

更新処理が終わるまでまってから出力タブをリロードして確認すると、ap-northeast-1dというAZの値が取れていることが確認できます。

image.png

Fn::Join関数

Fn::Join関数では指定された配列の文字列の値を別途指定された区切り文字で連結します。

値はリストで指定し、リストの最初のインデックスには区切り文字、2番目のインデックスには連結したい文字列をさらにリストで指定します。

例えば[AWS, EC2, Instance]という文字列のリストを::の区切り文字で連結したい場合にはFn::Join: ["::", [AWS, EC2, Instance]]といった書き方になります。

短縮系の場合には!Join ["::", [AWS, EC2, Instance]]といった書き方となります。

試しにYAMLのOutputs部分でこの関数を使って試してみます。

AWSTemplateFormatVersion: "2010-09-09"
Resources:
  MyFirstEC2Instance:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: ami-0590f3a1742b17914
      InstanceType: t3.nano
Outputs:
  MyResourceType:
    Value: !Join ["::", [AWS, EC2, Instance]]

更新などが終わったら出力タブでリロードして内容を確認します。

image.png

AWS::EC2::Instanceというリストの各文字列を::記号で連結した値が取得できていることが確認できました。

Fn::Select関数

Fn::Select関数ではリストの中から特定のインデックスの値を取得します。

値はリストで指定し、リストの最初のインデックスには取得したい値のインデックス、2番目のインデックスには対象のリストを指定します。インデックスは0からスタートします。

例えば[AWS, EC2, Instance]というリストの中から2番目の値(EC2)を取得したい場合にはFn::Select: [1, [AWS, EC2, Instance]]という書き方になります。

短縮系の場合には!Select [1, [AWS, EC2, Instance]]といった書き方になります。

試しに以下のYAMLで変更セットの作成や反映を行ってみます。

AWSTemplateFormatVersion: "2010-09-09"
Resources:
  MyFirstEC2Instance:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: ami-0590f3a1742b17914
      InstanceType: t3.nano
Outputs:
  MyString:
    Value: !Select [1, [AWS, EC2, Instance]]

更新が終わって出力タブでリロードするとEC2という値がリストの中から取れていることが確認できます。

image.png

Fn::Split関数

Fn::Split関数はFn::Joinの逆のような挙動をします。つまり特定の記号などで連結された文字列をリストに分割します。

値はリストで指定します。最初のインデックスには区切り文字、2番目のインデックスには分割したい文字列を指定します。

たとえばAWS::EC2::Instanceという文字列を::という区切り文字でリストに分割したい場合にはFn::Split: ["::", "AWS::EC2::Instance"]といったように指定します。

短縮系の場合には!Split ["::", "AWS::EC2::Instance"]という書き方になります。

Outputsでの指定にはリストは設定できないため、以下の例ではSplit関数で分割してからSelect関数で特定の値を取得して設定しています。

AWSTemplateFormatVersion: "2010-09-09"
Resources:
  MyFirstEC2Instance:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: ami-0590f3a1742b17914
      InstanceType: t3.nano
Outputs:
  MyString:
    Value: !Select [2, !Split ["::", "AWS::EC2::Instance"]]

スタックの変更セットを作成・反映し、更新が終わってから出力タブの画面でリロードすると文字列分割後のリストの中でインデックスが2のInstanceという値が取れていることを確認できます。

image.png

Fn::Sub関数

Fn::Sub関数では文字列内に対して別の値を挿入したりすることができます。Pythonのformatメソッドとかに近い形になります。

短縮系は!Subとなります。

引数には2つのインデックスを持つリストで指定します。最初のインデックスには置換対象の文字列、2つ目のインデックスには置換に指定するパラメーター名とパラメーターの辞書の値を指定します。

YAML上では以下のような感じになります。複数の置換パラメーターを指定したい場合には2つ目のインデックスに必要数分追加していきます。

!Sub
  - <置換対象の文字列>
  - <置換で使うパラメーター名1>: <置換で使うパラメーター1>
    <置換で使うパラメーター名2>: <置換で使うパラメーター2>
    ...

置換対象の文字列には${パラメーター名}といった記述で置換したい箇所を含めておきます。
Pythonで言うと文字列中の%sとか{formatで置換するパラメーター名}とかみたいな部分になります。

置換で使うパラメーターの値には他の関数などを利用することも出来ます。
例えば以下の例ではGetAtt関数を使ってAvailability Zoneの値を取得し、それを使ってSub関数で文字列の値の一部を置換しています。

AWSTemplateFormatVersion: "2010-09-09"
Resources:
  MyFirstEC2Instance:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: ami-0590f3a1742b17914
      InstanceType: t3.nano
Outputs:
  MyString:
    Value: !Sub
      - "My instance's AZ is ${AvailabilityZone}."
      - AvailabilityZone: !GetAtt MyFirstEC2Instance.AvailabilityZone

スタックの変更セットを作成・反映してみて挙動を確認してみます。

完了後にリロードなどをして出力内容を見てみるとMy instance's AZ is ${AvailabilityZone}.とYAML上で指定していた文字列がMy instance's AZ is ap-northeast-1d.と置換された文字列になっていることが確認できます。

Fn::GetAZs関数

Fn::GetAZs関数は指定されたリージョンで利用可能なAvailability Zoneのリストを返却します。

Fn::GetAZs: <対象のリージョン名>という書き方をします。短縮系では!GetAZs <対象のリージョン名>という記述になります。

以下の例では東京リージョン(ap-northeast-1)のリストをGetAZs関数で取得しています。Outputsへの指定ではリストは指定できないのでJoin関数でコンマ区切りで連結しています。

余談ですがap-northeast-1の指定をしているとなぜかcfn-lintに引っかかりました。us-east-1とかの他のリージョンでは普通にエラーなく通っています・・・。良く分からなかったのと実際に変更セットを作成した限りでは普通にエラー無く通ったので気にしないで進めます。

AWSTemplateFormatVersion: "2010-09-09"
Resources:
  MyFirstEC2Instance:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: ami-0590f3a1742b17914
      InstanceType: t3.nano
Outputs:
  MyString:
    Value: !Join [",", !GetAZs "ap-northeast-1"]

変更セットの作成や反映などをして出力結果を確認するとap-northeast-1a,ap-northeast-1c,ap-northeast-1dといったように東京リージョンの各AZ名が取れていることが確認できます。

Fn::FindInMap関数

最後にFn::FindInMap関数について触れていきます。ただしFn::FindInMap関数に触れる前にMappingsの機能について先に触れておきます(Fn::FindInMapと基本的にセットで使用するため)。

Mappingsの機能について

CloudFormationにはMappingsのセクションに多次元の辞書(マッピング)を使う形で各キーに応じた定数のようなものを定義することができます。

Mappingsセクション内にマッピング名、対象名、キー名といった具合に3つの階層が必要になります。キー名は同じパラメーターであれば同じキー名とかで大丈夫です。

これによって例えばパラメータで対象の環境を選択し、環境に応じた開発環境・ステージング・本番環境の各インスタンスタイプのマッピングを定義しておいて、選択された環境のインスタンスタイプの値をマッピングから取得する・・・みたいなことができるようになります。

YAMLだと以下のようなフォーマットになります。

Mappings:
  <マッピング名>:
    <対象名1>:
      <キー名1>: <値1>
    <対象名2>:
      <キー名2>: <値2>
    ...

例えば先ほどのインスタンスタイプの例に合わせてマッピング名をInstanceTypeMapping、対象名を開発環境・ステージング・本番としてDev, Stg, Prd、キー名をInstanceTypeとして値に各インスタンスタイプを持つマッピングだと以下のようになります。

Mappings:
  InstanceTypeMapping:
    Dev:
      InstanceType: t3.nano
    Stg:
      InstanceType: t3.nano
    Prd:
      InstanceType: t3.small

このマッピングの個別の値をFn::FindInMap関数を使って取得することができます。

Fn::FindInMap関数の使い方

Fn::FindInMap関数の値には3つのインデックスを持つリストを指定します。1つ目のインデックスにはマッピング名(前節の例で言うとInstanceTypeMapping部分が該当)、2つ目のインデックスには対象名(最初のキー名。前節の例で言うとDevStdなどの部分が該当)、3つ目のインデックスにはキー名(2つ目のキー目。前節で言うとInstanceType部分が該当)を指定します。返却値としてはマッピングの値(前節で言うとt3.nanoなどの部分が該当)が返却されます。

YAMLだとFn:FindInMap: [<マッピング名>, <対象名>, <キー名>]といった書き方になります。YAMLのリストの書き方的に以下のように改行とインデント・ハイフンを使う形でも受け付けてくれます。

Fn:FindInMap:
  - <マッピング名>
  - <対象名>
  - <キー名>

短縮系だと!FindInMap [<マッピング名>, <対象名>, <キー名>]といったように指定します。

また、この各インデックスの部分には他のRefなどの関数を挟むこともできます。つまりパラメータで環境を選択させて、選択された値をRef関数で参照してFn::FindInMap関数のリスト内で使う・・・みたいな書き方ができます。

例としてEnvironmentという名前のパラメータを定義していてそちらをFn::FindInMap関数で産所してマッピングの値を取得したい・・・といった場合には以下のような記述になります。

...
!FindInMap:
  - InstanceTypeMapping
  - !Ref Environment
  - InstanceType

実際にパラメータも定義したYAMLファイルを書いて変更セットを作成して試してみます。

AWSTemplateFormatVersion: "2010-09-09"
Mappings:
  InstanceTypeMapping:
    Dev:
      InstanceType: t3.nano
    Std:
      InstanceType: t3.nano
    Prd:
      InstanceType: t3.small
Parameters:
  Environment:
    Type: String
    AllowedValues:
      - Dev
      - Std
      - Prd
Resources:
  MyFirstEC2Instance:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: ami-0590f3a1742b17914
      InstanceType: !FindInMap
        - InstanceTypeMapping
        - !Ref Environment
        - InstanceType

YAMLをアップロードして設定を進めます。今回のYAMLテンプレートでは環境のパラメータを設定しているため選択が必要になります。

image.png

とりあえず試しとしてインスタンスタイプを変更してみたいためPrdを選択して進めます(現在はインスタンスタイプがnanoになっているのでPrdのsmallに変更してみます)。

image.png

イベントが完了するまで待ちます。

image.png

完了後にEC2のページにアクセスするとインスタンスタイプがPrdのマッピングに合わせたt3.smallになっていることが確認できます。

image.png

今度は同じテンプレートでパラメータでDevを選択してみます。

image.png

再度変更セットを反映してから完了するまで待った後にEC2インスタンスのページにアクセスするとインスタンスタイプがDevのマッピングに合わせたt3.nanoになっていることが確認できます。

image.png

このようにFn:FindInMap関数を使ってマッピングの定義から値を取得できることが確認できました。

参考文献・参考サイト・参考講座まとめ

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0