はじめに
CloudFormation で全世界待望?のリソースインポート機能がリリースされました。
AWS CloudFormation Launches Resource Import
https://aws.amazon.com/jp/about-aws/whats-new/2019/11/aws-cloudformation-launches-resource-import/
CloudFormationで管理されていないリソースをスタックに取り込むことができるようになったわけですが、
このリソースインポート機能を活用することで既存のスタック間でリソースを移動したり
複雑化したスタックのリファクタリングを行ったりすることもできます。
スタック分割を例に考える
既存のスタックを分割しようとする場合、概ね以下のような流れとなります。
- ソーステンプレート内の分割対象のリソースに対し
DeletionPolicy: Retain
を指定し、適用する - 分割対象のリソースをソーステンプレートから削除し、ターゲットテンプレートに追加する
- 既存スタックを更新して分割対象のリソースを削除(管理対象外)にする
- ターゲットテンプレートを使用して、管理対象外となった分割対象リソースをインポートする
ソーステンプレート: 既存スタックのテンプレート
ターゲットテンプレート: 分割する新しいスタックのテンプレート
やってみる
1つのテンプレートでVPCとEC2を一緒に管理していて、それぞれを別スタックに分割する例を考えてみます。
検証目的であるため、ここでは以下のようなシンプルなテンプレートで試してみます。
AWSTemplateFormatVersion: '2010-09-09'
Description:
split stack test
Parameters:
pLatestAmiId:
Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
Default: '/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2'
pInstanceType:
Type: String
Default: 't3.micro'
Resources:
# Create VPC
rMyVPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.0.0.0/16
EnableDnsSupport: true
EnableDnsHostnames: true
InstanceTenancy: default
Tags:
- Key: Name
Value: test-vpc
# Create Public RouteTable
rPublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref rMyVPC
Tags:
- Key: Name
Value: test-pubric-route
# Create Public Subnet
rPublicSubnet:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref rMyVPC
CidrBlock: 10.0.0.0/24
AvailabilityZone: !Select [ 0, !GetAZs "" ]
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: test-public-subnet
rRouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref rPublicSubnet
RouteTableId: !Ref rPublicRouteTable
# Create InternetGateway
rInternetGateway:
Type: "AWS::EC2::InternetGateway"
Properties:
Tags:
- Key: Name
Value: test-igw
rAttachGateway:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref rMyVPC
InternetGatewayId: !Ref rInternetGateway
# Route for InternetGateway
rRoute:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref rPublicRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref rInternetGateway
# Create EC2 Secuirty Group
rSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
VpcId: !Ref rMyVPC
GroupDescription: Security Group for EC2 Instance
SecurityGroupIngress:
- CidrIp: 0.0.0.0/0
FromPort: 443
IpProtocol: tcp
ToPort: 443
Tags:
- Key: Name
Value: test-sg
# Create EC2 Instance
rMyEC2:
Type: AWS::EC2::Instance
Properties:
ImageId: !Ref pLatestAmiId
InstanceType: !Ref pInstanceType
SecurityGroupIds:
- !Ref rSecurityGroup
SubnetId: !Ref rPublicSubnet
Tags:
- Key: Name
Value: test-ec2
以降、前述の手順1~4に沿って順番にやっていきます。
手順1
EC2およびセキュリティグループを別スタックに分割するため、ソーステンプレートで
DeletionPolicy: Retain
を追加します。
既存のスタックで既に設定されている場合はスキップ可能な作業です。
rSecurityGroup:
Type: AWS::EC2::SecurityGroup
+ DeletionPolicy: Retain
Properties:
rMyEC2:
Type: AWS::EC2::Instance
+ DeletionPolicy: Retain
Properties:
編集後のソーステンプレート
AWSTemplateFormatVersion: '2010-09-09'
Description:
split stack test add Deletion Policy
Parameters:
pLatestAmiId:
Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
Default: '/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2'
pInstanceType:
Type: String
Default: 't3.micro'
Resources:
# Create VPC
rMyVPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.0.0.0/16
EnableDnsSupport: true
EnableDnsHostnames: true
InstanceTenancy: default
Tags:
- Key: Name
Value: test-vpc
# Create Public RouteTable
rPublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref rMyVPC
Tags:
- Key: Name
Value: test-pubric-route
# Create Public Subnet
rPublicSubnet:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref rMyVPC
CidrBlock: 10.0.0.0/24
AvailabilityZone: !Select [ 0, !GetAZs "" ]
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: test-public-subnet
rRouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref rPublicSubnet
RouteTableId: !Ref rPublicRouteTable
# Create InternetGateway
rInternetGateway:
Type: "AWS::EC2::InternetGateway"
Properties:
Tags:
- Key: Name
Value: test-igw
rAttachGateway:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref rMyVPC
InternetGatewayId: !Ref rInternetGateway
# Route for InternetGateway
rRoute:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref rPublicRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref rInternetGateway
# Create EC2 Secuirty Group
rSecurityGroup:
Type: AWS::EC2::SecurityGroup
DeletionPolicy: Retain
Properties:
VpcId: !Ref rMyVPC
GroupDescription: Security Group for EC2 Instance
SecurityGroupIngress:
- CidrIp: 0.0.0.0/0
FromPort: 443
IpProtocol: tcp
ToPort: 443
Tags:
- Key: Name
Value: test-sg
# Create EC2 Instance
rMyEC2:
Type: AWS::EC2::Instance
DeletionPolicy: Retain
Properties:
ImageId: !Ref pLatestAmiId
InstanceType: !Ref pInstanceType
SecurityGroupIds:
- !Ref rSecurityGroup
SubnetId: !Ref rPublicSubnet
Tags:
- Key: Name
Value: test-ec2
※クリックで展開
編集後のソーステンプレートを既存スタックに反映させます。
Change Set上は、変更なしでアップデートが完了します。
手順2
セキュリティグループおよびEC2インスタンスに関連する記述をソーステンプレートから削除します。
また分割先のスタックからVPCやSubnetの情報を参照できるように、リソースIDをExportしておきます。
- Parameters:
- pLatestAmiId:
- Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
- Default: '/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2'
- pInstanceType:
- Type: String
- Default: 't3.micro'
-
- rSecurityGroup:
- Type: AWS::EC2::SecurityGroup
- DeletionPolicy: Retain
- Properties:
- VpcId: !Ref rMyVPC
- GroupDescription: Security Group for EC2 Instance
- SecurityGroupIngress:
- - CidrIp: 0.0.0.0/0
- FromPort: 443
- IpProtocol: tcp
- ToPort: 443
- Tags:
- - Key: Name
- Value: test-sg
-
- rMyEC2:
- Type: AWS::EC2::Instance
- DeletionPolicy: Retain
- Properties:
- ImageId: !Ref pLatestAmiId
- InstanceType: !Ref pInstanceType
- SecurityGroupIds:
- - !Ref rSecurityGroup
- SubnetId: !Ref rPublicSubnet
- Tags:
- - Key: Name
- Value: test-ec2
+
+Outputs:
+ rMyVPC:
+ Value: !Ref rMyVPC
+ Export
+ Name: rMyVPC
+ rPublicSubnet:
+ Value: !Ref rPublicSubnet
+ Export:
+ Name: rPublicSubnet
編集後のソーステンプレート
AWSTemplateFormatVersion: '2010-09-09'
Description:
split stack test add vpc only
Resources:
# Create VPC
rMyVPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.0.0.0/16
EnableDnsSupport: true
EnableDnsHostnames: true
InstanceTenancy: default
Tags:
- Key: Name
Value: test-vpc
# Create Public RouteTable
rPublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref rMyVPC
Tags:
- Key: Name
Value: test-pubric-route
# Create Public Subnet
rPublicSubnet:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref rMyVPC
CidrBlock: 10.0.0.0/24
AvailabilityZone: !Select [ 0, !GetAZs "" ]
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: test-public-subnet
rRouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref rPublicSubnet
RouteTableId: !Ref rPublicRouteTable
# Create InternetGateway
rInternetGateway:
Type: "AWS::EC2::InternetGateway"
Properties:
Tags:
- Key: Name
Value: test-igw
rAttachGateway:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref rMyVPC
InternetGatewayId: !Ref rInternetGateway
# Route for InternetGateway
rRoute:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref rPublicRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref rInternetGateway
Outputs:
rMyVPC:
Value: !Ref rMyVPC
Export:
Name: rMyVPC
rPublicSubnet:
Value: !Ref rPublicSubnet
Export:
Name: rPublicSubnet
※クリックで展開
分割するセキュリティグループとEC2に関する記載はターゲットテンプレートとして新規作成します。
VPCIDおよびSubnetIDはクロススタック参照させています。
インポートするリソースにもテンプレートで DeletionPolicy 属性を指定する必要があります。
AWSTemplateFormatVersion: '2010-09-09'
Description:
split stack test ec2 only
Parameters:
pLatestAmiId:
Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
Default: '/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2'
pInstanceType:
Type: String
Default: 't3.micro'
Resources:
# Create EC2 Secuirty Group
rSecurityGroup:
Type: AWS::EC2::SecurityGroup
DeletionPolicy: Retain
Properties:
VpcId: !ImportValue rMyVPC
GroupDescription: Security Group for EC2 Instance
SecurityGroupIngress:
- CidrIp: 0.0.0.0/0
FromPort: 443
IpProtocol: tcp
ToPort: 443
Tags:
- Key: Name
Value: test-sg
# Create EC2 Instance
rMyEC2:
Type: AWS::EC2::Instance
DeletionPolicy: Retain
Properties:
ImageId: !Ref pLatestAmiId
InstanceType: !Ref pInstanceType
SecurityGroupIds:
- !Ref rSecurityGroup
SubnetId: !ImportValue rPublicSubnet
Tags:
- Key: Name
Value: test-ec2
手順3
更新したソーステンプレートを使用して、既存のスタックを Update します。
DeletionPolicyにより、リソース自体の削除はスキップされますが、
この時点でセキュリティグループおよび、EC2は既存スタックの管理対象外となります。
手順4
ターゲットテンプレートを使用して、管理対象外となったEC2とセキュリティグループをインポートします。
スタックの作成で 既存のリソースを使用 を選択します。
テンプレートの指定で、ターゲットテンプレートをアップロードして次に進みます。
リソースを識別で、インポート対象のEC2とセキュリティグループのリソースIDを指定します。
スタックの詳細を指定で、新たに作成するスタックの名前を設定します。
インポートが完了し、既存のEC2とセキュリティグループが新しいスタックの
管理対象となっていることを確認します。
まとめ
移動するリソースに削除ポリシーを追加し、ソーススタックから削除&ターゲットスタックに
インポートすることでスタック間でのリソースの移動を簡単に行うことができます。
だだし、現地時点でインポートに対応しているリソースは限られているのでご注意ください。
Resources that Support Import Operations
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/resource-import-supported-resources.html
Moving Resources Between Stacks
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/refactor-stacks.html
以上です。
参考になれば幸いです。