#1. はじめに
最近はインフラ構築もコードで行われるようになりました。
その一例がAWSの提供するリソースプロビジョニングサービス「CloudFormation(以下、CFnと表す)」です。
今回はCFnを使用して、一般的な2階層Webサービスを構築しようと思います。
また、CFnに関する記事では、マネコン上でビルドする記事が多いですが、CFnの本質はIaC、つまりはコードでのインフラ構築ですので、本記事ではテンプレートのビルドはIDE上(Cloud9)でAWS CLIを使用して行うものとします。
記事は以下3編に分けて公開します。
①【AWS】CloudFormationでWebサービスを構築①(NW編)←本記事
②【AWS】CloudFormationでWebサービスを構築②(EC2編)
③【AWS】CloudFormationでWebサービスを構築③(RDS編)
#2. 概要
本記事の概要を以下に記載します。
##2.1 本記事の目的
CFnを利用し、IDE上(Cloud9)からWebサーバ環境を構築する。
##2.2 本記事の流れ
① NW環境、及びセキュリティテンプレートの作成 ⇒ ビルド
② サーバテンプレートの作成 ⇒ ビルド
③ データベーステンプレートの作成 ⇒ ビルド
④ 動作確認
##2.3 機能要件
・テンプレートの形式は『yaml』を採用する
・テンプレートファイルは各ロール毎に分割し、クロススタック方式を採用する
・作成するテンプレートを以下の通りとする
・「network.yml」
・「security.yml」
・「server.yml」
・「database.yml」
・リソース作成からビルドまでを全てコマンドライン上で行う
・IDEはCloud9を使用する ※皆さんはVSCode等のお好きなIDEを使用して下さい
・完了要件を以下2点とする
・Webサーバのテストページの閲覧
・RDSで作成したDBレコードのブラウザ閲覧
#3. 事前準備
事前準備として、以下の準備をお願いします。
・IDE(本記事ではCloud9を使用します)
・AWS CLIが使用可能であること
・独自ドメインを取得していること ※投稿主は「お名前.com」にてドメインを取得しました
また、テンプレートファイルの保管、及びビルド用のディレクトリ(以下、「作業用ディレクトリ」を表す)を任意の場所に作成してください。
ディレクトリの作成コマンドは以下の通りとなります。
$ mkdir cfn-dev-dir
$ cd cfn-dev-dir
以降、作成するテンプレートは全てこの作業用ディレクトリの直下に保存して下さい。
#4. NW編の概要
今回の『【AWS】CloudFormationでWebサーバを構築①(NW編)』では、Web環境周りのNW部分のテンプレートを作成します。
具体的なサービスとしては以下の通りとなります。
##4.1 「network.yml」で登場するサービス
・Amazon VPC
・Internet Gateway
・VPC Subnet
・VPC RouteTable
##4.2 「security.yml」で登場するサービス
・SecurityGroup
##4.3 NW編構成図
NW編で作成するテンプレート環境の構成図を下図の通りとします。
#5. NWテンプレートの作成
早速ですが、以下がNW部分のテンプレートになります。
命名規則等、必要であればご自身の環境に合わせて修正してください。
修正が完了したら、作業用ディレクトリに「network.yml」というファイル名で保存してください。
AWSTemplateFormatVersion: "2010-09-09"
Description: Web2tier-Network-Template
# ------------------------------------------------------------
# Input Parameters
# ------------------------------------------------------------
Parameters:
### Project Prefix ###
PJPrefix:
Type: String
### VPC ###
VPCCIDR:
Type: String
Default: "192.168.0.0/20"
### Public Subnet ###
PublicSubnetACIDR:
Type: String
Default: "192.168.1.0/24"
PublicSubnetCCIDR:
Type: String
Default: "192.168.2.0/24"
### Private Subnet ###
PrivateSubnetACIDR:
Type: String
Default: "192.168.3.0/24"
PrivateSubnetCCIDR:
Type: String
Default: "192.168.4.0/24"
### Resources ###
Resources:
# ------------------------------------------------------------
# VPC
# ------------------------------------------------------------
VPC:
Type: "AWS::EC2::VPC"
Properties:
CidrBlock: !Ref VPCCIDR
EnableDnsSupport: "true"
EnableDnsHostnames: "true"
InstanceTenancy: default
Tags:
- Key: Name
Value: !Sub "${PJPrefix}-vpc"
# ------------------------------------------------------------
# InternetGateway:
# ------------------------------------------------------------
InternetGateway:
Type: "AWS::EC2::InternetGateway"
Properties:
Tags:
- Key: Name
Value: !Sub "${PJPrefix}-igw"
IGWAttachment:
Type: "AWS::EC2::VPCGatewayAttachment"
Properties:
InternetGatewayId: !Ref InternetGateway
VpcId: !Ref VPC
# ------------------------------------------------------------
# NatGateway
# ------------------------------------------------------------
### NAT Gateway ###
NatGateway:
Type: AWS::EC2::NatGateway
Properties:
AllocationId:
Fn::GetAtt:
- NatGatewayEIP
- AllocationId
SubnetId: !Ref PublicSubnetA
Tags:
- Key: Name
Value: !Sub "${PJPrefix}-NAT-Gateway"
### NAT Gateway EIP ###
NatGatewayEIP:
Type: AWS::EC2::EIP
Properties:
Domain: vpc
Tags:
- Key: Name
Value: !Sub "${PJPrefix}-NGW-EIP"
# ------------------------------------------------------------
# Subnet
# ------------------------------------------------------------
### Public Subnet ###
PublicSubnetA:
Type: "AWS::EC2::Subnet"
Properties:
AvailabilityZone: "ap-northeast-1a"
CidrBlock: !Ref PublicSubnetACIDR
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub "${PJPrefix}-public-subnet-a"
PublicSubnetC:
Type: "AWS::EC2::Subnet"
Properties:
AvailabilityZone: "ap-northeast-1c"
CidrBlock: !Ref PublicSubnetCCIDR
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub "${PJPrefix}-public-subnet-c"
### Private Subnet ###
PrivateSubnetA:
Type: "AWS::EC2::Subnet"
Properties:
AvailabilityZone: "ap-northeast-1a"
CidrBlock: !Ref PrivateSubnetACIDR
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub "${PJPrefix}-private-subnet-a"
PrivateSubnetC:
Type: "AWS::EC2::Subnet"
Properties:
AvailabilityZone: "ap-northeast-1c"
CidrBlock: !Ref PrivateSubnetCCIDR
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub "${PJPrefix}-private-subnet-c"
# ------------------------------------------------------------
# RouteTable
# ------------------------------------------------------------
### Public Subnet A Routing ###
PublicARTB:
Type: "AWS::EC2::RouteTable"
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub "${PJPrefix}-public-route-a"
PublicASubnetRTBAssociation:
Type: "AWS::EC2::SubnetRouteTableAssociation"
Properties:
SubnetId: !Ref PublicSubnetA
RouteTableId: !Ref PublicARTB
PublicARoute:
Type: "AWS::EC2::Route"
Properties:
RouteTableId: !Ref PublicARTB
DestinationCidrBlock: "0.0.0.0/0"
GatewayId: !Ref InternetGateway
### Public Subnet C Routing ###
PublicCRTB:
Type: "AWS::EC2::RouteTable"
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub "${PJPrefix}-public-route-c"
PublicCSubnetRTBAssociation:
Type: "AWS::EC2::SubnetRouteTableAssociation"
Properties:
SubnetId: !Ref PublicSubnetC
RouteTableId: !Ref PublicCRTB
PublicCRoute:
Type: "AWS::EC2::Route"
Properties:
RouteTableId: !Ref PublicCRTB
DestinationCidrBlock: "0.0.0.0/0"
GatewayId: !Ref InternetGateway
### Private Subnet A Routing ###
PrivateARTB:
Type: "AWS::EC2::RouteTable"
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub "${PJPrefix}-private-route-a"
PrivateSubnetRTBAAssociation:
Type: "AWS::EC2::SubnetRouteTableAssociation"
Properties:
SubnetId: !Ref PrivateSubnetA
RouteTableId: !Ref PrivateARTB
PrivateRouteA01:
Type: "AWS::EC2::Route"
Properties:
RouteTableId: !Ref PrivateARTB
DestinationCidrBlock: "0.0.0.0/0"
NatGatewayId: !Ref NatGateway
### Private Subnet C Routing ###
PrivateCRTB:
Type: "AWS::EC2::RouteTable"
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub "${PJPrefix}-private-route-c"
PrivateSubnetRTBCAssociation:
Type: "AWS::EC2::SubnetRouteTableAssociation"
Properties:
SubnetId: !Ref PrivateSubnetC
RouteTableId: !Ref PrivateCRTB
PrivateRouteC01:
Type: "AWS::EC2::Route"
Properties:
RouteTableId: !Ref PrivateCRTB
DestinationCidrBlock: "0.0.0.0/0"
NatGatewayId: !Ref NatGateway
# ------------------------------------------------------------
# Output Parameter
# ------------------------------------------------------------
Outputs:
### VPC ###
VPC:
Value: !Ref VPC
Export:
Name: !Sub "${PJPrefix}-vpc"
### Subnet ###
## Public Subnet A ##
PublicSubnetA:
Value: !Ref PublicSubnetA
Export:
Name: !Sub "${PJPrefix}-public-subnet-a"
## Public Subnet C ##
PublicSubnetC:
Value: !Ref PublicSubnetC
Export:
Name: !Sub "${PJPrefix}-public-subnet-c"
## Private Subnet A ##
PrivateSubnetA:
Value: !Ref PrivateSubnetA
Export:
Name: !Sub "${PJPrefix}-private-subnet-a"
## Private Subnet C ##
PrivateSubnetC:
Value: !Ref PrivateSubnetC
Export:
Name: !Sub "${PJPrefix}-private-subnet-c"
##5.1 NWテンプレートのビルド
では作成したCFnのビルドを行います。
概要でも説明しましたが、ビルドはAWS CLIコマンドを使用して行います。
投稿主はCloud9を使用しているので、Cloud9上でBashを開き、そこでビルドを行っていきます。
AWS CLIを使用してのCFnテンプレートのビルド方法は非常に単純で、ワンライナーで完結します。
以下コマンドを実行してください。
※ スタック名やプレフィックス、また追加で指定したいパラメータ等があればご自身の環境に合わせ修正して下さい。
$ aws cloudformation create-stack \
--stack-name web2tier-Network-stack \
--template-body file://./network.yml \
--parameters ParameterKey=PJPrefix,ParameterValue=web2tier
↓ 構文エラーが無ければ、以下のような結果出力がされます。
{
"StackId": "arn:aws:cloudformation:ap-northeast-1:xxxxxxx:stack/<スタックネーム>/<メタ番号>"
}
#6. セキュリティテンプレートの作成
以下はSecurity部分のテンプレートになります。
こちらも命名規則等、必要であればご自身の環境に合わせて修正してください。
修正が完了したら、作業用ディレクトリに「security.yml」というファイル名で保存してください。
AWSTemplateFormatVersion: "2010-09-09"
Description: Web2tier-Security-Template
# ------------------------------------------------------------
# Input Parameters
# ------------------------------------------------------------
Parameters:
### Project Prefix ###
PJPrefix:
Type: String
### Resources ###
Resources:
# ------------------------------------------------------------
# SecurityGroup
# ------------------------------------------------------------
### ALB Server Security Group ###
ALBSG:
Type: "AWS::EC2::SecurityGroup"
Properties:
GroupDescription: "https"
GroupName: cfn-dev-alb-sg
VpcId: { "Fn::ImportValue": !Sub "${PJPrefix}-vpc" }
Tags:
- Key: Name
Value: !Sub "${PJPrefix}-alb-sg"
SecurityGroupIngress:
IpProtocol: tcp
FromPort : 443
ToPort : 443
CidrIp: 0.0.0.0/0
### Web Server Security Group ###
WebSG:
Type: "AWS::EC2::SecurityGroup"
Properties:
GroupDescription: "http"
GroupName: cfn-dev-web-sg
VpcId: { "Fn::ImportValue": !Sub "${PJPrefix}-vpc" }
Tags:
- Key: Name
Value: !Sub "${PJPrefix}-web-sg"
SecurityGroupIngress:
IpProtocol: tcp
FromPort : 80
ToPort : 80
SourceSecurityGroupId: !Ref ALBSG
### RDS Security Group ###
RDSSG:
Type: "AWS::EC2::SecurityGroup"
Properties:
GroupDescription: "mysql"
GroupName: cfn-dev-rds-sg
VpcId: { "Fn::ImportValue": !Sub "${PJPrefix}-vpc" }
Tags:
- Key: Name
Value: !Sub "${PJPrefix}-RDS-sg"
SecurityGroupIngress:
IpProtocol: tcp
FromPort : 3306
ToPort : 3306
SourceSecurityGroupId: !Ref WebSG
# ------------------------------------------------------------
# Output Parameter
# ------------------------------------------------------------
Outputs:
### SecurityGroup ###
ALBSG:
Value: !Ref ALBSG
Export:
Name: !Sub "${PJPrefix}-alb-sg"
WebSG:
Value: !Ref WebSG
Export:
Name: !Sub "${PJPrefix}-web-sg"
RDSSG:
Value: !Ref RDSSG
Export:
Name: !Sub "${PJPrefix}-rds-sg"
##6.1 NWテンプレートのビルド
ではNWと同じように作成したCFnテンプレートのビルドを行います。
以下コマンドを実行してください。
※ スタック名やプレフィックス、また追加で指定したいパラメータ等があればご自身の環境に合わせ修正して下さい。
$ aws cloudformation create-stack \
--stack-name web2tier-Security-stack \
--template-body file://./security.yml \
--parameters ParameterKey=PJPrefix,ParameterValue=web2tier
↓ 構文エラーが無ければ、以下のような結果出力がされます。
{
"StackId": "arn:aws:cloudformation:ap-northeast-1:xxxxxxx:stack/<スタックネーム>/<メタ番号>"
}
#7. まとめ
本記事は以上になります。
次回はサーバー部分のテンプレート作成「【AWS】CloudFormationでWebサーバを構築②(EC2編)」になります。
やはりCUIよりGUIの方が直感的に分かりやすく、ミスオペも無く簡単ですが、慣れればCUIのが簡易にインフラ構築が可能になります。
また、コード化することによって、GitHub等のバージョン管理システム上でコード管理を行えるようになり、大規模なインフラ構築における可視性の向上、及び迅速なプロビジョニングが可能になります。
本記事を足がかりに、是非この際にIaCに挑戦して貰えればと思います。
--- 記事一覧 ---
①【AWS】CloudFormationでWebサービスを構築①(NW編)
②【AWS】CloudFormationでWebサービスを構築②(EC2編)
③【AWS】CloudFormationでWebサービスを構築③(RDS編)