#ご挨拶
CloudFormationの学習の中で簡単なものを作ってみました。
#やりたいこと
CloudFormationでパブリックサブネットにあるEC2とプライベートサブネットにあるRDSを作成したい。
構成イメージ図は以下になります。
#前提と最終ゴール
- VPCとパブリックサブネットは既存のもの(デフォルト)を使用
2.東京リージョンで作成することを想定 - CloudFormationを使用できるIAMユーザなどは作成済み
- EC2インスタンスに使用するキーペアは作成済み
- 最終ゴールはWordPressのテストページが表示できるようになること
#テンプレート作成
作成したテンプレートは以下になります。
gitリポジトリ
※Resourcesセクションだけでごり押しで作成しました。
今後Parametersセクションを使用して再利用性を高めていきます。
AWSTemplateFormatVersion: "2010-09-09"
Description: cloudformation study
#リソース
Resources:
privatesubnet1:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: ap-northeast-1a
CidrBlock: 172.31.48.0/20
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: privatesubnet1
VpcId: #vpcid入力
privatesubnet2:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: ap-northeast-1c
CidrBlock: 172.31.64.0/20
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: privatesubnet2
VpcId: #vpcid入力
privateroutetable:
Type: AWS::EC2::RouteTable
Properties:
Tags:
- Key: Name
Value: privateroutetable
VpcId: #vpcid入力
routetableattach1:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref privateroutetable
SubnetId: !Ref privatesubnet1
routetableattach2:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref privateroutetable
SubnetId: !Ref privatesubnet2
ec2securitygroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: ec2-securitygroup
SecurityGroupEgress:
- IpProtocol: -1
FromPort: -1
ToPort: -1
CidrIp: 0.0.0.0/0
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: 0.0.0.0/0
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIpv6: ::/0
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: 0.0.0.0/0
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIpv6: ::/0
- IpProtocol: tcp
FromPort: 22
ToPort: 22
CidrIp: #自分のIPアドレス入力
VpcId: #vpcid入力
rdssecuritygroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: rds-securitygroup
SecurityGroupEgress:
- IpProtocol: -1
FromPort: -1
ToPort: -1
CidrIp: 0.0.0.0/0
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 3306
ToPort: 3306
SourceSecurityGroupId: !Ref ec2securitygroup
VpcId: #vpcid入力
ec2instance:
Type: AWS::EC2::Instance
Properties:
BlockDeviceMappings:
- DeviceName: #ルートデバイス名入力
Ebs:
DeleteOnTermination: true
VolumeSize: 16
VolumeType: gp2
ImageId: #イメージID入力
InstanceType: #インスタンスタイプ入力
KeyName: #キーペア入力
NetworkInterfaces:
- AssociatePublicIpAddress: true
DeleteOnTermination: true
DeviceIndex: "0"
GroupSet:
- !Ref ec2securitygroup
SubnetId: #サブネットID入力
Tags:
- Key: Name
Value: ec2instance
rdssubnetgroup:
Type: AWS::RDS::DBSubnetGroup
Properties:
DBSubnetGroupDescription: rdssubnetgroup
SubnetIds:
- !Ref privatesubnet1
- !Ref privatesubnet2
DBSubnetGroupName: #サブネットグループ名入力
Tags:
- Key: Name
Value: rdssubnetgroup
rdsinstance:
Type: AWS::RDS::DBInstance
Properties:
AllocatedStorage: #ストレージ量入力
DBInstanceClass: #インスタンスクラス入力
DBSubnetGroupName:
!Ref rdssubnetgroup
Engine: mysql
EngineVersion: "5.7.34"
MasterUsername: #DBユーザ名入力
MasterUserPassword: #DBパスワード入力
StorageType: gp2
Tags:
- Key: Name
Value: rdsinstance
VPCSecurityGroups:
- !Ref rdssecuritygroup
##各Resourcesセクション解説
###プライベートサブネット作成
プライベートサブネットはRDSのサブネットグループで使うので2つ作成します。(privatesubnet1、privatesubnet2)
privatesubnet1:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: ap-northeast-1a
CidrBlock: 172.31.48.0/20
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: privatesubnet1
VpcId: #vpcid入力
- AvailabilityZone:アベイラビリティゾーンの指定をします。
- CidrBlock:サブネットのCidrBlockを指定します。
- MapPublicIpOnLaunch:インスタンスをこのサブネットで起動した場合にパブリックIPアドレスをアタッチする(RDSを置くだけなので今回は必要なかったかも)
- Tags:タグの作成
- VpcId:サブネットが置かれるVPCの指定をします。
###ルートテーブル作成
プライベートサブネットのルートテーブルを作成します。
privateroutetable:
Type: AWS::EC2::RouteTable
Properties:
Tags:
- Key: Name
Value: privateroutetable
VpcId: #vpcid入力
- Tags:タグの作成
- VpcId:紐づけるVPCの指定
###ルートテーブルのアタッチ
プライベートサブネットにルートテーブルをアタッチします。
プライベートサブネットは2つあるので2つ分実行します。(routetableattach1、routetableattach2)
routetableattach1:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref privateroutetable
SubnetId: !Ref privatesubnet1
AWS::EC2::SubnetRouteTableAssociation公式ドキュメント
- RouteTableId:ルートテーブルを紐づけます (組み込み関数のRefでルートテーブルIDを参照しています)
- サブネットを紐づけます (組み込み関数のRefでサブネットIDを参照しています)
###EC2のセキュリティグループ作成
EC2のセキュリティグループを作成します。
今回はHTTPのポート番号とついでにHTTPSのポート番号、SSHを開けてます。(ドメインとか証明書設定しないのでHTTPSは必要無い)
ec2securitygroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: ec2-securitygroup
SecurityGroupEgress:
- IpProtocol: -1
FromPort: -1
ToPort: -1
CidrIp: 0.0.0.0/0
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: 0.0.0.0/0
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIpv6: ::/0
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: 0.0.0.0/0
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIpv6: ::/0
- IpProtocol: tcp
FromPort: 22
ToPort: 22
CidrIp: #自分のIPアドレス入力
VpcId: #vpcid入力
AWS::EC2::SecurityGroup公式ドキュメント
- GroupDescription:セキュリティグループの説明
- SecurityGroupEgress:アウトバウンドの設定
2. IpProtocol:プロトコルの指定 (-1を指定するとすべて許可する)
2. FromPort:許可するポート番号の範囲の開始番号 (-1を指定するとすべて許可する)
2. ToPort:許可するポート番号の範囲の終了番号 (-1を指定するとすべて許可する)
2. CidrIp:許可するIPアドレス (0.0.0.0/0ですべてのIPアドレスを許可する) - SecurityGroupIngress:インバウンドの設定
3. IpProtocol:プロトコルの指定
3. FromPort:許可するポート番号の範囲の開始番号
3. ToPort:許可するポート番号の範囲の終了番号
3. CidrIp:許可するIPアドレス - VpcId:紐づけるVPCの指定
###RDSのセキュリティグループ作成
RDSのセキュリティグループを作成します。
基本的にはEC2のセキュリティグループと同じ作り方になります。
EC2からの通信を許可する設定をします。
MySQLを使用するのでポート番号3306を開けます。
rdssecuritygroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: rds-securitygroup
SecurityGroupEgress:
- IpProtocol: -1
FromPort: -1
ToPort: -1
CidrIp: 0.0.0.0/0
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 3306
ToPort: 3306
SourceSecurityGroupId: !Ref ec2securitygroup
VpcId: #vpcid入力
AWS::EC2::SecurityGroup公式ドキュメント
- GroupDescription:セキュリティグループの説明
- SecurityGroupEgress:アウトバウンドの設定
2. IpProtocol:プロトコルの指定 (-1を指定するとすべて許可する)
2. FromPort:許可するポート番号の範囲の開始番号 (-1を指定するとすべて許可する)
2. ToPort:許可するポート番号の範囲の終了番号 (-1を指定するとすべて許可する)
2. CidrIp:許可するIPアドレス (0.0.0.0/0ですべてのIPアドレスを許可する) - SecurityGroupIngress:インバウンドの設定
3. IpProtocol:プロトコルの指定
3. FromPort:許可するポート番号の範囲の開始番号
3. ToPort:許可するポート番号の範囲の終了番号
3. SourceSecurityGroupId:許可するセキュリティグループを指定 - VpcId:紐づけるVPCの指定
###EC2インスタンス作成
EC2インスタンスを作成していきます。
ルートデバイス名は使用するAMIごとに変更してください。
ec2instance:
Type: AWS::EC2::Instance
Properties:
BlockDeviceMappings:
- DeviceName: #ルートデバイス名入力
Ebs:
DeleteOnTermination: true
VolumeSize: 16
VolumeType: gp2
ImageId: #イメージID入力
InstanceType: #インスタンスタイプ入力
KeyName: #キーペア入力
NetworkInterfaces:
- AssociatePublicIpAddress: true
DeleteOnTermination: true
DeviceIndex: "0"
GroupSet:
- !Ref ec2securitygroup
SubnetId: #サブネットID入力
Tags:
- Key: Name
Value: ec2instance
- BlockDeviceMappings:インスタンス起動時に使用するEBSの指定
- DeviceName:ルートデバイス名 (Ubuntuなら/dev/sda1)
- Ebs:EBSの設定
- DeleteOnTermination:インスタンスの終了時にEBSボリュームを削除する設定
- VolumeSize:ボリュームサイズの指定
- VolumeType:ボリュームタイプの指定
- ImageId:AMIの指定
- InstanceType:インスタンスタイプの指定
- KeyName:キーペアの指定
- NetworkInterfaces:ネットワークインターフェースの設定
5. AssociatePublicIpAddress:グローバルIPアドレスを起動時に割り当てる設定
5. DeleteOnTermination:インスタンスの終了時にネットワークインターフェースを削除する設定
5. DeviceIndex:プライマリネットワークインターフェイスを指定
5. GroupSet:セキュリティグループを指定
5. SubnetId:ネットワークインターフェイスに関連付けられているサブネットIDの指定 - Tags:タグの作成
###RDSサブネットグループ作成
サブネットグループを作成していきます。
作成したプライベートサブネットを使用します。
rdssubnetgroup:
Type: AWS::RDS::DBSubnetGroup
Properties:
DBSubnetGroupDescription: rdssubnetgroup
SubnetIds:
- !Ref privatesubnet1
- !Ref privatesubnet2
DBSubnetGroupName: #サブネットグループ名入力
Tags:
- Key: Name
Value: rdssubnetgroup
AWS::RDS::DBSubnetGroup公式ドキュメント
- DBSubnetGroupDescription:サブネットグループの説明
- SubnetIds:サブネットグループに含めるサブネットの指定 (組み込み関数のRefでサブネットIDを参照しています)
- DBSubnetGroupName:サブネットグループ名
- Tags:タグの作成
###RDSの作成
RDSを作成していきます。
今回はMySQL5.7系を使用します。
rdsinstance:
Type: AWS::RDS::DBInstance
Properties:
AllocatedStorage: #ストレージ量入力
DBInstanceClass: #インスタンスクラス入力
DBSubnetGroupName:
!Ref rdssubnetgroup
Engine: mysql
EngineVersion: "5.7.34"
MasterUsername: #DBユーザ名入力
MasterUserPassword: #DBパスワード入力
StorageType: gp2
Tags:
- Key: Name
Value: rdsinstance
VPCSecurityGroups:
- !Ref rdssecuritygroup
- AllocatedStorage:RDSのストレージ量指定
- DBInstanceClass:RDSインスタンスクラスの指定
- DBSubnetGroupName:サブネットグループの指定 (組み込み関数のRefでサブネットグループを参照しています)
- Engine:RDSのエンジンの指定
- EngineVersion:エンジンバージョンの指定
- MasterUsername:DBの管理者ユーザ名の指定
- MasterUserPassword:DBの管理者ユーザのパスワード指定
- StorageType:ストレージタイプの指定
- タグの作成
- VPCSecurityGroups:セキュリティグループを紐づける設定 (組み込み関数のRefでセキュリティグループIDを参照しています)
#CloudFormationでスタック作成
マネジメントコンソールから作成していきます。
マネジメントコンソールからCloudFormationのダウンロードへ移動。
移動後スタックの作成 (下記画像赤枠部分)から「新しいリソースを使用 (標準)」を選択
下記画像のようにテンプレートの指定からテンプレートファイルをアップロードを選択して作成したymlファイルをアップロードする。
次の画面ではスタック名を入力する。ymlファイルにパラメータセクションがあるとここで入力することができます。
次の画面ではスタックのタグやIAMロールなどの設定ができます。
今回はデフォルトでそのまま次の画面へ行きます。
次の画面ではスタック作成前の最終確認画面です。
この画面で設定に問題が無ければスタックの作成をクリックします。
作成が開始されると以下の画面のようにリソースの作成状況が表示されます。
ymlファイルでOutputsセクションをつけるとこの段階でEC2のIPアドレスなどが確認できるようです。
今後の更新でOutputsセクションも追加していきたいと考えています。
#EC2インスタンスでの作業
ここからはEC2インスタンスへSSH接続してApacheのインストールとWordPressのダウンロードを行います。
EC2インスタンスのダッシュボードからCloudFormationで作成されたインスタンスを選択してパブリックIPを確認します。
確認ができたらSSh接続を行います。
ssh -i 鍵ファイル名 ubuntu@EC2のIPアドレス
今回はubuntuを使用しました。
以下のコマンドを実行してMySQLクライアントとApacheとphpのインストールとWordPressのダウンロードを行います。
sudo apt update
sudo apt install mysql-client
sudo apt install apache2
sudo apt install php7.4 php7.4-curl php-imagick php7.4-mbstring php7.4-mysql php7.4-xml php7.4-zip
sudo systemctl start apache2
sudo systemctl enable apache2
sudo wget https://ja.wordpress.org/latest-ja.tar.gz
tar -xvzf latest-ja.tar.gz
sudo mv wordpress/ /var/www/
sudo chown -R www-data:www-data /var/www/wordpress
コマンドを解説します。
- sudo apt update:パッケージを最新にします。
- sudo apt install mysql-client:MySQLクライアントをインストールします。
- sudo apt install apache2:Apacheをインストールします。
- sudo apt install php7.4 php7.4-curl php-imagick php7.4-mbstring php7.4-mysql php7.4-xml php7.4-zip:phpとWordPressに必要なモジュールをインストールします。必要なモジュール
- sudo systemctl start apache2:Apacheを起動します。
- sudo systemctl enable apache2:Apacheを自動起動させます。
- sudo wget https://ja.wordpress.org/latest-ja.tar.gz:最新バージョンのWordPressをダウンロードします。
- tar -xvzf latest-ja.tar.gz:圧縮ファイルを解凍してアーカイブを展開します。
- sudo mv wordpress/ /var/www/:ドキュメントルート配下にWordPressのファイルを移動します。
- sudo chown -R www-data:www-data /var/www/wordpress:Apacheの実行ユーザとグループに変更します。
次にデータベースを作成します。
mysql -h RDSエンドポイント -u root -P 3306 -p rootのパスワード
create database wordpress default character set utf8;
本当はWordPress用のユーザも作成したほうがいいらしいのですが今回はrootで設定していきます。
次にドキュメントルートを初期の/var/www/htmlから/var/www/wordpressへ変更します。
cd /etc/apache2/sites-available/
sudo cp 000-default.conf wordpress.conf
sudo vi wordpress.conf
ドキュメントルートを以下のように変更
DocumentRoot /var/www/wordpress
上記のように初期のファイルをコピーして編集しているのは元々の物はひな形として使用するためです。(会社の先輩の受け売り)
変更したら以下のコマンドを実行します。
sudo a2dissite 000-default
sudo a2ensite wordpress
sudo systemctl reload apache2
コマンドの解説をします。
- sudo a2dissite 000-default:このコマンドでデフォルトの設定を無効化しています。
- sudo a2ensite wordpress:このコマンドで新規に作成したファイルを読み込ませるように設定しています。
- sudo systemctl reload apache2:こちらのコマンドでApacheを再起動します。
ここら辺の解説はこちらの方の記事がわかりやすかったです。
UbuntuのApache設定ファイル、どうやるんだっけ?
ここまで完了したらブラウザでEC2のIPアドレスでアクセスしてみてください。
アクセスすると以下の画面が出てきます。
出てきたら「さあ、始めましょう!」をクリックして先に進みます。
次の画面ではデータベースへの接続情報を入力します。
データベースのホスト名はRDSのエンドポイントを入力してください。
入力したらWordPressをインストールをクリックして次の画面へ移動します。
この画面ではWordPressの管理画面へのログインに使用する管理ユーザを作成します。
入力が完了してログインに成功したら完了です。
#感想
今回はCloudFormationを使用してEC2とRDSを作成しました。
ymlファイルの内容はごり押しで作成しているので今後ParametersセクションやOutputsセクションを利用して使いやすいスタックにしていきたいと考えています。
(今回のハマりポイントがWordPressのPHPモジュールインストール関連とか言えない)