はじめに
AWS公式のハンズオンシリーズの中から、CloudFormationで Web システムを構築するハンズオンを実施しました。
本記事は自身のハンズオン学習メモとして投稿します。
目次
ハンズオンの目的
- AWS環境をコードを使用して管理する方法を学習する
クラウドにおける構成管理の考え方をご理解頂くとともに、AWS CloudFormationを使用したWebシステムの環境構築について、実際に手を動かして理解を深めることができます。
(https://aws.amazon.com/jp/aws-jp-introduction/aws-jp-webinar-hands-on/ より引用)
本編
開発環境の構築
- 開発環境としてAWS Cloud9の環境を構築
- マネジメントコンソールからインスタンスを作成
- Cloud9の環境確認と設定
- バージョン情報の確認
- AWS CLIの補完設定
- エディタ設定
テンプレートの実行方法+VPCの作成
- マネジメントコンソールからVPC用スタックを作る
AWSTemplateFormatVersion: 2010-09-09
Description: Hands-on template for VPC
Resources:
CFnVPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.0.0.0/16
InstanceTenancy: default
EnableDnsSupport: true
EnableDnsHostnames: true
Tags:
- Key: Name
Value: handson-cfn
PublicSubnet1:
Type: AWS::EC2::Subnet
Properties:
CidrBlock: 10.0.0.0/24
VpcId: !Ref CFnVPC
AvailabilityZone: !Select [ 0, !GetAZs ]
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: PublicSubnet1
PublicSubnet2:
Type: AWS::EC2::Subnet
Properties:
CidrBlock: 10.0.1.0/24
VpcId: !Ref CFnVPC
AvailabilityZone: !Select [ 1, !GetAZs ]
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: PublicSubnet2
PrivateSubnet1:
Type: AWS::EC2::Subnet
Properties:
CidrBlock: 10.0.2.0/24
VpcId: !Ref CFnVPC
AvailabilityZone: !Select [ 0, !GetAZs ]
Tags:
- Key: Name
Value: PrivateSubnet1
PrivateSubnet2:
Type: AWS::EC2::Subnet
Properties:
CidrBlock: 10.0.3.0/24
VpcId: !Ref CFnVPC
AvailabilityZone: !Select [ 1, !GetAZs ]
Tags:
- Key: Name
Value: PrivateSubnet2
CFnVPCIGW:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: handson-cfn
CFnVPCIGWAttach:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
InternetGatewayId: !Ref CFnVPCIGW
VpcId: !Ref CFnVPC
PublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref CFnVPC
Tags:
- Key: Name
Value: Public Route
PublicRoute:
Type: AWS::EC2::Route
DependsOn: CFnVPCIGW
Properties:
RouteTableId: !Ref PublicRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref CFnVPCIGW
PublicSubnet1Association:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PublicSubnet1
RouteTableId: !Ref PublicRouteTable
PublicSubnet2Association:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PublicSubnet2
RouteTableId: !Ref PublicRouteTable
Outputs:
VPCID:
Description: VPC ID
Value: !Ref CFnVPC
Export:
Name: !Sub ${AWS::StackName}-VPCID
PublicSubnet1:
Description: PublicSubnet1
Value: !Ref PublicSubnet1
Export:
Name: !Sub ${AWS::StackName}-PublicSubnet1
PublicSubnet2:
Description: PublicSubnet2
Value: !Ref PublicSubnet2
Export:
Name: !Sub ${AWS::StackName}-PublicSubnet2
PrivateSubnet1:
Description: PrivateSubnet1
Value: !Ref PrivateSubnet1
Export:
Name: !Sub ${AWS::StackName}-PrivateSubnet1
PrivateSubnet2:
Description: PrivateSubnet2
Value: !Ref PrivateSubnet2
Export:
Name: !Sub ${AWS::StackName}-PrivateSubnet2
- Cloud9でのテンプレートの編集
パラメータについては、適宜テンプレートリファレンスを参照して作成していく。
- AWS CLIを利用してスタックの更新
validateして
aws cloudformation validate-template --template-body file://01_vpc.yml
updateする
aws cloudformation update-stack --stack-name handson-cfn --template-body file://01_vpc.yml
EC2の作成
- 配布したテンプレートでEC2を起動
createする
aws cloudformation create-stack --stack-name handson-cfn-ec2 --template-body file://02_ec2.yml
- 不足設定を書き加えて、テンプレートを完成させる
AWSTemplateFormatVersion: 2010-09-09
Description: Hands-on template for EC2
Parameters:
VPCStack:
Type: String
Default: handson-cfn
EC2AMI:
Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2
Resources:
EC2WebServer01:
Type: AWS::EC2::Instance
Properties:
ImageId: !Ref EC2AMI
InstanceType: t2.micro
SubnetId: subnet-04c1d329aec13802b
UserData: !Base64 |
#! /bin/bash
yum update -y
amazon-linux-extras install php7.2 -y
yum -y install mysql httpd php-mbstring php-xml
wget http://ja.wordpress.org/latest-ja.tar.gz -P /tmp/
tar zxvf /tmp/latest-ja.tar.gz -C /tmp
cp -r /tmp/wordpress/* /var/www/html/
touch /var/www/html/.check_alive
chown apache:apache -R /var/www/html
systemctl enable httpd.service
systemctl start httpd.service
SecurityGroupIds:
- !Ref EC2SG
EC2SG:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: sg for web server
VpcId: vpc-0dca3e5092f72557c
SecurityGroupIngress:
- IpProtocol: tcp
CidrIp: 10.0.0.0/16
FromPort: 80
ToPort: 80
Outputs:
EC2WebServer01:
Value: !Ref EC2WebServer01
Export:
Name: !Sub ${AWS::StackName}-EC2WebServer01
validateして
aws cloudformation validate-template --template-body file://02_ec2.yml
updateする
aws cloudformation update-stack --stack-name handson-cfn-ec2 --template-body file://02_ec2.yml
RDS, ELBの作成、スタックのライフサイクル・分割
- RDS・ELB用スタックの作成
以下のテンプレートを作成し、上記と同様にCreate&validate&update。
AWSTemplateFormatVersion: 2010-09-09
Description: Hands-on template for RDS
Parameters:
VPCStack:
Type: String
Default: handson-cfn
DBUser:
Type: String
Default: dbmaster
DBPassword:
Type: String
Default: H&ppyHands0n
NoEcho: true
Resources:
DBInstance:
Type: AWS::RDS::DBInstance
DeletionPolicy: Delete
Properties:
DBInstanceClass: db.t2.micro
AllocatedStorage: "10"
StorageType: gp2
Engine: MySQL
MasterUsername: !Ref DBUser
MasterUserPassword: !Ref DBPassword
DBName: wordpress
BackupRetentionPeriod: 0
DBSubnetGroupName: !Ref DBSubnetGroup
VPCSecurityGroups:
- !Ref DBSecurityGroup
DBSubnetGroup:
Type: AWS::RDS::DBSubnetGroup
Properties:
DBSubnetGroupDescription: DB Subnet Group for Private Subnet
SubnetIds:
- Fn::ImportValue: !Sub ${VPCStack}-PrivateSubnet1
- Fn::ImportValue: !Sub ${VPCStack}-PrivateSubnet2
DBSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: !Sub ${AWS::StackName}-MySQL
VpcId:
Fn::ImportValue: !Sub ${VPCStack}-VPCID
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 3306
ToPort: 3306
CidrIp: 10.0.0.0/16
Outputs:
DBEndpoint:
Value: !GetAtt DBInstance.Endpoint.Address
Export:
Name: !Sub ${AWS::StackName}-DBEndpoint
AWSTemplateFormatVersion: 2010-09-09
Description: Hands-on template for ALB
Parameters:
VPCStack:
Type: String
Default: handson-cfn
EC2Stack:
Type: String
Default: handson-cfn-ec2
Resources:
FrontLB:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
Name: !Ref AWS::StackName
Subnets:
- Fn::ImportValue: !Sub ${VPCStack}-PublicSubnet1
- Fn::ImportValue: !Sub ${VPCStack}-PublicSubnet2
SecurityGroups:
- !Ref SecurityGroupLB
FrontLBListener:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
LoadBalancerArn: !Ref FrontLB
Port: 80
Protocol: HTTP
DefaultActions:
- Type: forward
TargetGroupArn: !Ref FrontLBTargetGroup
FrontLBTargetGroup:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
Name: !Sub ${AWS::StackName}-tg
VpcId:
Fn::ImportValue: !Sub ${VPCStack}-VPCID
Port: 80
Protocol: HTTP
HealthCheckPath: /.check_alive
Targets:
- Id:
Fn::ImportValue: !Sub ${EC2Stack}-EC2WebServer01
SecurityGroupLB:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: !Ref AWS::StackName
VpcId:
Fn::ImportValue: !Sub ${VPCStack}-VPCID
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: 0.0.0.0/0
Outputs:
FrontLBEndpoint:
Value: !GetAtt FrontLB.DNSName
Export:
Name: !Sub ${AWS::StackName}-Endpoint
- 完成した構成の動作を確認
無事にWordPressに接続成功。
スタックのライフサイクル・分割について
- 個々のスタックは、ライフサイクルと所有者を基準に分割
- VPC用スタックをベースとして、他スタックからクロススタック参照によって連携
作成した AWS リソースの削除
スタックを削除すると紐づくリソースが全て削除される。
#おわりに
異なるスタックのリソースを参照できるクロススタック参照と、ネストの方法について調べてみた。
クロススタック参照
- 参照される側のテンプレート
"Outputs"の項目でExportプロパティを記述し、値をエクスポート - 参照する側のテンプレート
組み込み関数Fn::ImportValueを使って、値をインポート
詳しくは以下を参照。
CloudFormationのスタック間でリソースを参照する
ネスト
以下により、上位テンプレートで下位テンプレートからの出力を受ける事が出来る。また、上位テンプレートで受けた出力は別の下位テンプレートへの入力として指定することもできる。
- ネストするテンプレートをAmazonS3上にアップロード
- 下位のテンプレートで渡したいパラメータをOutputsに記述
- 上位のテンプレートでは"組み込み関数Fn::GetAttを利用する
詳しくは以下を参照。
CloudFormationでスタックをネストする
所感
スタックの作成時、テンプレートから依存関係を自動で判別し構築してくれるのは便利だと感じた。
比較対象としては他プラットフォームも含めて管理できるTerraformが挙がってくると思うので、そちらも触ってみたい。