CloudFormation の Fn::GetAZs で ap-northeast-1d が返ってこなくてハマった
Posted on
CloudFormation で 3 AZ (Availability Zone) のサブネットを作るときに Fn::GetAZs
でハマったのでメモしておきます。
利用できる AZ はアカウントによって違いがあるので、AZ をハードコーディングしてしまうと汎用性がなくなってしまいます。そのために用意されている関数が Fn::GetAZs
で、指定されたリージョンの AZ を配列で返してくれます。
Fn::GetAZs で ap-northeast-1d が返ってこない
ap-northeast-1a, 1c, 1d が使えるアカウントで次のような CloudFormation テンプレートを書くと、なぜか "Template error: Fn::Select cannot select nonexistent value at index 2" というエラーになりました。配列に 2 つの AZ しか含まれていないようです。
Resources:
PublicSubnet1:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: 10.0.0.0/24
AvailabilityZone: !Select
- 0
- Fn::GetAZs: !Ref AWS::Region
PublicSubnet2:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: 10.0.1.0/24
AvailabilityZone: !Select
- 1
- Fn::GetAZs: !Ref AWS::Region
PublicSubnet3:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: 10.0.2.0/24
AvailabilityZone: !Select
- 2
- Fn::GetAZs: !Ref AWS::Region
aws ec2 describe-availability-zones
コマンドでは 3 AZ が取得できます。
$ aws ec2 describe-availability-zones --query 'AvailabilityZones[].ZoneName'
[
"ap-northeast-1a",
"ap-northeast-1c",
"ap-northeast-1d"
]
おかしいなと思って、先ほどのテンプレートに Outputs
を追加して配列の中身を確認してみました。
Outputs:
AZs:
Value: !Join [ ", ", !GetAZs ap-northeast-1 ]
すると、たしかに ap-northeast-1a, ap-northeast-1c しか返ってきません。
Fn::GetAZs は Default Subnet の AZ を返す
改めて Fn::GetAZs
のドキュメントを読んでみると次のような注意書きがありました。
For the EC2-VPC platform, the Fn::GetAZs function returns only Availability Zones that have a default subnet unless none of the Availability Zones has a default subnet; in that case, all Availability Zones are returned.
Fn::GetAZs
はアカウントで使える AZ のリストではなく、そのアカウントの Default Subnet の AZ が返ってくるというわけです。 ap-northeast-1d は最近できた AZ で、自分のアカウントの Default Subnet には存在しませんでした。罠すぎる…。
AWS CloudFormationの Fn::GetAZsはdefault subnetのあるAZが基本的に返ってくるので、足し忘れてると面倒だったりします。豆知識。 https://t.co/q3WxnS3GNL
— Ryosuke IWANAGA (@riywo) January 25, 2018
Default Subnet は次のコマンドで追加することができます。
$ aws ec2 create-default-subnet --availability-zone ap-northeast-1d
Default Subnet を ap-northeast-1d に作ったあと、先ほどの CloudFormation を流すと意図したとおり 3 AZ が取得できました。