インフラやクラウドの専門というわけではないのですがそろそろIaC周りもちゃんと勉強しておきたい・・・という感じなのでAWSのCloudFormationについて入門しつつ復習として記事にまとめておきます。
※とりあえず最初ということでごく基本的なところを中心に記事を書いていきます。
注意事項と前記事までの振り返り
本記事の処理を動かすとEC2関係などで色々と追加になったり起動したりします。その辺はリソースの停止や削除などをしないとお金がかかったりしてくる可能性があるためご注意ください。
また、本記事は5記事目となります。前回までの内容を踏襲していく形となっているのでご注意ください。
1記事目:
2記事目:
3記事目:
4記事目:
本記事で触れること
各種条件分岐設定(ConditionsやCondition設定など)や分岐設定用の各種関数(Fn::EqualsやFn::Ifなど)について触れていきます。
条件設定の機能の概要と出来ること
- CloudFormation条件設定ではパラメータなどを参照して条件を満たす場合 / 満たさない場合でテンプレートの挙動を分岐させることができる機能です。
- 特定の条件を満たした場合に一部のリソースを作成するようにしたり、リソースに設定する属性値を変動させたり、出力値を分岐させたりすることができます。
条件設定の基本的な書き方
条件設定の各種条件部分はConditionsセクションに書きます。以下のような書き方になります。
Conditions:
<条件の任意の論理名>:
<条件判定用のFn::Equalsなどの関数指定>
例えばElastic IPアドレスを作成するかどうかという条件を定義したい場合で、条件の論理名をCreateElasticIPConditionとして条件がパラメータに指定された環境が本番環境の場合としたい場合以下のようになります(パラメータ名がEnvironment、本番の場合のパラメータをPrdとします)。Fn::Equals(短縮系は!Equals)関数とかは後の節で詳しく触れます。
Conditions:
CreateElasticIPCondition:
!Equals [!Ref Environment, Prd]
この作成した条件を参照してリソースを作成するかどうかを指定したい場合には以下のようになります。
Resources:
<リソースの任意の論理名>:
Type: <リソースのタイプ>
Condition: <対象条件の論理名>
...
上記のケースではCondition部分にはConditionsセクション内で定義した論理名を指定します(前述の例で言うとCreateElasticIPConditionなど)。この場合Conditionで指定した条件を満たした場合にのみこのリソースが作成されます。
例えば条件を満たしたらMyPrdElasticIPという論理名のElastic IPアドレスのリソースを作成する(条件にはCreateElasticIPConditionを指定)・・・みたいな形にしたい場合以下のような記述になります。
...
Resources:
...
MyPrdElasticIP:
Type: AWS::EC2::EIP
Condition: CreateElasticIPCondition
Properties:
...
実際に変更セットを作成・反映してみて確認してみます。パラメータには開発環境(Dev)もしくは本番環境(Prd)かを選択するEnvironmentという論理名のものを用意し、もしそのパラメータが本番環境のPrdである場合にElastic IPアドレスのリソースを作成しEC2インスタンスのリソースに設定する・・・という形でYAMLを書きます。
AWSTemplateFormatVersion: "2010-09-09"
Parameters:
Environment:
Type: String
AllowedValues:
- Dev
- Prd
Conditions:
CreateElasticIPCondition:
!Equals [!Ref Environment, Prd]
Resources:
MyEC2Instance:
Type: AWS::EC2::Instance
Properties:
ImageId: ami-0590f3a1742b17914
InstanceType: t3.nano
MyElasticIP:
Type: AWS::EC2::EIP
Condition: CreateElasticIPCondition
Properties:
InstanceId: !Ref MyEC2Instance
YAMLをアップロードして変更セットを反映する前にEC2のElastic IP アドレスのページを確認しておきます。現時点では以下のように1つもElastic IP アドレスが存在しない形になっています。
変更セットをアップロードして反映していきます。
パラメータのEnvironmentの値はまずはDevを選択します。この場合ConditionsのCreateElasticIPConditionの条件を満たさなくなるのでElastic IP アドレス関係のリソースは作成されなくなります。
反映してイベントがUPDATE_COMPLETEになるまで待った後に確認してみてもElastic IP アドレス関係のイベントは発生していないことが確認できます。
EC2のElastic IP アドレスのページを見てみても特に追加などはされていないことが確認できます。
続いて同じYAMLテンプレートで、EnvironmentのパラメータだけPrdに変更してみます。
変更セットの確認画面でもElastic IP アドレス関係のアクションがAddになっていることを確認できます。
反映後のイベント画面でも各種Elastic IP アドレス関係のものが実行されていることが確認できます。
EC2のElastic IP アドレスのページを見てみると正常に追加がされていることが確認できます。
EC2インスタンスのページで対象のインスタンスを確認してみても追加となったElastic IP アドレスが反映されていることが確認できます。
このように同じYAMLテンプレートでありながらConditionsの設定による分岐でリソースを生成を分岐させることができました。
分岐条件によってリソースが作成されなくなった場合の挙動
既に作成済みのリソースが選択したパラメータなどによって作成されなくなった場合にどうなるのかを見てみます。
前節で使ったYAMLテンプレートとスタックをそのまま使用していきます。再度EnvironmentのパラメータにDevを選択します。前回はPrdでElastic IP アドレスが作成する条件になっていたものが反映されていますが今度はそのリソースが作成されなくなります。
変更セットを作成して確認してみると対象のElastic IP アドレスが削除(Remove)される形になりました。どうやら作成済みのリソースが分岐条件によって作成されなくなった場合にはそのまま残る形ではなく削除されるようです。
反映してみるとElastic IP アドレスなどが削除されていることが確認できます。
EC2のElastic IP アドレスのページを確認してみても一覧から消えていることが確認できます。
Fn::Equals関数
前節までで使ってきましたがFn::Equals関数はリスト内の2つの値が等しいかどうかの真偽値を取得する関数です。一致していればtrue、一致していなければfalseの真偽値を返します。主にConditionsセクションなどで使います。
値は2つのインデックスを持つリストで指定して、比較用の各値を2つのインデックス位置に設定します。
例えばFn::Equals [<1つ目の値>, <2つ目の値>]といったように書きます。短縮系では!Equals [<1つ目の値>, <2つ目の値>]といった感じになります。
前節までで!Equals関数を使って変更セットの作成などまで対応しているのでこの節ではその辺は省略しますが、例えばEnvironmentというパラメータがPrdかどうかという条件であれば以下のような記述となります。
Conditions:
CreateElasticIPCondition:
!Equals [!Ref Environment, Prd]
Fn::And関数
Fn::And関数はリスト内の各インデックスの条件(Condition)の真偽値が全てtrueであればtrueとなる関数です。3つ以上の条件を指定することもできます。基本的に真偽値を得るためにFn::Equals関数などをリスト内に入れる形となります。また、Conditionsセクションで定義されている条件単体(Condition)の値もドキュメントを見ている感じ!Conditionという記述で指定できるようです(Fn::Conditionという関数があるのだろうか?と軽く検索してみたのですがヒットしなかったのでこの場合は!Conditionの短縮系のみある感じでしょうか・・・?)。
例えば以下のような記述になります。
Fn::And:
- Fn::Equals: [<1つ目の値>, <2つ目の値>]
- !Condition <定義されている条件の論理名>
短縮系では!And [<各条件の値>]という形です。以下のような記述となります。
!And
- !Equals [<1つ目の値>, <2つ目の値>]
- !Condition <定義されている条件の論理名>
試しとして雑ですが以下のYAMLでUserNameというユーザー名選択用のパラメータと環境選択用のEnvironmentという2つのパラメータを用意しました。また、環境が本番(Prd)且つ対象ユーザーがB(UserB)の場合にElastic IP アドレスのリソースを設定する(リソースでその辺を作成する)という条件を指定しています。
お試しなので!And関数内では!Equalsと!Conditionの関数を両方使う形で設定してみます。
AWSTemplateFormatVersion: "2010-09-09"
Parameters:
Environment:
Type: String
AllowedValues:
- Dev
- Prd
UserName:
Type: String
AllowedValues:
- UserA
- UserB
Conditions:
IsPrdEnv:
!Equals [!Ref Environment, Prd]
IsUserBAndPrdEnv:
!And
- !Equals [!Ref UserName, UserB]
- !Condition IsPrdEnv
Resources:
MyEC2Instance:
Type: AWS::EC2::Instance
Properties:
ImageId: ami-0590f3a1742b17914
InstanceType: t3.nano
MyElasticIP:
Type: AWS::EC2::EIP
Condition: IsUserBAndPrdEnv
Properties:
InstanceId: !Ref MyEC2Instance
変更セットの作成や反映をしていきます。試しにまずは環境のパラメータはPrd、ユーザー名のパラメータはUserBを選択します。環境とユーザー名両方の条件で!And関数の条件を満たすためElastic IP アドレスのリソースが作成される想定です。
変更セットの変更内容を見てみるとElastic IP アドレス関係が追加される表示になっていることを確認できます。反映前に!Andの条件の結果がどうなるかとかが見れるのは良いですね。
反映後のイベントもElastic IP アドレス関係の更新が走っていることが確認できます。
今度は同じテンプレートで再度変更セットを作成して環境のパラメータはDevの方を選択します。!And関数の条件を満たさなくなるためElastic IP アドレスのリソースが作成されず削除される想定です。
変更セットの変更内容の確認画面では想定通りElastic IP アドレスのアクションがRemoveになっていることが確認できます(そのまま変更セットを反映しておきます)。
Fn::Or関数
Fn::And関数があるならOr関係の関数もあります・・・ということでFn::Or関数について触れていきます。
書き方的にはFn::And関数と同じような形でリストで複数の条件(Conditionとして定義したものやFn::Equals関数など)を以下のように指定します。
Fn::Or:
- Fn::Equals: [<1つ目の値>, <2つ目の値>]
- !Condition <定義されている条件の論理名>
短縮系では!Or [<各条件>]といった具合で以下のようになります。
!Or
- Fn::Equals: [<1つ目の値>, <2つ目の値>]
- !Condition <定義されている条件の論理名>
試しに以下のようにYAMLテンプレートを調整してみます。
- 環境のパラメータ(
Environment)にステージングとしてStgの選択肢を追加します。 -
ConditionsにIsPrdOrStgEnvという名前の条件で選択されパラメータがPrdもしくはStgかどうかという条件を追加しました。 - もし
IsPrdOrStgEnvの条件が満たされていればElastic IP アドレスのリソースが生成・設定されるようにしています。
AWSTemplateFormatVersion: "2010-09-09"
Parameters:
Environment:
Type: String
AllowedValues:
- Dev
- Stg
- Prd
Conditions:
IsPrdOrStgEnv:
!Or
- !Equals [!Ref Environment, Prd]
- !Equals [!Ref Environment, Stg]
Resources:
MyEC2Instance:
Type: AWS::EC2::Instance
Properties:
ImageId: ami-0590f3a1742b17914
InstanceType: t3.nano
MyElasticIP:
Type: AWS::EC2::EIP
Condition: IsPrdOrStgEnv
Properties:
InstanceId: !Ref MyEC2Instance
変更セットを作成し、まずはパラメータでPrdを選択してみます。Elastic IP アドレスのリソースが作成・設定される想定です。
変更セットの変更内容の確認画面では想定通りElastic IP アドレスが設定される形になっています(このまま反映します)。
続いてYAMLテンプレートはそのままで今度は環境のパラメータでDevを選択します。Elastic IP アドレスが削除される想定です。
変更確認画面でElastic IPアドレスのアクションが想定通りRemoveになっていることが確認できます(このまま反映します)。
最後に環境のパラメータでStgを選択します。!Or関数的にこの場合もElastic IP アドレスのリソースが作成・設定される想定です。
確認画面で想定通りElastic IP アドレスのアクションがAddになっていることが確認できました(このまま反映しておきます)。
Fn::Not関数
Fn::Not関数では指定された条件(Condition)の逆の真偽値を取得します。例えばtrueとなる条件であればfalse、falseであればtrueの真偽値を取得できます。
書き方としてはFn::Not: [<条件の指定>]といった具合になります。短縮系では!Not [<条件の指定>]となります。
条件部分にはFn::Equals関数やConditionsのセクションに定義した条件などを指定します。例えば!Not [!Equals [!Ref Environment, Prd]]といった記述となります。
以下の例では環境のパラメータ(Environment)で開発環境(Dev)以外を選択したかどうかという条件でIsNotDevEnvという名前でConditionsセクションに条件を追加しています。条件は!Not関数を使って!Not [!Equals [!Ref Environment, Dev]]としています。
また、もし該当の条件を満たす場合にはElastic IP アドレスの設定がEC2に設定されるようにしています。
AWSTemplateFormatVersion: "2010-09-09"
Parameters:
Environment:
Type: String
AllowedValues:
- Dev
- Stg
- Prd
Conditions:
IsNotDevEnv:
!Not [!Equals [!Ref Environment, Dev]]
Resources:
MyEC2Instance:
Type: AWS::EC2::Instance
Properties:
ImageId: ami-0590f3a1742b17914
InstanceType: t3.nano
MyElasticIP:
Type: AWS::EC2::EIP
Condition: IsNotDevEnv
Properties:
InstanceId: !Ref MyEC2Instance
変更セットの作成と反映を行っていきます。まずはパラメータでDevを選択し、条件がfalseとなってElastic IP アドレスが反映されない想定で進めます。
変更セットの変更内容を見ると、想定通りElastic IP アドレスがRemoveになっていることが確認できます(そのまま反映します)。
続いてもう一度同じYAMLテンプレートを追加して、環境のパラメータにPrdを選択します。Dev以外が選択されたので条件がtrueとなるのでElastic IP アドレスが追加される想定です。
変更確認画面で想定通り条件がtrueとなりElastic IP アドレスが追加になっていることが確認できました(そのまま反映します)。
Fn::If関数
Fn::If関数は条件を満たした場合と満たさない場合のそれぞれの値の分岐を設定できる関数です。特定の属性部分などで使用します。
書き方としてはFn::If: [<条件の論理名>, <真の時に設定する値>, <偽の時に設定する値>]といったように値はリストで指定し、最初のインデックスにはConditionsセクションで定義した条件の論理名、2番目のインデックスには条件を満たす場合に設定する値、3番目のインデックスには条件を満たさない場合に設定する値の3つを指定します。
短縮系では!If [<条件の論理名>, <真の時に設定する値>, <偽の時に設定する値>]という書き方になります。
以下の例では環境選択用のEnvironmentというパラメータを設けて、選択されたパラメータが開発環境(Dev)かどうかの条件(IsDevEnv)をConditionsセクションに設けています。
さらに、そのIsDevEnvの条件を満たした場合にはEC2インスタンスのインスタンスタイプをt3.nano、満たさない場合にはt3.microに値を分岐するようにしています。
AWSTemplateFormatVersion: "2010-09-09"
Parameters:
Environment:
Type: String
AllowedValues:
- Dev
- Prd
Conditions:
IsDevEnv:
!Equals [!Ref Environment, Dev]
Resources:
MyEC2Instance:
Type: AWS::EC2::Instance
Properties:
ImageId: ami-0590f3a1742b17914
InstanceType: !If [IsDevEnv, t3.nano, t3.micro]
変更セットを作って試してみます。まずはパラメータにはPrdを選択します(条件を満たさないのでインスタンスタイプがt3.microになる想定)。
反映後のイベントが完了してからEC2インスタンスのページに遷移してみるとインスタンスタイプが想定通りt3.microになっていることを確認できます。
続いて同じYAMLテンプレートでパラメータでDevを選択してみます。条件を満たすのでインスタンスタイプがt3.nanoになる想定です。
再度EC2インスタンスのページを開いて見ると想定通りインスタンスタイプがt3.nanoになっていることが確認できます。
参考文献・参考サイト・参考講座まとめ






























