1. はじめに
CloudFormationのOutputsセクションでForEachを使ってサブネットIDをエクスポートするときに、最初うまくいかなかったので備忘録として
2. 何をしたいのか
CloudFormationテンプレートで作成したリソースを他のテンプレートで参照したい場合、参照元のテンプレートのOutputsセクションにリソースを記述すると思います。
その記述をリソースの数が多いと面倒なので、ForEach関数を使ってコードをきれいにしたいと思いました。
3. 失敗したテンプレート
AWSTemplateFormatVersion: 2010-09-09
Description: Create VPC, Subent
Transform: AWS::LanguageExtensions
# Parameters Section
Parameters:
System:
Type: String
Default: Sample
VpcCidr:
Type: String
Default: 10.0.0.0/24
# Mappings Section
Mappings:
# SubnetMappings
SubnetMappings:
SampleSubnet01:
Cidr: 10.0.0.0/27
Az: ap-northeast-1c
Number: 01
SampleSubnet02:
Cidr: 10.0.0.32/27
Az: ap-northeast-1a
Number: 02
SampleSubnet03:
Cidr: 10.0.0.64/27
Az: ap-northeast-1c
Number: 03
SampleSubnet04:
Cidr: 10.0.0.96/27
Az: ap-northeast-1a
Number: 04
SampleSubnet05:
Cidr: 10.0.0.128/27
Az: ap-northeast-1c
Number: 05
SampleSubnet06:
Cidr: 10.0.0.160/27
Az: ap-northeast-1a
Number: 06
# Resources Section
Resources:
# Sample Prd Vpc
SampleVpc:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VpcCidr
EnableDnsHostnames: true
EnableDnsSupport: true
Tags:
- Key: Name
Value: !Sub ${System}-vpc
# Subnet
# Private Subnets
'Fn::ForEach::SubnetLoop':
- SubnetName
- - SampleSubnet01
- SampleSubnet02
- SampleSubnet03
- SampleSubnet04
- SampleSubnet05
- SampleSubnet06
- '${SubnetName}':
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: !FindInMap [SubnetMappings, !Ref SubnetName, Az]
CidrBlock: !FindInMap [SubnetMappings, !Ref SubnetName, Cidr]
VpcId: !Ref SampleVpc
Tags:
- Key: Name
Value: !Sub
- ${System}-subnet-${SubnetNumber}
- SubnetNumber: !FindInMap [SubnetMappings, !Ref SubnetName, Number]
# Outputs Section
Outputs:
# VpcId
SampleVpcId:
Value: !Ref SampleVpc
Export:
Name: !Sub ${System}Vpc-Id
# SubnetId
'Fn::ForEach::ExportSubnetLoop':
- ExportSubnetName
- - SampleSubnet01
- SampleSubnet02
- SampleSubnet03
- SampleSubnet04
- SampleSubnet05
- SampleSubnet06
- '${ExportSubnetName}Id':
###↓↓↓ここが誤り↓↓↓###
Value: !Ref ExportSubnetName
###↑↑↑ここが誤り↑↑↑###
Export:
Name: !Sub ${ExportSubnetName}-Id
間違い部分はValue: !Ref ExportSubnetName
となります。
ForEach関数を使用した場合、Ref関数でExportSubnetNameの値を取得しても、IDを取得できず、スタックの出力結果は下の画像のようになってしまします。
これでは、VPCは参照できますが、サブネットは参照できません。
4. ではどうればよいか
# Outputs Section
Outputs:
# VpcId
SampleVpcId:
Value: !Ref SampleVpc
Export:
Name: !Sub ${System}Vpc-Id
# SubnetId
'Fn::ForEach::ExportSubnetLoop':
- ExportSubnetName
- - SampleSubnet01
- SampleSubnet02
- SampleSubnet03
- SampleSubnet04
- SampleSubnet05
- SampleSubnet06
- '${ExportSubnetName}Id':
Value: !GetAtt [!Ref ExportSubnetName, SubnetId]
Export:
Name: !Sub ${ExportSubnetName}-Id
Value
は!GetAtt
を使って記述します。
こうすればExportSubnetName
のサブネットIDを取得して、値として出力してくれるようになります。
5. 終わりに
ForEachを使った場合、Mappingsにパラメータをまとめるので、Resourcesは短くなりますが、Mappingsが以外と長くなります。
ForEachを使ってResourcesを短くしたほうがいいのか、通常どおり書いたほうがいいのかは、人によると思いました。
あと、Transform: AWS::LanguageExtensions
を忘れやすいので、気を付けましょう。