#内容#
CloudFormation で VPC の cidr を変更しようとハマった時のポイントについて記載する。
まず、そもそもの前提として VPC の プライマリの cidr を変更することはできない。(セカンダリとして拡張することは可能。)
参考:Amazon VPC の IPv4 アドレス範囲を変更するにはどうすればよいですか?
その前提で、 VPC、サブネットを CloudFormation から変更を試みるとどんな挙動になるのか。
基本的にこの記事は、CloudFormation でエラーが表示されたときにどんな対処をすべきか考えていくためのものです。
#構成#
検証目的なので、リソースは半端です。実際にスタックを作成してみていただくことをお進めします。
AWSTemplateFormatVersion: 2010-09-09
Description: cidr reduction
Resources:
#VPC1
Vpc1:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 192.168.0.0/20
EnableDnsSupport: true
EnableDnsHostnames: true
#Subnet1
Subnet1:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: !Select
- 0
- !GetAZs
Ref: AWS::Region
CidrBlock: 192.168.1.0/24
VpcId: !Ref Vpc1
RouteAssociation1:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref RouteTable
SubnetId: !Ref Subnet1
#Subnet2
Subnet2:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: !Select
- 1
- !GetAZs
Ref: AWS::Region
CidrBlock: 192.168.2.0/24
VpcId: !Ref Vpc1
PriAssociation2:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref RouteTable
SubnetId: !Ref Subnet2
#RouteTable
RouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref Vpc1
#ELB
elb1:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
Scheme: internal
SubnetMappings:
- PrivateIPv4Address: 192.168.1.10
SubnetId: !Ref Subnet1
- PrivateIPv4Address: 192.168.2.10
SubnetId: !Ref Subnet2
Type: network
Target1:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
HealthCheckEnabled: true
HealthCheckPath: /health_check
HealthCheckPort: 80
HealthCheckProtocol: HTTP
Name: elbtg
TargetType: ip
Port: 80
Protocol: TCP
VpcId: !Ref Vpc1
PriNlbListener:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
DefaultActions:
- Type: forward
TargetGroupArn: !Ref Target1
LoadBalancerArn: !Ref elb1
Port: 80
Protocol: TCP
#VPC2
Vpc2:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.0.0.0/16
EnableDnsSupport: true
EnableDnsHostnames: true
#VPCPeer
VpcPeer:
Type: AWS::EC2::VPCPeeringConnection
Properties:
VpcId: !Ref Vpc1
PeerVpcId: !Ref Vpc2
ToMainVpcRoute:
Type: AWS::EC2::Route
Properties:
DestinationCidrBlock: 10.0.0.0/16
RouteTableId: !Ref RouteTable
VpcPeeringConnectionId: !Ref VpcPeer
#SG
Sg1:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Sg
GroupName: Sg
SecurityGroupIngress:
- CidrIp: 192.168.0.0/20
FromPort: 80
IpProtocol: tcp
ToPort: 80
VpcId: !Ref Vpc1
##VPCep
EC2Vpce:
Type: AWS::EC2::VPCEndpoint
Properties:
PrivateDnsEnabled: true
ServiceName: !Sub com.amazonaws.${AWS::Region}.ec2
SecurityGroupIds:
- !Ref Sg1
SubnetIds:
- !Ref Subnet1
- !Ref Subnet2
VpcEndpointType: Interface
VpcId: !Ref Vpc1
#UPDATE_FAILED 1#
まずしないと思いますが、VPC1
Subnet1
Subnet2
ELB
の Cidr を別のネットワークに変更してみた。
次のような理由で、UPDATE_FAILED となった。
CloudFormation cannot update a stack when a custom-named resource requires replacing. Rename XXXXXXXXXXXX and update the stack again.
次のページに書かれている内容を確認してみる。
AWS CloudFormation の「Cannot update a stack when a custom-named resource requires replacing」エラーを解決する方法を教えてください。
まず、CloudFormation の基本的な動作として、
- CloudFormation によりリソースの置き換えが発生する場合は、まず置き換え用のリソースを作成し、その後で既存のリソースを削除する動作となっている。
- そのため、一時的に新旧 2 つのリソースが同時に並存する形となり、リソース名の重複が許されないリソースについては、既存のリソースが存在している状態で置き換え用のリソースを作成することができない。
今回、カスタム名を利用しているリソースは置き換えが必要であり、いずれかの変更が必要である。
- カスタム名は必須でないので、そもそも利用しない。
- リネームする。
今回は後者のリネームで対処してみる。
(例)
Name: elbtg
↓
Name: elbtg2
#UPDATE_FAILED 2#
UPDATE_FAILED 1 は解消されたようだが、次は別の問題が記録された。
Resource handler returned message: "The following target groups are in a different VPC than load balancer
ロードバランサーが属する VPC と、ロードバランサーに指定したターゲットグループの VPC が異なるためエラーが発生している。
これは、VPC、サブネットの cidr の変更に伴い、VPC、サブネットは置き換えが発生した。
- 置き換えが発生しないロードバランサーは、旧VPCに属する。
- 置き換えが発生するターゲットグループは新VPCに属する。
ということになる。
変更セットから、置Z換えが発生するかは確認可能であり、この辺りの考慮が甘かった。
- CloudFormation からスタックを更新する場合は、変更セットを利用する。
- ドキュメントで置き換えが発生するか
(Update requires: Replacement)
確認する。
ことが重要だ。
明示的に置き換えが発生するようにロードバランサーのプロパティに Name を入れてみた。
変更セットを確認してみると今度はロードバランサーも置き換えられるようだ。
これでうまくいった、というよりも VPCが新しく作成されると、まるっと入れ替えになるので、やる人も考える人もいないと思うので、トラブルシュートの考え方とし書いておいた。