3AZ構成CloudFormationのデプロイに失敗したので対処してみた (!GetAZsが全AZを返さない)
CloudFormation で 3AZ 構成の VPC を東京リージョン(ap-northeast-1)にデプロイしようとしたところ、以下のエラーが発生しました。
Template error: Fn::Select cannot select nonexistent value at index 2.
テンプレートでは !GetAZs で取得したAZリストの3番目(index 2)を参照していました。
Resources:
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.0.0.0/16
Subnet3:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: 10.0.2.0/24
AvailabilityZone: !Select [2, !GetAZs ''] # ← ここでエラー
東京リージョンであれば !GetAZs は通常3つのAZを返すはずが、実際には2つしか返していないようでした。この事象の原因調査を行う機会がありましたので紹介します。
EC2 API との比較
念のため、EC2 API (AWS CLI) で東京リージョンの利用可能なAZを確認しました。
$ aws ec2 describe-availability-zones --region ap-northeast-1 \
--query 'AvailabilityZones[*].ZoneName' --output table
-------------------------------
|DescribeAvailabilityZones |
+---------------------------+
| ap-northeast-1a |
| ap-northeast-1c |
| ap-northeast-1d |
+---------------------------+
API 経由では問題なく3つのAZ(1a, 1c, 1d)が返ってきています。
「EC2 API では3つ見えるのに、CloudFormation の !GetAZs では2つしか取得できない」という乖離が発生していました。
根本原因
調査の結果、デフォルトサブネットの状態が影響していることが分かりました。以下のコマンドで確認します。
$ aws ec2 describe-subnets \
--filters "Name=default-for-az,Values=true" \
--region ap-northeast-1 \
--query 'Subnets[*].[AvailabilityZone,SubnetId]' \
--output table
-----------------------------------------
| DescribeSubnets |
+------------------+-------------------+
| ap-northeast-1a | subnet-xxxxxxxx |
| ap-northeast-1c | subnet-yyyyyyyy |
+------------------+-------------------+
# ap-northeast-1d が欠落している
出力結果の通り、ap-northeast-1d のデフォルトサブネットが存在していませんでした。
このアカウントは2018年の ap-northeast-1d リリース前から利用しており、当時 1d 未サポートのAMIを利用する関係で、サブネットを除外していた可能性がありました。
参考: 東京リージョンに4つ目のアベイラビリティゾーン(ap-northeast-1d)ができました! | DevelopersIO
AWS CloudFormation 公式ドキュメントには、Fn::GetAZs の挙動について以下の記述があります。
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.
要約すると、!GetAZs の挙動は以下のようになります。
- デフォルトサブネットが1つでも存在する場合
→ デフォルトサブネットが存在する AZ のみを返す(今回のケース) - デフォルトサブネットが1つも存在しない場合
→ そのリージョンのすべての AZ を返す
今回は「一部のAZ(1a, 1c)にだけデフォルトサブネットがある」状態だったため、1d がリストから漏れる状況が発生しました。
解決策
今回の問題が発生したAWSアカウントは検証環境でした。
ハンズオンや、EC2 Image Builder などで デフォルトVPCを利用する可能性があるため、デフォルトサブネットの追加で対処しました。
解決策1: デフォルトサブネットを作成する
欠落している AZ(今回は ap-northeast-1d)にデフォルトサブネットを作成します。
aws ec2 create-default-subnet --availability-zone ap-northeast-1d
これにより「全てのAZにデフォルトサブネットがある状態」となり、!GetAZs が3つのAZを返すようになります。既存のデフォルトVPCを維持したい場合はこちらが有効です。
解決策2: デフォルトVPCを削除する
デフォルトVPC自体を完全に削除します。
aws ec2 delete-vpc --vpc-id vpc-xxxxx
前述の仕様通り、「デフォルトサブネットが1つも存在しない場合」は全AZが返されるため、これでも !GetAZs は3つのAZを返すようになります。
まとめ
CloudFormation の !GetAZs は、単純に「リージョンの全AZ」を返すわけではなく、デフォルトVPCおよびデフォルトサブネットの存在により、挙動が変わります。EC2 API やVPCダッシュボードに表示されるAZが得られない場合、デフォルトサブネットの欠落を疑ってみてください。
また、開発・検証環境などを除き、特に本番運用環境においてはリスク要因となるデフォルトVPCについて、その削除も検討することをお勧めします。







