目次
ご挨拶
お疲れさまです、寺井です。
先月のAWSアップデートをチェックしてたところ、目を引くアップデートを見つけました。
- Accelerate your CloudFormation authoring experience with looping function
AWS CloudFormationがFn::ForEach関数によるループ機能に対応しました。この機能により同じコード行を複製する簡単かつ迅速になり、見落としや更新漏れ等を防ぐのを可能にします。
週刊AWS – 2023/7/24週
効率化が好きな人にとっては待望のアップデートだと思いますので、具体的にどのように使えるのか試してみようと思います。
※本記事では「Fn::ForEach」組み込み関数に焦点を置いてお話します。
CloudFormationの具体的な使い方や、IAMなどに関する部分については触れておりません。
「Fn::ForEach」を活用したCloudFormationテンプレート
まずは今回作成したテンプレートを紹介します。
そのままコピペで使えるようになっておりますので、ぜひご活用ください!
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::LanguageExtensions # 「Fn::ForEach」を使えるようにする宣言(※必須)
Parameters:
DeveloperNames: # 配列を定義(ここで定義した値の数だけリソースが作成される)
Type: List<String>
Default: dev1, dev2, dev3, dev4, dev5
Ec2ImageId: # SSM Parameter StoreからAmazon Linux2のAMIを取得
Type: AWS::SSM::Parameter::Value<String>
Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2
Ec2InstanceType: # EC2インスタンスタイプを指定
Type: String
Default: t3.micro
Resources:
'Fn::ForEach::DeveloperLoop': # ループ処理
- DeveloperName
- !Ref DeveloperNames # Parametersセクションで定義した配列を使用
- '${DeveloperName}VPC': # VPCの作成
Type: 'AWS::EC2::VPC'
Properties:
CidrBlock: '10.0.0.0/16'
Tags:
- Key: Name
Value: !Sub '${DeveloperName}-vpc'
'${DeveloperName}InternetGateway': # インターネットゲートウェイの作成
Type: 'AWS::EC2::InternetGateway'
'${DeveloperName}VPCGatewayAttachment': # VPCとインターネットゲートウェイの関連付け
Type: 'AWS::EC2::VPCGatewayAttachment'
Properties:
VpcId: !Ref
'Fn::Sub': '${DeveloperName}VPC'
InternetGatewayId: !Ref
'Fn::Sub': '${DeveloperName}InternetGateway'
'${DeveloperName}RouteTable': # ルートテーブルの作成
Type: 'AWS::EC2::RouteTable'
Properties:
VpcId: !Ref
'Fn::Sub': '${DeveloperName}VPC'
'${DeveloperName}Route': # インターネットへのルートの作成
Type: 'AWS::EC2::Route'
Properties:
RouteTableId: !Ref
'Fn::Sub': '${DeveloperName}RouteTable'
DestinationCidrBlock: '0.0.0.0/0'
GatewayId: !Ref
'Fn::Sub': '${DeveloperName}InternetGateway'
'${DeveloperName}Subnet': # サブネットの作成
Type: 'AWS::EC2::Subnet'
Properties:
VpcId: !Ref
'Fn::Sub': '${DeveloperName}VPC'
CidrBlock: '10.0.0.0/24'
MapPublicIpOnLaunch: true
AvailabilityZone: !Select [ 0, !GetAZs '' ]
Tags:
- Key: Name
Value: !Sub '${DeveloperName}-subnet'
'${DeveloperName}SubnetRouteTableAssociation': # サブネットとルートテーブルの関連付け
Type: 'AWS::EC2::SubnetRouteTableAssociation'
Properties:
SubnetId: !Ref
'Fn::Sub': '${DeveloperName}Subnet'
RouteTableId: !Ref
'Fn::Sub': '${DeveloperName}RouteTable'
'${DeveloperName}EC2': # EC2インスタンスの作成
Type: 'AWS::EC2::Instance'
Properties:
InstanceType: !Ref Ec2InstanceType
SubnetId: !Ref
'Fn::Sub': '${DeveloperName}Subnet'
ImageId: !Ref Ec2ImageId
Tags:
- Key: Name
Value: !Sub '${DeveloperName}-ec2'
完成するリソース
- ネットワーク
- VPC
- インターネットゲートウェイ
- サブネット
- ルートテーブル
- コンピューティング
- EC2
というごくシンプルな構成ですが、
Parametersセクションで渡す{DeveloperNames}配列の要素の数分、まとめて作成されます。
今回だと{DeveloperNames}には、
dev1, dev2, dev3, dev4, dev5
という5つの値を設定しておりますので、1つのスタックで5つの環境がまとめて作成できるという寸法です。
これがあれば100個でも200個でも同じ環境の複製ができますね。
効率厨歓喜。
(あ、でもサービスクォータにはご注意ください。)
Fn::ForEach 組み込み関数について
概要
組み込みFn::ForEach関数はコレクションとフラグメントを受け取り、コレクション内の項目を指定されたフラグメント内の識別子に適用します。Fn::ForEachそれ自体を含む他の組み込み関数を含めることができ、 Conditions、Outputs、Resources (リソース プロパティを含む) セクションFn::ForEach内で使用できます。これは、 Format version、description、Metadata、Transform、Parameters、Mappings、Rules、またはセクションでは使用できません。
Fn::ForEach - AWS CloudFormation
使い方まとめ
LanguageExtensions の追加
Fn::ForEach関数はデフォルトでは使用できない関数となっておりますので、まずは使用できるようにテンプレート内での宣言が必要です。
(Pythonでいうライブラリをimportする的な作業)
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::LanguageExtensions #←これ
︙
AWS CloudFormation にデフォルトで含まれていない組み込み関数やその他の機能を使用できるようにします。
AWS::LanguageExtensions transform - AWS CloudFormation
構文
'Fn::ForEach::UniqueLoopName':
- Identifier
- - Value1 # Collection
- Value2
- 'OutputKey':
OutputValue
公式の構文と、先ほど紹介したテンプレートを照らし合わせながら、それぞれの項目ごとに見ていきます。
UniqueLoopName: ループの一意な名前
どんな名前でも大丈夫ですが、テンプレート内で一意である必要があります。
スタック内で同じループ名があると、後の方のループ処理で上書きされてしまいますので、重複しないように注意が必要です。
︙
Resources:
'Fn::ForEach::DeveloperLoop': # UniqueLoopName
- DeveloperName
︙
Identifier: ループ内で呼び出せる識別子
{任意の変数名}
の形式で使用できる
今回は「Parameters」セクションで定義した[DeveloperNames]という配列を「!Ref」で参照しています。
︙
'Fn::ForEach::DeveloperLoop':
- DeveloperName # Identifier
- !Ref DeveloperNames # Value(Collection)
︙
OutputKey: 各リソースの論理IDになる
先ほど宣言した識別子を使用して${DeveloperName}VPC
と指定することで、${配列の値}VPC
という形になり、一意の論理IDとして利用できます。
OutputValue: 繰り返される処理内容を記述
「OutputValue」の中では、「!Sub」と組み合わせたりして配列の値を使用することも可能です。
︙
- '${DeveloperName}VPC': # OutputKey
Type: 'AWS::EC2::VPC' # OutputValue ~
Properties:
CidrBlock: '10.0.0.0/16'
Tags:
- Key: Name
Value: !Sub '${DeveloperName}-vpc'
'${DeveloperName}InternetGateway': # OutputKey
Type: 'AWS::EC2::InternetGateway'
︙
まとめ
めちゃめちゃ良いなと思ったんですけど、「ImportValue」との組み合わせが上手く実現できなかったりで、慣れるまで時間がかかりそうです。
(これやるならCDKでも良いような…。ボソッ)
サクッと簡単なリソースを検証用に複数立てるときに便利なので、皆さんもぜひご利用ください。
ありがとうございました!
好きなこと:音楽、猫、お酒、ゲーム、効率化
経歴:音楽専門学校 → テレビ業界AD → 通信回線代理店 → IT関連職業訓練 → 2022.12~ 株式会社ディーネット