AWS基礎から学習②-CloudFormation-

#はじめに
今回はCloudFormationでの環境構築について書いていきます。
CloudFormationはソースコードを記載することで自動でインフラの環境構築を行えるすばらしいサービスです。

CloudFormationの特徴
①ソースコードの通りにインフラの環境構築を行う
②ソースコードを共有することで共有先でも同じ環境を用意できる
といった特徴があり、

特に①は開発を行っていく上で<b>ヒューマンエラー</b>がなくなる点で優れています。システムを構築する上では人間が行う操作はどうしてもエラー原因のもとを作ってしまうことが多く、これをできる限り少なくすることが、エラーの少ないシステムを作り上げる上では重要な要素となっています。
(例：システム作成時の手順操作が一つ抜けたor誤った等)

しかし、ソースコードで環境構築を行うということで苦手意識を持つ方が多いと思います。

そこで今回は環境構築のイメージがしやすいように
①AWSコンソール操作画面時
②ソースコード
を並行してみながら環境構築するところを記事していきます。

この形式であれば、テンプレートに苦手意識があった方でも作成時のイメージがしやすくなるかと思うのでぜひ一読いただければと思います。

CloudFormation始めて触ってみる方やテンプレートを見てもよくわからなかった方の参考になれば幸いです。

#環境
・AWSサービス(2021/1/26時点)
※各種設定画面は都度アップデートされていますので画像と異なる場合があります。

・エディタ…VisualStudioCode
※エディタは任意のもので作成してもいいですが、VisualStudioCodeにはCloudformationのソースを書く上で非常に便利な拡張機能があるのでそちらを使うと非常に効率よくコードを書けます。)
下記環境の構築の際に参考になる記事を用意しました。

>https://nopipi.hatenablog.com/entry/2019/04/27/155616
参照元：のぴぴのメモ

なお、今回はソースコードは画像で貼っていますので手元で確認しながら記事を見たい方は[こちら](https://github.com/Ruscty/cloudformation-templates/tree/main/cloudformation)の自分のGithubに置いていますのでこちらからダウンロードしてみてください。

#目次
[1.初期項目について](#1-初期項目について)
[2.VPC作成](#2vpc作成)
[3.EC2作成](#3ec2作成)
[4.今回のソースコード](#4今回のソースコード)
[5.まとめ](#5まとめ)

#目標構成図
構成図は前回記事の構成図を再現していきます。
![aws-test.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1048766/5fd08d91-3cea-0ad4-a54e-84380e950c8c.png)

なお、CloudFormationのスタック(作成予定の目標環境)を区別するためVPC、EC2それぞれのサービスでテンプレートを用意します。
![CF1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1048766/b6b0d736-1982-537c-c4a7-2aa419561e1a.png)

#1.初期項目について
構成図の環境構築を行う前にまずCloudFormationで使われる初期項目について見ていきましょう。
![初期項目.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1048766/1805c48c-6df9-434f-c2e5-77a9e13dccc8.png)

|項目  |設定内容  |必須/任意 |
|---|---|---|
|AWSTemplateFormatVersion  |Cloudfromationのテンプレート形式バージョンを指定する。 [2010-09-09]はそのまま使用。  |必須  |
|Description  |英訳の通り説明文になります。このテンプレートの説明を記載します。  |任意  |
|Metadata  |リソースに付与する情報を記載する。(例：認証情報やユーザー情報)|任意  |
|Parameters  |Cloudformationの操作画面内で作成するAWSリソースのパラメータを任意に設定したい場合に記載する項目。(例：VPCの名前を都度任意に設定したい場合等)  |任意  |
|Mappings  |取得したいリソースの参照先を表す際に記載する項目。主にリージョンを超えての参照を行う際に使われる。(例：作業場所が東京リージョンで使用したいAWSのリソースが北米リージョンにある場合など)  |任意  |
|Conditions  |テンプレートに記載のリソースを作成する条件を記載する項目。(例：スタックを追加するときに条件が合わなかった場合にそのリソースのみ環境構築を行わない場合等)  |任意  |
|Resources  |メインとなる作成するAWSリソースを記載する項目。  |必須  |
|Outputs  |他スタックと連携する際に必要な指定した値を出力する項目。|任意  |

#2.VPC作成
それではまずVPCサービスの構成を作成していきます。
・VPC
・インターネットゲートウェイ
・サブネット
・ElasticIP
・セキュリティグループ
・ルートテーブル
が対象です。

ここから先はResources内に記載する内容です。
###VPC
・左側：実際の操作画面
・右側：テンプレート
![比較１.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1048766/33304398-1f78-32ea-183d-f9bcb6f754ce.png)

VPCの設定になります。
この後のリソース作成でも重要となってくるのが「myVPCID」の部分。
<b>・myVPCID</b>
→ここは<b>VPCの論理ID</b>となります。
論理IDはそのテンプレート内で一意にしか持てないIDを指し、<b>任意の名称</b>を設定することが出来ます。
(自分は最初、論理IDは決まった値しかないと思い込んでしまい、複数のリソースを作成する際に迷ったことがありました。)

|項目  |設定内容  |
|---|---|
|Type  |AWSのリソースの種類を指定します。VPCを指定するので「AWS::EC2::VPC」となります。|
|Properties  |値を設定する項目一覧になります。properties以下に値入力が必要となる項目を設定します。|
|CidrBlock |VPCのCIDRを設定します。
|EnableDnsSupport|VPC に対して DNS 解決がサポートされているかどうかを示します。作成時の画面では設定する場所はありませんがデフォルトで有効になっています。
|Tags(Key,Value)|→タグを設定<br>※KeyにNameと設定することでValueの値がVPCの名前になります。他のAWSリソースも同様に設定しています。

###インターネットゲートウェイ
![比較２.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1048766/9c470ffb-3a6e-c824-742b-fc1123da0e21.png)
インターネットゲートウェイの作成とアタッチまで行っています。

ここで注目すべき点は黄枠と線で示した<b>「!Ref [論理ID]」</b>の部分です。
!Refを使うことでテンプレート内の指定した論理IDを参照することが出来ます。これでインターネットゲートウェイのVPCを設定する項目で関連付け(アタッチ)を行うことが出来ます。
(※以降の黄色枠、先は論理IDの参照を示します。)

|項目  |設定内容  |
|---|---|
|IGWID  |インターネットゲートウェイの論理ID(任意)  |
|Type  |インターネットゲートウェイを指定するので「AWS::EC2::InternetGateway」  |
|AttachGatewayID  |インターネットゲートウェイのアタッチ論理ID(任意)  |
|Type  |インターネットゲートウェイのアタッチを行うので「AWS::EC2::InternetGateway」 |
|VpcId  |Vpcの論理IDを指定します。|
|InternetGatewayId  |インタネットゲートウェイの論理IDを指定します。 |
(この後に記載するテーブルの共通する項目は省略していきます。)
###サブネット
■パブリックサブネット
![比較３.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1048766/4397d42f-860b-2f48-dfe9-a7f6511e342f.png)
■プライベートサブネット
![比較.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1048766/a6e0de9d-b19d-513e-f537-4a1c88857937.png)


サブネットの作成です。
基本的に項目の構成はあまり変わりませんね。
パブリック、プライベートサブネットはCIDRの範囲に気をつけながら設定してください。

|項目  |設定内容  |
|---|---|
|PublicSubnetID PrivateSubnetID  |サブネットの論理ID(任意)  |
|Type  |サブネットの作成を指定するので「AWS::EC2::Subnet」  |
|AvailabilityZone  |アベイラビリティゾーンを指定 |


###ElasticIP
![比較４.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1048766/ea5dd3ab-2013-8a34-6eef-d6b600735875.png)

今回のElasticIPの設定は画面側と共通する項目はありませんが、割り当てるElasticIPをどのVPC内で利用するか指定します。

|項目  |設定内容  |
|---|---|
|Domain  |ElasticIPを利用するVPCを指定  |

ここで作成したElasticIPは後ほどEC2に割り当てる際に利用します。

###セキュリティグループ
■パブリックサブネットのセキュリティグループ
![比較セキュ①.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1048766/fdac8446-5bcd-0c23-9a75-41e2c913adfc.png)

■プライベートサブネットのセキュリティグループ
![hikaku.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1048766/ba998484-00c8-9638-ab6b-40307e37a85c.png)
セキュリティグループも基本的に操作画面に沿って設定していきます。
なお今回のアウトバウンドルールはコメントアウトしていますが、
コメントアウトした場合は現在の操作画面の設定が初期値として反映されます。

またプライベートサブネットのセキュリティグループの設定を今回は0.0.0.0/0としていますが、セキュリティを高める場合には、コメントアウト部分に記載の通りEC2に設定するElasticIPを設定すると効果的です。

|項目  |設定内容  |
|---|---|
|SecGroupNamePublicID<br>SecGroupNamePrivateID  |セキュリティグループの論理ID(任意)<br> |
|Type  |セキュリティグループの作成を指定するので「AWS::EC2::SecurityGroup」  |
|GroupName  |セキュリティグループの名前 |
|GroupDescription  |セキュリティグループの説明文  |
|SecurityGroupIngress  |セキュリティグループのインバウンド  |
|IpProtocol  |ポート番号(今回SSH接続で22を指定)  |
|FromPort  |ポート番号(今回SSH接続で22を指定)  |
|CidrIp  |セキュリティグループのCIDRを設定  |
|SecurityGroupEgress  |セキュリティグループのアウトバウンド  |

###ルートテーブル
■パブリックサブネットのルートテーブル
![スクリーンショット 2021-01-28 21.30.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1048766/7bb47bcc-45f4-f8fa-1255-1ba920484b45.png)
■プライベートサブネットのルートテーブル
![スクリーンショット 2021-01-28 21.30.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1048766/498f8132-6072-e908-96d0-c427595f51d7.png)

参照が多くなってきて、複雑になってきました。ですが難しいことはありません。ルートテーブルを作成し、<b>それぞれどのサブネットの論理IDに関連付けるか</b>、またどこの画面操作をしているのか確認できればおのずと繋がって来ると思います。
■ルートテーブルの作成

|項目  |設定内容  |
|---|---|
|RouteTableNamePublicID<br>RouteTableNamePrivateID  |ルートテーブルの論理ID(任意)  |
|Type  |ルートテーブルの作成を指定するので「AWS::EC2::RouteTable」  |

■ルートテーブルの関連付け

|項目  |設定内容  |
|---|---|
|SubnetId  |ルートテーブルの関連付けを指定するので「AWS::EC2::SubnetRouteTableAssociation」  |
|SubnetId  |関連付けるサブネット |
|RouteTableId  |関連付けるルートテーブル  |

■ルートテーブルのルートを指定

|項目  |設定内容  |
|---|---|
|Type  |ルートテーブル内のルートを指定するので「AWS::EC2::Route」  |
|RouteTableId  |ルートテーブルの論理ID(任意) |
|DestinationCidrBlock  |接続するCIDRブロックを指定<br>(ここでは0.0.0.0/0)  |
|GatewayId  |インターネットゲートウェイの論理ID(任意)  |

###Outputs
OutputsではResourcesで設定した値を出力することができ、その値を別のスタックで使用することが可能になります。今回の例ではVPCスタックで作成したものをEC2のスタックで利用できるようにします。
そして今回使用するVPCの値は

①ElasticIP
→EC2に固定IPアドレスを付与します。

②サブネット
→EC2を配置するサブネットの論理IDを出力します。

②パブリック&プライベートサブネットのセキュリティグループ
→EC2に作成したセキュリティグループを設定します。
![比較出力.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1048766/feb42c36-7f58-cf97-84e4-97d51bcc2236.png)
ここで注目したい点は<b>「!GetAtt」</b>の部分。
記載方法としては
!GetAtt [論理ID].[各種パラメータ]となっており、
対象の論理IDのAWSリソースから情報を取得します。
なお、[各種パラメータ]はそれぞれのAWSリソースで決まった値が入るので、ここはドキュメントで確認する作業が必要となります。
(例：[セキュリティグループのドキュメント](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-security-group.html#aws-properties-ec2-security-group-return-values))

###ここまでの構成図
![VPC_image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1048766/0fc24b98-6e16-2823-fc03-ab50bdc10865.png)


#3.EC2作成
次にEC2のテンプレートです。
###前準備
前準備として<b>キーペアはCloudformationで作成することが出来ない</b>ためキーペアは事前に作成します。
EC2メニューの「ネットワーク & セキュリティ>キーペア」でキーペアの作成を行います。
![キーペア.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1048766/5231dc68-9bdc-d429-d452-9efc346f089c.png)

###EC2作成
パブリックサブネット側とプライベートサブネット側で設定する内容は大きく変わらないので合わせて記載します。
![EC2比較.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1048766/a7ce1a7b-2461-5228-f9f1-06308a78ef57.png)

ここでの注目点は<b>「!ImportValue」</b>です。
VPCのテンプレートでOutputで出力した値をここで使用しています。
Export>Nameで指定した値を入力して値を取得し、スタック間での連携が可能となります。

|項目  |設定内容  |
|---|---|
|Type  |EC2を指定するので「AWS::EC2::Instance」  |
|KeyName  |キーペアの名前  |
|ImageId  |AMIを入力  |
|InstanceType  |インスタンスタイプを入力 |
|SecurityGroupIds  |セキュリティグループのIdを指定  |
|SubnetId  |EC2を配置するサブネットIdを指定  |
|UserData  |シェルスクリプトを記載する(今回は省略)<br>事前にEC2にインストールしたいソフトウェアをここで記載する。  |

###ElasticIPをEC2に割り当て
![Elastic割り当て.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1048766/0bfa90a4-01ef-fb86-d9d2-9d663c64782a.png)
EC2にElasticIPアドレスを割り当て、外部からSSH接続でキーペアを使ってアクセス可能にします。

|項目  |設定内容  |
|---|---|
|Type  |AWS::EC2::EIPAssociation  |
|AllocationId  |ElasticIPをEC2と関連付けるためのIdを指定<br>VPCで設定したElasticIPを関連付ける  |
|InstanceId  |EC2の論理IDを指定  |

<b>割り当てのEC2の画面</b>
![EC2結果.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1048766/0bc3c241-2e71-e62a-ae61-387e292f369c.png)

###Cloudformationでスタックを作成
最後にcloudformation内でテンプレートを用いて
①VPC
②EC2
の順でスタックを作成します。

①VPC
![スタック１.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1048766/00649f43-875a-52d2-15f0-17bf541c64cc.png)
テンプレートを選択。
![スタック２.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1048766/07d7c724-7015-0d6f-64d7-fe7d2ed5a559.png)
スタックの名前を入力。
![スタック３.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1048766/4848d0f8-5d77-6bb6-dc84-fd7a6e457d77.png)
タグを任意に入力し、必要に応じてIAMロールを設定し、
スタックを作成します。
![スタック５.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1048766/061e8063-cef7-1a4d-ad84-5154967979ff.png)
スタックの作成が完了すると上記の用にCREATE_COMPLETEと表示され環境が構築されます。

②EC2
![スタック７.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1048766/217054e7-6617-2438-d759-fb733ed6f27c.png)

同様にEC2スタックを作成し、それぞれのスタックが作成されたことを確認します。これで今回の構成図は作成完了です。


###最終的な構成図
![aws-test.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1048766/5fd08d91-3cea-0ad4-a54e-84380e950c8c.png)

構成図の作成はここまでとなります。
構成図完成後、接続確認をしますが、こちらは[前回記事](https://qiita.com/ruscty/items/9058e33a8726aa9fb89c#8%E4%BD%9C%E6%A5%AD%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BC%E3%81%AB%E6%8E%A5%E7%B6%9A)の接続方法を参考にしてみてください。

#4.今回のソースコード
今回作成したソースコードについては下記リンク先のgithubあげましたので、実際のソースコードを確認したい方はぜひ参考にしてみてください。
[今回のソースコードはこちら](https://github.com/Ruscty/cloudformation-templates/tree/main/cloudformation)

#5.まとめ
以上が今回のCloudformationでのEC2の環境構築でした。
実際の操作画面とソースコードを比較しながらやっていきましたが、
ソースコードでの環境構築のイメージがしやすかったのではないでしょうか？

私としては実際の操作画面と比較しながら書いてみて
<b>ソースコードを書く＝操作手順説明書を書く</b>
に近いイメージで書くことが出来ました。

AWS Cloudformationのドキュメントを見て書いていくよりも断然理解が早く進んだのでこの学習方法も使えそうな気がします。

操作画面でポチポチ入力してインフラ環境を構築するだけでなく、ソースコード書いて自動で環境構築できるようになるとかっこいいですよね。
いつか実際の現場でCloudformation使いこなしてボタンひと押しで環境構築をサクッと終わらせてみたいですね。

今回は以上です。

長くなりましたが、ここまで読んでいただきありがとうございました。
AWSを勉強する方の参考になれば幸いです。


#AWSの学習体験
当記事は動画学習サービスのAWSCloudTechの講座を参考に作成しました。
これからもっと普及するクラウドサービスの一角であるAWSを学びたい方におすすめです。

現在、無料講座を開放しているようなので気になった方はぜひ体験してみてください。
[<img width = 1500 src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1048766/5aa91bb4-0c66-9c25-0094-c0d86387c68a.jpeg">](https://aws-cloud-tech.com/?pa=AWSCLOUDTECH1A)