はじめに
はじめまして。かわむと申します。
私は今年度SIerに入社し、現場配属されてから2か月ほどになります。最初に担当した業務がAWSのCloudFormationを使用してごく一般的なネットワーク(VPC、サブネットなど)を作成するという簡単な業務だったのですが、無知であるが故につまずいた部分がありましたので、アウトプットを兼ねて共有したいと思います。
構成図
かなり簡略化しておりますが、以下のコンポーネントを作成しました
・VPC(Virtual Private Cloud)
・サブネット
・ルートテーブル
・VPCエンドポイント(ゲートウェイ型)
最初に作成したyamlテンプレート(ミスあり)
まず初めに、以下のようなyamlテンプレートを作成しました。こちらのコードには誤りが二か所存在します。(そもそもIGWを設置していないことは別として、デプロイ時にエラーが発生します。)
AWSTemplateFormatVersion: "2010-09-09"
Description: "CloudFormation template for a VPC with Multi-AZ subnets and VPC Endpoint."
#VPC作成
Resources:
VPC:
Type: "AWS::EC2::VPC"
Properties:
CidrBlock: "10.0.0.0/16"
#サブネット作成
SubnetAZ1:
Type: "AWS::EC2::Subnet"
Properties:
VpcId: !Ref VPC
CidrBlock: "10.0.1.0/24"
AvailabilityZone: "ap-northeast-1a"
SubnetAZ2:
Type: "AWS::EC2::Subnet"
Properties:
VpcId: !Ref VPC
CidrBlock: "10.0.2.0/24"
AvailabilityZone: "ap-northeast-1b"
#ルートテーブル作成
RouteTableAZ1:
Type: "AWS::EC2::RouteTable"
Properties:
VpcId: !Ref VPC
RouteTableAZ2:
Type: "AWS::EC2::RouteTable"
Properties:
VpcId: !Ref VPC
#ルート追加
RouteAZ1Internet:
Type: "AWS::EC2::Route"
Properties:
RouteTableId: !Ref RouteTableAZ1
DestinationCidrBlock: "0.0.0.0/0"
GatewayId: "local"
RouteAZ2Internet:
Type: "AWS::EC2::Route"
Properties:
RouteTableId: !Ref RouteTableAZ2
DestinationCidrBlock: "0.0.0.0/0"
GatewayId: "local"
RouteAZ1Local:
Type: "AWS::EC2::Route"
Properties:
RouteTableId: !Ref RouteTableAZ1
DestinationCidrBlock: "10.0.0.0/16"
GatewayId: "local"
RouteAZ2Local:
Type: "AWS::EC2::Route"
Properties:
RouteTableId: !Ref RouteTableAZ2
DestinationCidrBlock: "10.0.0.0/16"
GatewayId: "local"
RouteAZ1Endpoint:
Type: "AWS::EC2::Route"
Properties:
RouteTableId: !Ref RouteTableAZ1
DestinationCidrBlock: "com.amazonaws.ap-northeast-1.s3"
GatewayId: !Ref VPCGatewayEndpoint
RouteAZ2Endpoint:
Type: "AWS::EC2::Route"
Properties:
RouteTableId: !Ref RouteTableAZ2
DestinationCidrBlock: "com.amazonaws.ap-northeast-1.s3"
GatewayId: !Ref VPCGatewayEndpoint
#VPCエンドポイント作成
VPCGatewayEndpoint:
Type: "AWS::EC2::VPCEndpoint"
Properties:
VpcId: !Ref VPC
ServiceName: "com.amazonaws.ap-northeast-1.s3"
RouteTableIds:
- !Ref RouteTableAZ1
- !Ref RouteTableAZ2
#ルートテーブルをサブネットに紐づける
SubnetRouteTableAssociationAZ1:
Type: "AWS::EC2::SubnetRouteTableAssociation"
Properties:
SubnetId: !Ref SubnetAZ1
RouteTableId: !Ref RouteTableAZ1
SubnetRouteTableAssociationAZ2:
Type: "AWS::EC2::SubnetRouteTableAssociation"
Properties:
SubnetId: !Ref SubnetAZ2
RouteTableId: !Ref RouteTableAZ2
エラーの箇所はわかりましたでしょうか。答えはどちらもRouteの定義中にあります。
1点目は以下の部分です。
RouteAZ1Local:
Type: "AWS::EC2::Route"
Properties:
RouteTableId: !Ref RouteTableAZ1
DestinationCidrBlock: "10.0.0.0/16"
GatewayId: "local"
RouteAZ2Local:
Type: "AWS::EC2::Route"
Properties:
RouteTableId: !Ref RouteTableAZ2
DestinationCidrBlock: "10.0.0.0/16"
GatewayId: "local"
上記のコードでは、VPC CIDR宛(local)へのルートを追加しています。しかし、AWSのルートテーブルは作成時にデフォルトでlocalルートが定義されるため、重複が発生します。
そして二点目は以下の部分です。
#ルート追加
RouteAZ1Internet:
Type: "AWS::EC2::Route"
Properties:
RouteTableId: !Ref RouteTableAZ1
DestinationCidrBlock: "0.0.0.0/0"
GatewayId: "local"
RouteAZ2Internet:
Type: "AWS::EC2::Route"
Properties:
RouteTableId: !Ref RouteTableAZ2
DestinationCidrBlock: "0.0.0.0/0"
GatewayId: "local"
#VPCエンドポイント作成
VPCGatewayEndpoint:
Type: "AWS::EC2::VPCEndpoint"
Properties:
VpcId: !Ref VPC
ServiceName: "com.amazonaws.ap-northeast-1.s3"
RouteTableIds:
- !Ref RouteTableAZ1
- !Ref RouteTableAZ2
上記のコードではVPCエンドポイントへのルートを追加していますが、そのすぐ下でVPCエンドポイントとルートテーブルとの紐づけを定義してしまっています。この場合もルートに重複が生じてエラーになってしまいます。
修正後のyamlテンプレート
先ほどのミスを修正したテンプレートが以下になります。
AWSTemplateFormatVersion: "2010-09-09"
Description: "CloudFormation template for a VPC with Multi-AZ subnets and VPC Endpoint."
#VPC作成
Resources:
VPC:
Type: "AWS::EC2::VPC"
Properties:
CidrBlock: "10.0.0.0/16"
#サブネット作成
SubnetAZ1:
Type: "AWS::EC2::Subnet"
Properties:
VpcId: !Ref VPC
CidrBlock: "10.0.1.0/24"
AvailabilityZone: "ap-northeast-1a"
SubnetAZ2:
Type: "AWS::EC2::Subnet"
Properties:
VpcId: !Ref VPC
CidrBlock: "10.0.2.0/24"
AvailabilityZone: "ap-northeast-1b"
#ルートテーブル作成
RouteTableAZ1:
Type: "AWS::EC2::RouteTable"
Properties:
VpcId: !Ref VPC
RouteTableAZ2:
Type: "AWS::EC2::RouteTable"
Properties:
VpcId: !Ref VPC
#ルート追加
RouteAZ1Internet:
Type: "AWS::EC2::Route"
Properties:
RouteTableId: !Ref RouteTableAZ1
DestinationCidrBlock: "0.0.0.0/0"
GatewayId: "local"
RouteAZ2Internet:
Type: "AWS::EC2::Route"
Properties:
RouteTableId: !Ref RouteTableAZ2
DestinationCidrBlock: "0.0.0.0/0"
GatewayId: "local"
#VPCエンドポイント作成
VPCGatewayEndpoint:
Type: "AWS::EC2::VPCEndpoint"
Properties:
VpcId: !Ref VPC
ServiceName: "com.amazonaws.ap-northeast-1.s3"
RouteTableIds:
- !Ref RouteTableAZ1
- !Ref RouteTableAZ2
#ルートテーブルをサブネットに紐づける
SubnetRouteTableAssociationAZ1:
Type: "AWS::EC2::SubnetRouteTableAssociation"
Properties:
SubnetId: !Ref SubnetAZ1
RouteTableId: !Ref RouteTableAZ1
SubnetRouteTableAssociationAZ2:
Type: "AWS::EC2::SubnetRouteTableAssociation"
Properties:
SubnetId: !Ref SubnetAZ2
RouteTableId: !Ref RouteTableAZ2
こちらで無事正常にデプロイすることができました。
おわりに
今回のミスの原因は、ルートテーブル作成時にデフォルトでlocal宛てのルートが定義されることや、VPCエンドポイントとルートテーブルの適切な紐づけ方を知らなかったことという初歩的なものでした。ただ、CloudFormationではミスをしていても、デプロイ時に基本的にロールバックされるためある程度トライ&エラーの形で実施していくことができるのかと思います。(コードはあっているけど構成が違うといったミスは非常に怖いですが)
また、初めての業務がマネジメントコンソールを利用したデプロイ作業でなく、CloudFormationを利用する作業となりやや困惑していましたが、スタックをすぐに修正可能であったり、テンプレートを流用して同じリソースを作成可能なことなど、非常に有用な技術だなと感じました。今回テンプレートの中で使用していない、ParametersやConditons等を徐々に覚えていきながら業務に取り組んでいきたいと思う次第です。