この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
CloudFormationでのスタックのネスト
CloudFormationでは、スタックをネストさせること可能です。
ネストさせる際には、テンプレート(ファイル)を分割して記述することができるので、一度作成したテンプレートを使い回すことができます。
本記事では、実際にスタックをネストし、EC2の起動を行なっていきます。
作成する構成
EC2をPublic Subnet上に立てます。今回は使用しませんが、Private Subnetも構築します。
各リソースのテンプレート作成
ファイル構成は以下のように行います。
├── ec2
│ ├── ec2.yaml
│ └── sg.yaml
├── main.yaml
├── subnet
│ ├── private
│ │ └── subnet.yaml
│ └── public
│ └── subnet.yaml
└── vpc
└── vpc.yaml
EC2を作成する際に、セキュリティグループのテンプレートを呼び出すようにします。
親テンプレートの作成
各テンプレートを呼び出す親テンプレートを作成します。
main.yaml
AWSTemplateFormatVersion: "2010-09-09"
Description: nesting stack
Resources:
VPC:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: vpc/vpc.yaml
Parameters:
TagName : "VPCTEST"
PrivateSubnet:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: subnet/private/subnet.yaml
Parameters:
VPC: !GetAtt VPC.Outputs.VPCID
PublicSubnet:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: subnet/public/subnet.yaml
Parameters:
VPC: !GetAtt VPC.Outputs.VPCID
EC2Instance:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: ec2/ec2.yaml
Parameters:
VPC: !GetAtt VPC.Outputs.VPCID
KeyName: hogehoge
Subnet: !GetAtt PublicSubnet.Outputs.SubnetID
VPCテンプレートの作成
VPCのIDを渡すのでOutputsに指定しています。
vpc/vpc.yaml
AWSTemplateFormatVersion: '2010-09-09'
Description: 'VPC for nesting'
Parameters:
VPCCIDR:
Type: String
Default: "10.1.0.0/16"
TagName :
Type: String
Default: "nesting"
Resources:
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VPCCIDR
Tags:
- Key: Name
Value: !Ref TagName
Outputs:
VPCID:
Value: !Ref VPC
サブネットテンプレートの作成
パブリック、プライベートサブネットそれぞれの作成を行います。
subnet/private/subnet.yaml
AWSTemplateFormatVersion: '2010-09-09'
Description: 'private subnet for nesting'
Parameters:
AZ:
Type: AWS::EC2::AvailabilityZone::Name
Default: ap-northeast-1a
TagName:
Type: String
Default: "subnetnesting"
VPC:
Type: AWS::EC2::VPC::Id
Resources:
PrivateSubnet:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: !Ref AZ
VpcId: !Ref VPC
CidrBlock: 10.1.1.0/24
Tags:
- Key: Name
Value: !Ref TagName
PrivateRouteTable:
Type: "AWS::EC2::RouteTable"
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Ref TagName
PrivateSubnetTableAssociation:
Type: "AWS::EC2::SubnetRouteTableAssociation"
Properties:
SubnetId: !Ref PrivateSubnet
RouteTableId: !Ref PrivateRouteTable
Outputs:
SubnetID:
Value: !Ref PrivateSubnet
subnet/public/subnet.yaml
AWSTemplateFormatVersion: '2010-09-09'
Description: 'public subnet for nesting'
Parameters:
AZ:
Type: AWS::EC2::AvailabilityZone::Name
Default: ap-northeast-1a
TagName:
Type: String
Default: "subnetnesting"
VPC:
Type: AWS::EC2::VPC::Id
Resources:
PublicSubnet:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: !Ref AZ
VpcId: !Ref VPC
CidrBlock: 10.1.2.0/24
Tags:
- Key: Name
Value: !Ref TagName
PublicRouteTable:
Type: "AWS::EC2::RouteTable"
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Ref TagName
InternetGateway:
Type: "AWS::EC2::InternetGateway"
Properties:
Tags:
- Key: Name
Value: !Ref TagName
InternetGatewayAttachment:
Type: "AWS::EC2::VPCGatewayAttachment"
Properties:
InternetGatewayId: !Ref InternetGateway
VpcId: !Ref VPC
PublicRoute:
Type: "AWS::EC2::Route"
Properties:
RouteTableId: !Ref PublicRouteTable
DestinationCidrBlock: "0.0.0.0/0"
GatewayId: !Ref InternetGateway
PublicSubnetTableAssociation:
Type: "AWS::EC2::SubnetRouteTableAssociation"
Properties:
SubnetId: !Ref PublicSubnet
RouteTableId: !Ref PublicRouteTable
Outputs:
SubnetID:
Value: !Ref PublicSubnet
EC2テンプレートの作成
EC2では、セキュリティグループのテンプレートを呼び出すように記述します。
動作確認のため、LAMPを構築するようにユーザデータを指定します。
ec2/ec2.yaml
AWSTemplateFormatVersion: '2010-09-09'
Description: 'VPC for nesting'
Parameters:
ImageId:
Type: String
Default: "ami-0701e21c502689c31"
KeyName:
Type: String
Subnet:
Type: AWS::EC2::Subnet::Id
VPC:
Type: AWS::EC2::VPC::Id
TagName :
Type: String
Default: "nesting"
Resources:
EC2SG:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: sg.yaml
Parameters:
VPC: !Ref VPC
EC2Instance:
Type: AWS::EC2::Instance
Properties:
ImageId: !Ref ImageId
KeyName: !Ref KeyName
InstanceType: t2.micro
NetworkInterfaces:
- AssociatePublicIpAddress: "true"
DeviceIndex: "0"
SubnetId: !Ref Subnet
GroupSet:
- !GetAtt EC2SG.Outputs.SGID
UserData: !Base64 |
#!/bin/bash
yum update -y
amazon-linux-extras install -y lamp-mariadb10.2-php7.2 php7.2
yum install -y httpd mariadb-server
systemctl start httpd
systemctl enable httpd
usermod -a -G apache ec2-user
chown -R ec2-user:apache /var/www
chmod 2775 /var/www && find /var/www -type d -exec sudo chmod 2775 {} \;
find /var/www -type f -exec sudo chmod 0664 {} \;
echo "<?php phpinfo(); ?>" > /var/www/html/phpinfo.php
systemctl start mariadb
mysqladmin password hogehoge1111
yum install php-mbstring php-xml -y
systemctl restart httpd
systemctl restart php-fpm
wget https://www.phpmyadmin.net/downloads/phpMyAdmin-latest-all-languages.tar.gz
mkdir /var/www/html/phpMyAdmin && tar -xvzf phpMyAdmin-latest-all-languages.tar.gz -C /var/www/html/phpMyAdmin --strip-components 1
rm phpMyAdmin-latest-all-languages.tar.gz
systemctl start mariadb
Tags:
- Key: Name
Value: !Ref TagName
セキュリティグループテンプレートの作成
セキュリティグループのIDをEC2に渡す必要があるため、Outputsで指定します。
ec2/sg.yaml
AWSTemplateFormatVersion: '2010-09-09'
Description: 'SG for nesting'
Parameters:
MyIP:
Type: String
Default: "0.0.0.0/0"
VPC:
Type: AWS::EC2::VPC::Id
TagName :
Type: String
Default: "nesting"
Resources:
EC2SG:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: "test demo"
VpcId: !Ref VPC
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: !Ref MyIP
- IpProtocol: tcp
FromPort: 22
ToPort: 22
CidrIp: !Ref MyIP
Tags:
- Key: Name
Value: !Ref TagName
Outputs:
SGID:
Value: !Ref EC2SG
スタック作成の準備をする
このままの記述では、ローカルファイルを参照できないので、S3 バケットへアップロードします。
バケットの作成
$ aws s3 mb s3://nested-stack-artifact
バケット作成後、下記コマンドでアップロードします。
aws cloudformation package --template-file main.yaml \
--s3-bucket nested-stack-artifact \
--output-template-file artifact.yml
正常に実行できると、artifact.yml
が作成されています。
中身を見てみると、先ほどまでローカルファイルを指定していたものがs3のファイル参照に変更されていることが確認できます。
artifact.yml
AWSTemplateFormatVersion: '2010-09-09'
Description: nesting stack
Resources:
VPC:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: https://s3.ap-northeast-1.amazonaws.com/nested-stack-artifact/hogehoge.template
Parameters:
TagName: VPCTEST
PrivateSubnet:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: https://s3.ap-northeast-1.amazonaws.com/nested-stack-artifact/hogehoge.template
Parameters:
VPC:
Fn::GetAtt:
- VPC
- Outputs.VPCID
PublicSubnet:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: https://s3.ap-northeast-1.amazonaws.com/nested-stack-artifact/hogehoge.template
Parameters:
VPC:
Fn::GetAtt:
- VPC
- Outputs.VPCID
EC2Instance:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: https://s3.ap-northeast-1.amazonaws.com/nested-stack-artifact/hogehoge.template
Parameters:
VPC:
Fn::GetAtt:
- VPC
- Outputs.VPCID
KeyName: hogehoge
Subnet:
Fn::GetAtt:
- PublicSubnet
- Outputs.SubnetID
スタックの作成
では、最後にスタックの作成を行います。先程のartifact.yml
を指定します。
aws cloudformation deploy --template-file artifact.yml --stack-name nested-stack-demo
コンソール上を確認すると、作成したスタックとネストされたスタックが確認できます。
しばらく待つと、CREATE_COMPLETEとなります。
まとめ
本記事では、ネスタされたスタックを作成してみましたが、再利用できるのは非常に魅力的だと感じました。
一方で、どこまで分割していくかが悩ましいところです。細かく分割してしまうと、逆にファイルの管理が大変になりそうですので、機能ごとにスタックをまとめて、再利用していくのが良さそうです。