CloudFormationのコマンドラインツールRainを使用してWordPress環境を構築してみた
はじめに
Classmethod様の記事を拝見してRainを使ってみたかったのと、VPC関連リソースをCloudFormation化して好きな時に作って壊したいなと思っていたので、重い腰を上げてやってみました。
環境↓
$ sw_vers
ProductName: macOS
ProductVersion: 11.2.1
BuildVersion: 20D74
$ rain --version
Rain v1.1.1 darwin/amd64
Rainとは
CloudFormationのためのコマンドラインツールです。
使ってみて嬉しかった機能は以下の3つです。
- デプロイのリアルタイム情報が表示される
- リソースを指定したら、そのリソースに合わせたテンプレートを作成してくれる
- デプロイ失敗後の再デプロイがコンソールと比べて激速
詳細はGitHubをご覧ください。
私がRainを知ったきっかけはClassmethod様の記事なのでこちらもどうぞ。
WordPress環境の完成図
Rainを使ってCloudFormationテンプレートを作成する
rain build | ネットワーク系テンプレート作成
rain build
コマンドでリソースタイプを指定すると、そのリソースのプロパティを記述したテンプレートの雛形を作成してくれます。
まず、VPCなどのネットワーク系リソースのテンプレートを作成し、その後にEC2インスタンス、RDSを作成していきます。
必要なリソースタイプはこちらの公式ドキュメントから探しながら、
こちらのAWS側で提供しているテンプレートなども参考にしました。$ rain build AWS::EC2::VPC AWS::EC2::InternetGateway AWS::EC2::VPCGatewayAttachment AWS::EC2::Subnet AWS::EC2::Subnet AWS::EC2::Subnet AWS::EC2::Subnet AWS::EC2::RouteTable AWS::EC2::Route AWS::EC2::SubnetRouteTableAssociation > rain/Network.yaml
Network.yaml
AWSTemplateFormatVersion: "2010-09-09"
Description: Template generated by rain
Resources:
MyInternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: CHANGEME
Value: CHANGEME
MyRoute:
Type: AWS::EC2::Route
Properties:
DestinationCidrBlock: CHANGEME # Optional
DestinationIpv6CidrBlock: CHANGEME # Optional
EgressOnlyInternetGatewayId: CHANGEME # Optional
GatewayId: CHANGEME # Optional
InstanceId: CHANGEME # Optional
NatGatewayId: CHANGEME # Optional
NetworkInterfaceId: CHANGEME # Optional
RouteTableId: CHANGEME
TransitGatewayId: CHANGEME # Optional
VpcPeeringConnectionId: CHANGEME # Optional
MyRouteTable:
Type: AWS::EC2::RouteTable
Properties:
Tags:
- Key: CHANGEME
Value: CHANGEME
VpcId: CHANGEME
MySubnet1:
Type: AWS::EC2::Subnet
Properties:
AssignIpv6AddressOnCreation: false # Optional
AvailabilityZone: CHANGEME # Optional
CidrBlock: CHANGEME
Ipv6CidrBlock: CHANGEME # Optional
MapPublicIpOnLaunch: false # Optional
Tags:
- Key: CHANGEME
Value: CHANGEME
VpcId: CHANGEME
MySubnet2:
Type: AWS::EC2::Subnet
Properties:
AssignIpv6AddressOnCreation: false # Optional
AvailabilityZone: CHANGEME # Optional
CidrBlock: CHANGEME
Ipv6CidrBlock: CHANGEME # Optional
MapPublicIpOnLaunch: false # Optional
Tags:
- Key: CHANGEME
Value: CHANGEME
VpcId: CHANGEME
MySubnet3:
Type: AWS::EC2::Subnet
Properties:
AssignIpv6AddressOnCreation: false # Optional
AvailabilityZone: CHANGEME # Optional
CidrBlock: CHANGEME
Ipv6CidrBlock: CHANGEME # Optional
MapPublicIpOnLaunch: false # Optional
Tags:
- Key: CHANGEME
Value: CHANGEME
VpcId: CHANGEME
MySubnet4:
Type: AWS::EC2::Subnet
Properties:
AssignIpv6AddressOnCreation: false # Optional
AvailabilityZone: CHANGEME # Optional
CidrBlock: CHANGEME
Ipv6CidrBlock: CHANGEME # Optional
MapPublicIpOnLaunch: false # Optional
Tags:
- Key: CHANGEME
Value: CHANGEME
VpcId: CHANGEME
MySubnetRouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: CHANGEME
SubnetId: CHANGEME
MyVPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: CHANGEME
EnableDnsHostnames: false # Optional
EnableDnsSupport: false # Optional
InstanceTenancy: CHANGEME # Optional
Tags:
- Key: CHANGEME
Value: CHANGEME
MyVPCGatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
InternetGatewayId: CHANGEME # Optional
VpcId: CHANGEME
VpnGatewayId: CHANGEME # Optional
Outputs:
MySubnet1AvailabilityZone:
Value: !GetAtt MySubnet1.AvailabilityZone
MySubnet1Ipv6CidrBlocks:
Value: !GetAtt MySubnet1.Ipv6CidrBlocks
MySubnet1NetworkAclAssociationId:
Value: !GetAtt MySubnet1.NetworkAclAssociationId
MySubnet1VpcId:
Value: !GetAtt MySubnet1.VpcId
MySubnet2AvailabilityZone:
Value: !GetAtt MySubnet2.AvailabilityZone
MySubnet2Ipv6CidrBlocks:
Value: !GetAtt MySubnet2.Ipv6CidrBlocks
MySubnet2NetworkAclAssociationId:
Value: !GetAtt MySubnet2.NetworkAclAssociationId
MySubnet2VpcId:
Value: !GetAtt MySubnet2.VpcId
MySubnet3AvailabilityZone:
Value: !GetAtt MySubnet3.AvailabilityZone
MySubnet3Ipv6CidrBlocks:
Value: !GetAtt MySubnet3.Ipv6CidrBlocks
MySubnet3NetworkAclAssociationId:
Value: !GetAtt MySubnet3.NetworkAclAssociationId
MySubnet3VpcId:
Value: !GetAtt MySubnet3.VpcId
MySubnet4AvailabilityZone:
Value: !GetAtt MySubnet4.AvailabilityZone
MySubnet4Ipv6CidrBlocks:
Value: !GetAtt MySubnet4.Ipv6CidrBlocks
MySubnet4NetworkAclAssociationId:
Value: !GetAtt MySubnet4.NetworkAclAssociationId
MySubnet4VpcId:
Value: !GetAtt MySubnet4.VpcId
MyVPCCidrBlock:
Value: !GetAtt MyVPC.CidrBlock
MyVPCCidrBlockAssociations:
Value: !GetAtt MyVPC.CidrBlockAssociations
MyVPCDefaultNetworkAcl:
Value: !GetAtt MyVPC.DefaultNetworkAcl
MyVPCDefaultSecurityGroup:
Value: !GetAtt MyVPC.DefaultSecurityGroup
MyVPCIpv6CidrBlocks:
Value: !GetAtt MyVPC.Ipv6CidrBlocks
そのプロパティがオプションか分かるように表示してくれます。
誤字の心配がなく、Outputs
までカバー。
rain build --bare
とすれば、必須のプロパティのみ表示してくれます。
神ですね。
リソースの並び順はアルファベット順のようです。
個人的には指定した引数順に並べてくれたらなお嬉しいです。
では、このテンプレートを活用して肉付けしていきます。
VPC・InternetGatewayの設定
Parameters:
VpcCidrIpv4:
Type: String
Default: 10.0.0.0/16
ConstraintDescription: Malformed input-Parameter VpcCidrIpv4 must match pattern (x.x.x.x/16-28)
AllowedPattern: ^(([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])/1[6-9]|2[0-8]$
InstanceTenancy:
Type: String
Default: default
AllowedValues:
- default
- dedicated
- host
Resources:
# VPC
MyVPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VpcCidrIpv4
EnableDnsHostnames: true # Optional
EnableDnsSupport: true # Optional
InstanceTenancy: !Ref InstanceTenancy # Optional
# InternetGateway
MyInternetGateway:
Type: AWS::EC2::InternetGateway
MyVPCGatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
InternetGatewayId: !Ref MyInternetGateway # Optional
VpcId: !Ref MyVPC
VPCのCidrBlock
やInstanceTenancy
をパラメータで渡すことで、カスタマイズできるようにしています。
CIDRはAllowedPattern
により正規表現に一致する値しか入力できないようにしています。
ここまでする必要があるかは疑問ですが、正規表現の勉強がてらしてみました。
なお、CloudFormationの正規表現はJavaの正規表現構文に準拠しています。
正規表現の参考・チェックに使用したサイトはこちら。Subnetの設定
Parameters:
SubnetCidrIpv4:
Type: CommaDelimitedList
Default: 10.0.0.0/24, 10.0.1.0/24, 10.0.2.0/24, 10.0.3.0/24
Description: Comma-delimited list of four CIDR blocks. The first half is Public and the second half is Private。
AvailabilityZoneSubnet1:
Type: AWS::EC2::AvailabilityZone::Name
Default: ap-northeast-1a
AvailabilityZoneSubnet2:
Type: AWS::EC2::AvailabilityZone::Name
Default: ap-northeast-1c
Resources:
# Subnet
PublicSubnet1:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: !Ref AvailabilityZoneSubnet1 # Optional
CidrBlock: !Select
- 0
- !Ref SubnetCidrIpv4
MapPublicIpOnLaunch: true # Optional
VpcId: !Ref MyVPC
PublicSubnet2:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: !Ref AvailabilityZoneSubnet2 # Optional
CidrBlock: !Select
- 1
- !Ref SubnetCidrIpv4
MapPublicIpOnLaunch: true # Optional
VpcId: !Ref MyVPC
PrivateSubnet1:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: !Ref AvailabilityZoneSubnet1 # Optional
CidrBlock: !Select
- 2
- !Ref SubnetCidrIpv4
MapPublicIpOnLaunch: false # Optional
VpcId: !Ref MyVPC
PrivateSubnet2:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: !Ref AvailabilityZoneSubnet2 # Optional
CidrBlock: !Select
- 3
- !Ref SubnetCidrIpv4
MapPublicIpOnLaunch: false # Optional
VpcId: !Ref MyVPC
サブネットのCidrBlock
はパラメータ型CommaDelimitedList
と組み込み関数Fn::Select
を使用し、一つのパラメータから値を受け取れるようにしました。
Routeの設定
# Route
PublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
Tags:
- Key: CHANGEME
Value: CHANGEME
VpcId: !Ref MyVPC
PublicRoute:
Type: AWS::EC2::Route
Properties:
GatewayId: !Ref MyInternetGateway # Optional
RouteTableId: !Ref PublicRouteTable
PublicSubnet1RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PublicRouteTable
SubnetId: !Ref PublicSubnet1
PublicSubnet2RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PublicRouteTable
SubnetId: !Ref PublicSubnet2
PrivateRouteTable:
Type: AWS::EC2::RouteTable
Properties:
Tags:
- Key: CHANGEME
Value: CHANGEME
VpcId: !Ref MyVPC
PrivateSubnet1RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PrivateRouteTable
SubnetId: !Ref PrivateSubnet1
PrivateSubnet2RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PrivateRouteTable
SubnetId: !Ref PrivateSubnet2
Route関連のリソースは多少ややこしく感じました。
まずRouteTable
を作成し、そのテーブルにRoute
を追加して、そのRouteTable
を各サブネットにAssociation
します。
これでリソース部分は完成しました。
後はコンソールでパラメータの見た目を良くするためのMetadata
の設定と、他のテンプレートでVPCIDなどを使用するためのOutputs
の設定をしたらネットワーク系テンプレートの作成は完了です。
Metadata
Metadata
Metadata:
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: VPC Configuration
Parameters:
- VPCCidrIpv4
- InstanceTenancy
- Label:
default: Subnet Configuration
Parameters:
- SubnetCidrIpv4
- AvailabilityZoneSubnet1
- AvailabilityZoneSubnet2
- Label:
default: Tag
Parameters:
- PrefixNameTagValue
Outputs
Outputs
Outputs:
MyVPCId:
Value: !Ref MyVPC
Export:
Name: !Sub ${AWS::StackName}-VPCId
PublicSubnet1Id:
Value: !Ref PublicSubnet1
Export:
Name: !Sub ${AWS::StackName}-PublicSubnet1Id
PublicSubnet2Id:
Value: !Ref PublicSubnet2
Export:
Name: !Sub ${AWS::StackName}-PublicSubnet2Id
PrivateSubnet1Subnet1Id:
Value: !Ref PrivateSubnet1
Export:
Name: !Sub ${AWS::StackName}-PrivateSubnet1Id
PrivateSubnet2Subnet1Id:
Value: !Ref PrivateSubnet2
Export:
Name: !Sub ${AWS::StackName}-PrivateSubnet2Id
EC2インスタンスとRDSで各IDを使用するので、クロススタック参照するために出力しておきます。
rain fmt | テンプレートのフォーマット
テンプレートが完成したので、フォーマットしたらどうなるのか試してみます。
デフォルトでは標準出力でフォーマットされるため、ファイルに書き込みます。
$ rain fmt Network.yaml > fmt-Network.yaml
以下の点が変化していました。
- パラメータのプロパティ順序
- コメント位置
以下のように変わっていました。
Parameters:
InstanceTenancy:
Type: String
Default: default
AllowedValues:
- default
- dedicated
- host
Resources:
# VPC
MyVPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VPCCidrIpv4
EnableDnsHostnames: true # Optional
EnableDnsSupport: true # Optional
InstanceTenancy: !Ref InstanceTenancy # Optional
# InternetGateway
↓
Parameters:
InstanceTenancy:
Type: String
AllowedValues:
- default
- dedicated
- host
Default: default
Resources:
# VPC
MyVPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VPCCidrIpv4
EnableDnsHostnames: true # Optional
EnableDnsSupport: true # Optional
InstanceTenancy: !Ref InstanceTenancy # Optional
# InternetGateway
コメントが変なところに行っているので、rain fmt
は使わない方がいいかもしれません。
yaml⇄JSONの変更もできますが、yaml→JSONにしようとしたらSemantic difference after formatting:
とエラーが発生してできませんでした。
リストに-
ではなく[]
を使用する必要があるかもしれません。
rain deploy | テンプレートデプロイ
Stackをデプロイするため、rain deploy
を使用します。
rain deploy
を実行すると、以下のことがわかりました。
- 初回はrain用のS3バケットが作成される
- Stack名を指定しない場合、テンプレートの名前がStackの名前となる(拡張子除く)
- 入力するパラメータの順序は毎回異なる
- 変更セットが表示
- RollBack時のエラー理由表示
- デプロイ失敗後の再デプロイ時、失敗したStackを自動的に削除するが、入力したパラメータは流用できる
- デプロイに成功すると
Outputs
も表示
特にデプロイ失敗後の再デプロイ時に、自動的にStackを削除してくれることが嬉しいです。
コンソールだとこの作業が面倒なので助かります。
rain deploy
実行時のターミナルは以下のとおりです(私が原因のプロパティの誤字でエラーが起きています)。
$ rain deploy --profile $PROFILE Network.yaml NetworkStack
Rain needs to create an S3 bucket called 'rain-artifacts-300805321587-ap-northeaRain needs to create an S3 bucket called 'rain-artifacts-300805321587-ap-northeaRain needs to create an S3 bucket called 'rain-artifacts-300805321587-ap-northeast-1'. Continue? (Y/n) Y
Enter a value for parameter 'InstanceTenancy' (default value: default):
Enter a value for parameter 'SubnetCidrIpv4' "Comma-delimited list of four CIDR blocks. The first half is Public and the second half is Private。" (default valuEnter a value for parameter 'SubnetCidrIpv4' "Comma-delimited list of four CIDR blocks. The first half is Public and the second half is Private。" (default valuEnter a value for parameter 'SubnetCidrIpv4' "Comma-delimited list of four CIDR blocks. The first half is Public and the second half is Private。" (default value: 10.0.0.0/24, 10.0.1.0/24, 10.0.2.0/24, 10.0.3.0/24):
Enter a value for parameter 'AvailabilityZoneSubnet1' (default value: ap-northeaEnter a value for parameter 'AvailabilityZoneSubnet1' (default value: ap-northeaEnter a value for parameter 'AvailabilityZoneSubnet1' (default value: ap-northeaEnter a value for parameter 'AvailabilityZoneSubnet1' (default value: ap-northeast-1a):
Enter a value for parameter 'AvailabilityZoneSubnet2' (default value: ap-northeaEnter a value for parameter 'AvailabilityZoneSubnet2' (default value: ap-northeaEnter a value for parameter 'AvailabilityZoneSubnet2' (default value: ap-northeast-1c):
Enter a value for parameter 'VPCCidrIpv4' (default value: 10.0.0.0/16):
CloudFormation will make the following changes:
Stack NetworkStack:
+ AWS::EC2::InternetGateway MyInternetGateway
+ AWS::EC2::VPCGatewayAttachment MyVPCGatewayAttachment
+ AWS::EC2::VPC MyVPC
+ AWS::EC2::RouteTable PrivateRouteTable
+ AWS::EC2::SubnetRouteTableAssociation PrivateSubnet1RouteTableAssociation
+ AWS::EC2::Subnet PrivateSubnet1
+ AWS::EC2::SubnetRouteTableAssociation PrivateSubnet2RouteTableAssociation
+ AWS::EC2::Subnet PrivateSubnet2
+ AWS::EC2::RouteTable PublicRouteTable
+ AWS::EC2::Route PublicRoute
+ AWS::EC2::SubnetRouteTableAssociation PublicSubnet1RouteTableAssociation
+ AWS::EC2::Subnet PublicSubnet1
+ AWS::EC2::SubnetRouteTableAssociation PublicSubnet2RouteTableAssociation
+ AWS::EC2::Subnet PublicSubnet2
Do you wish to continue? (Y/n)
Deploying template 'Network.yaml' as stack 'NetworkStack' in ap-northeast-1.
Stack NetworkStack: ROLLBACK_COMPLETE
Messages:
- MyVPCGatewayAttachment: Encountered unsupported property VPCId
- PrivateRouteTable: Encountered unsupported property VPCId
- PrivateSubnet1: Encountered unsupported property VPCId
- PrivateSubnet2: Encountered unsupported property VPCId
- PublicRouteTable: Encountered unsupported property VPCId
- PublicSubnet1: Encountered unsupported property VPCId
- PublicSubnet2: Encountered unsupported property VPCId
failed deploying stack 'NetworkStack'
以下は失敗したStackを自動的に削除した後、デプロイが成功している状態です。
$ rain deploy --profile $PROFILE Network.yaml NetworkStack
Deleted existing, empty stack.
省略
Deploying template 'Network.yaml' as stack 'NetworkStack' in ap-northeast-1.
Stack NetworkStack: CREATE_COMPLETE
Outputs:
PrivateSubnet2Subnet1Id: subnet-0368fc284b9639f4c # exported as NetworkStack-PrivateSubnet2Id
MyVPCId: vpc-056ab2c7c9dc91a8f # exported as NetworkStack-VPCId
PublicSubnet1Id: subnet-08d4895141b51b8be # exported as NetworkStack-PublicSubnet1Id
PublicSubnet2Id: subnet-08aa1bbb0a9d3a82f # exported as NetworkStack-PublicSubnet2Id
PrivateSubnet1Subnet1Id: subnet-07581ce346dfe2ebb # exported as NetworkStack-PrivateSubnet1Id
Successfully deployed NetworkStack
コンソールを確認すると、リソースは無事に作成できていました。
EC2インスタンステンプレート作成
以下のテンプレートを作成し、Rainでデプロイしました。
インスタンスの設定
Parameters:
ImageId:
Type: AWS::EC2::Image::Id
Default: ami-0992fc94ca0f1415a
InstanceType:
Type: String
Default: t2.micro
KeyName:
Type: AWS::EC2::KeyPair::KeyName
PrefixNameTagValue:
Type: String
Default: CloudTech
NetworkStackName:
Type: String
Default: NetworkStack
Resources:
MyInstance:
Type: AWS::EC2::Instance
Properties:
ImageId: !Ref ImageId # Optional
InstanceType: !Ref InstanceType # Optional
KeyName: !Ref KeyName # Optional
NetworkInterfaces:
- AssociatePublicIpAddress: true
DeleteOnTermination: true
DeviceIndex: 0
GroupSet:
- !Ref MySecurityGroup
SubnetId:
Fn::ImportValue: !Sub ${NetworkStackName}-PublicSubnet1Id
UserData:
Fn::Base64: |
#!/bin/bash
yum -y update
amazon-linux-extras install php7.2 -y
yum -y install mysql httpd php-mbstring php-xml gd php-gd
systemctl enable httpd.service
systemctl start httpd.service
wget -P /home/ec2-user http://ja.wordpress.org/latest-ja.tar.gz
cd /home/ec2-user
tar zxvf latest-ja.tar.gz
cp -r wordpress/* /var/www/html/
chown apache:apache -R /var/www/html
Tags:
- Key: Name
Value: !Join
- "-"
- - !Ref PrefixNameTagValue
- Web-Server
ImageId
,InstanceType
,KeyName
はカスタムできるようにパラメータで渡しています。
ボリュームは設定しなければデフォルトのものがアタッチされるようです。
NetworkInterfaces
プロパティでセキュリティグループやサブネットを指定します。
Fn::ImportValue
で他のテンプレートでExport
している値を参照しています(クロススタック参照)。
セキュリティグループの設定
Parameters:
SSHLocation:
Type: String
Default: 0.0.0.0/32
Resources:
MySecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: ssh-myip-http-full
GroupName: ssh-myip-http-full # Optional
SecurityGroupIngress:
- CidrIp: !Ref SSHLocation # Optional
FromPort: 22 # Optional
IpProtocol: tcp
ToPort: 22 # Optional
- CidrIp: 0.0.0.0/0 # Optional
FromPort: 80 # Optional
IpProtocol: tcp
ToPort: 80 # Optional
- CidrIp: 0.0.0.0/0 # Optional
FromPort: 443 # Optional
IpProtocol: tcp
ToPort: 443 # Optional
Tags:
- Key: Name
Value: !Join
- "-"
- - !Ref PrefixNameTagValue
- Web-Server
VpcId:
Fn::ImportValue: !Sub ${NetworkStackName}-VPCId # Optional
Outputs:
MySecurityGroup:
Value: !Ref MySecurityGroup
Export:
Name: !Sub ${AWS::StackName}-AllowWebServer
WebServer用のセキュリティグループを作成しています。
sshは自分のIPアドレスのみをパラメータで渡し、http,httpsはフルオープンです。
WordPress画面の確認
インスタンスのパブリックIPアドレスを確認すると、以下のように表示されたのでWordPressのインストールは成功です。
次はRDSのテンプレートを作成します。
RDSのテンプレート作成
以下のテンプレートをRainでデプロイしました。
AWSTemplateFormatVersion: "2010-09-09"
Description: Template generated by rain
Parameters:
DBInstanceClass:
Type: String
Default: db.t2.micro
DBName:
Type: String
Default: wordpress
DBUser:
Type: String
NoEcho: true
MinLength: 1
MaxLength: 16
AllowedPattern: "[a-zA-Z][a-zA-Z0-9]*"
ConstraintDescription: must begin with a letter and contain only alphanumeric characters.
DBPassword:
Type: String
NoEcho: true
MinLength: 8
MaxLength: 41
AllowedPattern: "[a-zA-Z0-9]*"
ConstraintDescription: must contain only alphanumeric characters.
AvailabilityZone:
Type: AWS::EC2::AvailabilityZone::Name
Default: ap-northeast-1a
NetworkStackName:
Type: String
Default: NetworkStack
InstanceStackName:
Type: String
Default: InstanceStack
PrefixNameTagValue:
Type: String
Default: CloudTech
Resources:
MyDBInstance:
Type: AWS::RDS::DBInstance
Properties:
AllocatedStorage: 20
AvailabilityZone: !Ref AvailabilityZone # Optional
BackupRetentionPeriod: 0 # Optional
DBInstanceClass: !Ref DBInstanceClass
DBName: !Ref DBName # Optional
DBSubnetGroupName: !Ref MyDBSubnetGroup # Optional
Engine: mysql # Optional
MasterUserPassword: !Ref DBPassword # Optional
MasterUsername: !Ref DBUser # Optional
PubliclyAccessible: false # Optional
Tags:
- Key: Name
Value: !Join
- "-"
- - !Ref PrefixNameTagValue
- mysql
VPCSecurityGroups:
- !Ref MySecurityGroup
MyDBSubnetGroup:
Type: AWS::RDS::DBSubnetGroup
Properties:
DBSubnetGroupDescription: !Sub ${AWS::StackName}-SubnetGroup
SubnetIds:
- Fn::ImportValue: !Sub ${NetworkStackName}-PrivateSubnet1Id
- Fn::ImportValue: !Sub ${NetworkStackName}-PrivateSubnet2Id
Tags:
- Key: Name
Value: !Join
- "-"
- - !Ref PrefixNameTagValue
- SubnetGroup
MySecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: db-SG
GroupName: db-SG # Optional
SecurityGroupIngress:
- SourceSecurityGroupId:
Fn::ImportValue: !Sub ${InstanceStackName}-AllowWebServer # Optional
FromPort: 3306 # Optional
IpProtocol: tcp
ToPort: 3306 # Optional
Tags:
- Key: Name
Value: !Join
- "-"
- - !Ref PrefixNameTagValue
- mysql
VpcId:
Fn::ImportValue: !Sub ${NetworkStackName}-VPCId # Optional
Outputs:
MyDBInstanceEndpointAddress:
Value: !GetAtt MyDBInstance.Endpoint.Address
MyDBInstanceEndpointPort:
Value: !GetAtt MyDBInstance.Endpoint.Port
MySecurityGroupGroupId:
Value: !GetAtt MySecurityGroup.GroupId
MySecurityGroupVpcId:
Value: !GetAtt MySecurityGroup.VpcId
RDSはプロパティが多いので、業務でテンプレート化すると大変そうです。
パラメータのNoEcho
は値をマスクしてコンソール、CLI、APIに表示させないようにできます。
もっとセキュアにするにはSSMのパラメータストアやSecret Managerを使うとよいでしょう。
仕上げにWordPressの画面からインストールを完了させて、ログインをします。
成功しました。
rain rm | Stackの削除
テンプレート化すると設定項目が多くて大変ですね。
これでWordPress環境構築が終了したので、Stackを削除して終了します。
$ rain rm InstanceStack --profile $PROFILE
Stack InstanceStack: CREATE_COMPLETE
Are you sure you want to delete this stack? (Y/n)
Successfully deleted stack 'InstanceStack'
他のStackも同様に削除できたら、後片付け完了です。
最後に、使用していないRainの各コマンドを試して終わりにします。
その他のrainコマンド
rain ls | 実行中Stackを表示
$ rain ls --profile $PROFILE
CloudFormation stacks in ap-northeast-1:
ConfigS3: UPDATE_COMPLETE
EnableConfig: UPDATE_COMPLETE
EnableGuardDuty: CREATE_COMPLETE
StackSet-EnableAccessAnalyzer-828997b8-17d8-47a5-a734-52e2ecce44f3: CREATE_COMPLETE
$ rain ls ConfigS3 --profile $PROFILE
Stack ConfigS3: UPDATE_COMPLETE
Outputs:
ConfigBucketOutput: enableconfig-configbucket-xxx # S3 (exported as ConfigS3-S3BucketName)
$ rain ls --all EnableConfig --profile $PROFILE
Stack EnableConfig: UPDATE_COMPLETE
Parameters:
IncludeGlobalResourceTypes: true
ResourceTypes: <All>
DeliveryChannelName: <Generated>
S3StackName: ConfigS3
Frequency: 24hours
AllSupported: true
Resources:
ConfigDeliveryChannel: CREATE_COMPLETE
EnableConfig-ConfigDeliveryChannel-xxxx
ConfigRecorder: CREATE_COMPLETE
EnableConfig-ConfigRecorder-xxxx
ConfigRecorderRole: CREATE_COMPLETE
EnableConfig-ConfigRecorderRole-xxxx
$ rain ls --all --profile $PROFILE
CloudFormation stacks in ap-northeast-1:
ConfigS3: UPDATE_COMPLETE
EnableConfig: UPDATE_COMPLETE
EnableGuardDuty: CREATE_COMPLETE
StackSet-EnableAccessAnalyzer-828997b8-17d8-47a5-a734-52e2ecce44f3: CREATE_COMPLETE
CloudFormation stacks in ap-northeast-2:
StackSet-EnableAccessAnalyzer-85e9246d-a979-4035-a5be-e15a43df73da: CREATE_COMPLETE
CloudFormation stacks in ap-south-1:
StackSet-EnableAccessAnalyzer-9b3bd2af-4ffd-43b6-978a-6de54760bfdd: CREATE_COMPLETE
CloudFormation stacks in ap-southeast-1:
StackSet-EnableAccessAnalyzer-423b7c20-a875-4142-a2a1-9dafda0a1129: CREATE_COMPLETE
CloudFormation stacks in ap-southeast-2:
StackSet-EnableAccessAnalyzer-745381f2-4287-4d16-a648-2fbd8cc82815: CREATE_COMPLETE
CloudFormation stacks in ca-central-1:
StackSet-EnableAccessAnalyzer-64740f3b-eb80-4d16-b680-3a047fa19a4e: CREATE_COMPLETE
CloudFormation stacks in eu-central-1:
StackSet-EnableAccessAnalyzer-7598a6b5-0ade-4b44-949f-6c21e1c7431b: CREATE_COMPLETE
CloudFormation stacks in eu-north-1:
StackSet-EnableAccessAnalyzer-0dbf73f3-058f-4d9e-9e9e-414ceab6658e: CREATE_COMPLETE
CloudFormation stacks in eu-west-1:
StackSet-EnableAccessAnalyzer-fa6692d2-8c2b-4316-a0bb-6713f8a0f18a: CREATE_COMPLETE
CloudFormation stacks in eu-west-2:
StackSet-EnableAccessAnalyzer-d354463c-30ef-4640-94b2-2918c50b4ff3: CREATE_COMPLETE
CloudFormation stacks in eu-west-3:
StackSet-EnableAccessAnalyzer-4cac3e6d-fe04-4431-bf76-91a9e7df1cee: CREATE_COMPLETE
CloudFormation stacks in sa-east-1:
StackSet-EnableAccessAnalyzer-7e5f58c7-e7bd-4621-b49d-36219c15e68b: CREATE_COMPLETE
CloudFormation stacks in us-east-1:
StackSet-EnableAccessAnalyzer-22576926-73ca-4132-a5a5-001bc20dfde6: CREATE_COMPLETE
CloudFormation stacks in us-east-2:
StackSet-EnableAccessAnalyzer-f4a61f4b-8a41-4976-ba4d-7f506286a5b8: CREATE_COMPLETE
CloudFormation stacks in us-west-1:
StackSet-EnableAccessAnalyzer-78b1e93f-e88f-4ada-bc4e-a0a0c71711cc: CREATE_COMPLETE
CloudFormation stacks in us-west-2:
StackSet-EnableAccessAnalyzer-7179d02f-ce1b-4539-878c-b657381e8a3d: CREATE_COMPLETE
rain cat | 実行中Stackからテンプレート取得
$ rain cat StackSet-EnableAccessAnalyzer-828997b8-17d8-47a5-a734-52e2ecce44f3 --profile $PROFILE
AWSTemplateFormatVersion: "2010-09-09"
Description: EnableAccessAnalyzer
Parameters:
AccountID:
Description: Account ID to be archived
Type: String
MaxLength: 12
MinLength: 12
Resources:
AccessAnalyzer:
Type: AWS::AccessAnalyzer::Analyzer
Properties:
Type: ACCOUNT
ArchiveRules:
- Filter:
- Property: principal.AWS
Eq:
- !Ref AccountID
- Property: isPublic
Eq:
- false
RuleName: ArchiveOfTrustedID
Outputs:
AccessAnalyzerOutput:
rain console | コンソールにログイン
$ rain console ConfigS3 --profile $PROFILE
sign-in URLs can only be constructed for assumed roles
rain diff | テンプレートの比較
Network.yaml
をコピーしたBackUp-Network.yaml
にリソースを一つ追加してみました。
このように違いが表示されます。
$ rain diff Network.yaml BackUp-Network.yaml
(|) Resources:
(+) rivateSubnet2RouteTableAssociation:
(+) Properties:
(+) RouteTableId:
(+) Ref: PrivateRouteTable
(+) SubnetId:
(+) Ref: PrivateSubnet2
(+) Type: AWS::EC2::SubnetRouteTableAssociation
rain info | 現在の設定を表示
$ rain info --profile $PROFILE
Account: xxxxx
Region: xxxxx
Identity: arn:aws:iam::xxxxxxx:user/xxxxx
Profile: xxxxx
rain logs | Stackのイベントログを表示
デフォルトではStackの有用なメッセージを含むログを表示します。
$ rain logs ConfigS3 --profile $PROFILE
Jan 23 12:34:32 ConfigS3/ConfigBucket (AWS::S3::Bucket) UPDATE_IN_PROGRESS "Apply stack-level tags to imported resource if applicable."
Jan 23 12:34:31 ConfigS3/ConfigBucket (AWS::S3::Bucket) IMPORT_COMPLETE "Resource import completed."
Jan 23 12:34:30 ConfigS3/ConfigBucket (AWS::S3::Bucket) IMPORT_IN_PROGRESS "Resource import started."
$ rain logs EnableConfig --profile $PROFILE
No interesting log messages to display. To see everything, use the --all flag
$ rain logs --all EnableConfig --profile $PROFILE
Jan 23 14:38:12 EnableConfig/EnableConfig (AWS::CloudFormation::Stack) UPDATE_COMPLETE
Jan 23 14:38:12 EnableConfig/ConfigBucketPolicy (AWS::S3::BucketPolicy) DELETE_SKIPPED
Jan 23 14:38:10 EnableConfig/EnableConfig (AWS::CloudFormation::Stack) UPDATE_COMPLETE_CLEANUP_IN_PROGRESS
Jan 23 14:38:03 EnableConfig/EnableConfig (AWS::CloudFormation::Stack) UPDATE_IN_PROGRESS "User Initiated"
Jan 23 14:31:41 EnableConfig/EnableConfig (AWS::CloudFormation::Stack) UPDATE_COMPLETE
Jan 23 14:31:40 EnableConfig/EnableConfig (AWS::CloudFormation::Stack) UPDATE_COMPLETE_CLEANUP_IN_PROGRESS
Jan 23 14:31:37 EnableConfig/ConfigBucketPolicy (AWS::S3::BucketPolicy) UPDATE_COMPLETE
Jan 23 14:31:32 EnableConfig/EnableConfig (AWS::CloudFormation::Stack) UPDATE_IN_PROGRESS "User Initiated"
Jan 23 13:32:50 EnableConfig/EnableConfig (AWS::CloudFormation::Stack) CREATE_COMPLETE
Jan 23 13:32:49 EnableConfig/ConfigRecorder (AWS::Config::ConfigurationRecorder) CREATE_COMPLETE
Jan 23 13:32:43 EnableConfig/ConfigDeliveryChannel (AWS::Config::DeliveryChannel) CREATE_COMPLETE
Jan 23 13:32:42 EnableConfig/ConfigDeliveryChannel (AWS::Config::DeliveryChannel) CREATE_IN_PROGRESS "Resource creation Initiated"
Jan 23 13:32:34 EnableConfig/ConfigRecorder (AWS::Config::ConfigurationRecorder) CREATE_IN_PROGRESS "Resource creation Initiated"
Jan 23 13:32:34 EnableConfig/ConfigRecorder (AWS::Config::ConfigurationRecorder) CREATE_IN_PROGRESS
Jan 23 13:32:31 EnableConfig/ConfigRecorderRole (AWS::IAM::Role) CREATE_COMPLETE
Jan 23 13:32:16 EnableConfig/ConfigDeliveryChannel (AWS::Config::DeliveryChannel) CREATE_IN_PROGRESS
Jan 23 13:32:14 EnableConfig/ConfigBucketPolicy (AWS::S3::BucketPolicy) CREATE_COMPLETE
Jan 23 13:32:14 EnableConfig/ConfigBucketPolicy (AWS::S3::BucketPolicy) CREATE_IN_PROGRESS "Resource creation Initiated"
Jan 23 13:32:13 EnableConfig/ConfigRecorderRole (AWS::IAM::Role) CREATE_IN_PROGRESS "Resource creation Initiated"
Jan 23 13:32:12 EnableConfig/ConfigRecorderRole (AWS::IAM::Role) CREATE_IN_PROGRESS
Jan 23 13:32:12 EnableConfig/ConfigBucketPolicy (AWS::S3::BucketPolicy) CREATE_IN_PROGRESS
Jan 23 13:32:08 EnableConfig/EnableConfig (AWS::CloudFormation::Stack) CREATE_IN_PROGRESS "User Initiated"
rain merge | テンプレートのマージ
指定したテンプレート同士がセクションごとにまとめられて標準出力に出ます。
rain tree | テンプレート内の依存関係表示
依存関係が分かります。
$ rain tree RDS-Instance.yaml
Resources:
MyDBSubnetGroup:
DependsOn:
Parameters:
- AWS::StackName
- NetworkStackName
- PrefixNameTagValue
MySecurityGroup:
DependsOn:
Parameters:
- InstanceStackName
- NetworkStackName
- PrefixNameTagValue
MyDBInstance:
DependsOn:
Parameters:
- AvailabilityZone
- DBInstanceClass
- DBName
- DBPassword
- DBUser
- PrefixNameTagValue
Resources:
- MyDBSubnetGroup
- MySecurityGroup
Outputs:
MySecurityGroupGroupId:
DependsOn:
Resources:
- MySecurityGroup
MySecurityGroupVpcId:
DependsOn:
Resources:
- MySecurityGroup
MyDBInstanceEndpointAddress:
DependsOn:
Resources:
- MyDBInstance
MyDBInstanceEndpointPort:
DependsOn:
Resources:
- MyDBInstance
rain watch | Stackの更新状態を監視
Stackのステータスを繰り返し表示します。
外部から開始された進行状況を監視に役立ちます。
$ rain watch ConfigS3 --profile $PROFILE
Fetching stack status .˙Stack ConfigS3: UPDATE_COMPLETE
not watching unchanging stack
さいごに
今回初めてCloudFormationのツールを使用しました。
Rain以外にも色々とあるので、他のツールも試してみたいです。
CloudFormation化は後の設定変更などを考えなければ簡単に行えますが、業務で使うとなると色々と考えることが多くて大変そうです。
この記事は主に私の勉強のために執筆していますが、他の誰かのお役に立てれば幸いです。
テンプレート
ネットワーク
Network.yaml
AWSTemplateFormatVersion: "2010-09-09"
Description: Template generated by rain
Metadata:
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: VPC Configuration
Parameters:
- VPCCidrIpv4
- InstanceTenancy
- Label:
default: Subnet Configuration
Parameters:
- SubnetCidrIpv4
- AvailabilityZoneSubnet1
- AvailabilityZoneSubnet2
- Label:
default: Tag
Parameters:
- PrefixNameTagValue
Parameters:
VPCCidrIpv4:
Type: String
Default: 10.0.0.0/16
ConstraintDescription: Malformed input-Parameter VPCCidrIpv4 must match pattern (x.x.x.x/16-28)
AllowedPattern: ^(([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])/1[6-9]|2[0-8]$
InstanceTenancy:
Type: String
Default: default
AllowedValues:
- default
- dedicated
- host
SubnetCidrIpv4:
Type: CommaDelimitedList
Default: 10.0.0.0/24, 10.0.1.0/24, 10.0.2.0/24, 10.0.3.0/24
Description: Comma-delimited list of four CIDR blocks. The first half is Public and the second half is Private.
AvailabilityZoneSubnet1:
Type: AWS::EC2::AvailabilityZone::Name
Default: ap-northeast-1a
AvailabilityZoneSubnet2:
Type: AWS::EC2::AvailabilityZone::Name
Default: ap-northeast-1c
PrefixNameTagValue:
Type: String
Default: CloudTech
Resources:
# VPC
MyVPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VPCCidrIpv4
EnableDnsHostnames: true # Optional
EnableDnsSupport: true # Optional
InstanceTenancy: !Ref InstanceTenancy # Optional
Tags:
- Key: Name
Value: !Join
- "-"
- - !Ref PrefixNameTagValue
- VPC
# InternetGateway
MyInternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: !Join
- "-"
- - !Ref PrefixNameTagValue
- InternetGateway
MyVPCGatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
InternetGatewayId: !Ref MyInternetGateway # Optional
VpcId: !Ref MyVPC
# Subnet
PublicSubnet1:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: !Ref AvailabilityZoneSubnet1 # Optional
CidrBlock: !Select
- 0
- !Ref SubnetCidrIpv4
MapPublicIpOnLaunch: true # Optional
Tags:
- Key: Name
Value: !Join
- "-"
- - !Ref PrefixNameTagValue
- PublicSubnet1
VpcId: !Ref MyVPC
PublicSubnet2:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: !Ref AvailabilityZoneSubnet2 # Optional
CidrBlock: !Select
- 1
- !Ref SubnetCidrIpv4
MapPublicIpOnLaunch: true # Optional
Tags:
- Key: Name
Value: !Join
- "-"
- - !Ref PrefixNameTagValue
- PublicSubnet2
VpcId: !Ref MyVPC
PrivateSubnet1:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: !Ref AvailabilityZoneSubnet1 # Optional
CidrBlock: !Select
- 2
- !Ref SubnetCidrIpv4
MapPublicIpOnLaunch: false # Optional
Tags:
- Key: Name
Value: !Join
- "-"
- - !Ref PrefixNameTagValue
- PraivateSubnet1
VpcId: !Ref MyVPC
PrivateSubnet2:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: !Ref AvailabilityZoneSubnet2 # Optional
CidrBlock: !Select
- 3
- !Ref SubnetCidrIpv4
MapPublicIpOnLaunch: false # Optional
Tags:
- Key: Name
Value: !Join
- "-"
- - !Ref PrefixNameTagValue
- PraivateSubnet2
VpcId: !Ref MyVPC
# Route
PublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
Tags:
- Key: Name
Value: !Join
- "-"
- - !Ref PrefixNameTagValue
- Public-Route-Table
VpcId: !Ref MyVPC
PublicRoute:
Type: AWS::EC2::Route
Properties:
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref MyInternetGateway # Optional
RouteTableId: !Ref PublicRouteTable
PublicSubnet1RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PublicRouteTable
SubnetId: !Ref PublicSubnet1
PublicSubnet2RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PublicRouteTable
SubnetId: !Ref PublicSubnet2
PrivateRouteTable:
Type: AWS::EC2::RouteTable
Properties:
Tags:
- Key: Name
Value: !Join
- "-"
- - !Ref PrefixNameTagValue
- Praivate-Route-Table
VpcId: !Ref MyVPC
PrivateSubnet1RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PrivateRouteTable
SubnetId: !Ref PrivateSubnet1
PrivateSubnet2RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PrivateRouteTable
SubnetId: !Ref PrivateSubnet2
Outputs:
MyVPCId:
Value: !Ref MyVPC
Export:
Name: !Sub ${AWS::StackName}-VPCId
PublicSubnet1Id:
Value: !Ref PublicSubnet1
Export:
Name: !Sub ${AWS::StackName}-PublicSubnet1Id
PublicSubnet2Id:
Value: !Ref PublicSubnet2
Export:
Name: !Sub ${AWS::StackName}-PublicSubnet2Id
PrivateSubnet1Subnet1Id:
Value: !Ref PrivateSubnet1
Export:
Name: !Sub ${AWS::StackName}-PrivateSubnet1Id
PrivateSubnet2Subnet1Id:
Value: !Ref PrivateSubnet2
Export:
Name: !Sub ${AWS::StackName}-PrivateSubnet2Id
EC2インスタンス
Instance.yaml
AWSTemplateFormatVersion: "2010-09-09"
Description: Template generated by rain
Parameters:
ImageId:
Type: AWS::EC2::Image::Id
Default: ami-0992fc94ca0f1415a
InstanceType:
Type: String
Default: t2.micro
KeyName:
Type: AWS::EC2::KeyPair::KeyName
SSHLocation:
Type: String
Default: 0.0.0.0/32
PrefixNameTagValue:
Type: String
Default: CloudTech
NetworkStackName:
Type: String
Default: NetworkStack
Resources:
MyInstance:
Type: AWS::EC2::Instance
Properties:
ImageId: !Ref ImageId # Optional
InstanceType: !Ref InstanceType # Optional
KeyName: !Ref KeyName # Optional
NetworkInterfaces:
- AssociatePublicIpAddress: true
DeleteOnTermination: true
DeviceIndex: 0
GroupSet:
- !Ref MySecurityGroup
SubnetId:
Fn::ImportValue: !Sub ${NetworkStackName}-PublicSubnet1Id
UserData:
Fn::Base64: |
#!/bin/bash
yum -y update
amazon-linux-extras install php7.2 -y
yum -y install mysql httpd php-mbstring php-xml gd php-gd
systemctl enable httpd.service
systemctl start httpd.service
wget -P /home/ec2-user http://ja.wordpress.org/latest-ja.tar.gz
cd /home/ec2-user
tar zxvf latest-ja.tar.gz
cp -r wordpress/* /var/www/html/
chown apache:apache -R /var/www/html
Tags:
- Key: Name
Value: !Join
- "-"
- - !Ref PrefixNameTagValue
- Web-Server
MySecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: ssh-myip-http-full
GroupName: ssh-myip-http-full # Optional
SecurityGroupIngress:
- CidrIp: !Ref SSHLocation # Optional
FromPort: 22 # Optional
IpProtocol: tcp
ToPort: 22 # Optional
- CidrIp: 0.0.0.0/0 # Optional
FromPort: 80 # Optional
IpProtocol: tcp
ToPort: 80 # Optional
- CidrIp: 0.0.0.0/0 # Optional
FromPort: 443 # Optional
IpProtocol: tcp
ToPort: 443 # Optional
Tags:
- Key: Name
Value: !Join
- "-"
- - !Ref PrefixNameTagValue
- Web-Server
VpcId:
Fn::ImportValue: !Sub ${NetworkStackName}-VPCId # Optional
Outputs:
MySecurityGroup:
Value: !Ref MySecurityGroup
Export:
Name: !Sub ${AWS::StackName}-AllowWebServer
RDS
RDS.yaml
AWSTemplateFormatVersion: "2010-09-09"
Description: Template generated by rain
Parameters:
DBInstanceClass:
Type: String
Default: db.t2.micro
DBName:
Type: String
Default: wordpress
DBUser:
Type: String
NoEcho: true
MinLength: 1
MaxLength: 16
AllowedPattern: "[a-zA-Z][a-zA-Z0-9]*"
ConstraintDescription: must begin with a letter and contain only alphanumeric characters.
DBPassword:
Type: String
NoEcho: true
MinLength: 8
MaxLength: 41
AllowedPattern: "[a-zA-Z0-9]*"
ConstraintDescription: must contain only alphanumeric characters.
AvailabilityZone:
Type: AWS::EC2::AvailabilityZone::Name
Default: ap-northeast-1a
NetworkStackName:
Type: String
Default: NetworkStack
InstanceStackName:
Type: String
Default: InstanceStack
PrefixNameTagValue:
Type: String
Default: CloudTech
Resources:
MyDBInstance:
Type: AWS::RDS::DBInstance
Properties:
AllocatedStorage: 20
AvailabilityZone: !Ref AvailabilityZone # Optional
BackupRetentionPeriod: 0 # Optional
DBInstanceClass: !Ref DBInstanceClass
DBName: !Ref DBName # Optional
DBSubnetGroupName: !Ref MyDBSubnetGroup # Optional
Engine: mysql # Optional
MasterUserPassword: !Ref DBPassword # Optional
MasterUsername: !Ref DBUser # Optional
PubliclyAccessible: false # Optional
Tags:
- Key: Name
Value: !Join
- "-"
- - !Ref PrefixNameTagValue
- mysql
VPCSecurityGroups:
- !Ref MySecurityGroup
MyDBSubnetGroup:
Type: AWS::RDS::DBSubnetGroup
Properties:
DBSubnetGroupDescription: !Sub ${AWS::StackName}-SubnetGroup
SubnetIds:
- Fn::ImportValue: !Sub ${NetworkStackName}-PrivateSubnet1Id
- Fn::ImportValue: !Sub ${NetworkStackName}-PrivateSubnet2Id
Tags:
- Key: Name
Value: !Join
- "-"
- - !Ref PrefixNameTagValue
- SubnetGroup
MySecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: db-SG
GroupName: db-SG # Optional
SecurityGroupIngress:
- SourceSecurityGroupId:
Fn::ImportValue: !Sub ${InstanceStackName}-AllowWebServer # Optional
FromPort: 3306 # Optional
IpProtocol: tcp
ToPort: 3306 # Optional
Tags:
- Key: Name
Value: !Join
- "-"
- - !Ref PrefixNameTagValue
- mysql
VpcId:
Fn::ImportValue: !Sub ${NetworkStackName}-VPCId # Optional
Outputs:
MyDBInstanceEndpointAddress:
Value: !GetAtt MyDBInstance.Endpoint.Address
MyDBInstanceEndpointPort:
Value: !GetAtt MyDBInstance.Endpoint.Port
MySecurityGroupGroupId:
Value: !GetAtt MySecurityGroup.GroupId
MySecurityGroupVpcId:
Value: !GetAtt MySecurityGroup.VpcId
Discussion