【AWS】CloudFormationでEC2インスタンスを構築

# はじめに
CloudFormationを使って、Nginxが動作するEC2インスタンスを作成しました。
作成したテンプレートファイルは以下のGithubリポジトリにアップロードしています。
https://github.com/nkserveren26/ec2-cloudformation

# インフラ構成図
作成するインフラ構成図を以下に示します。
EC2はAmazon Linuxです。
<img width="400" alt="2022-06-26_11h44_58.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/3bdc1cbf-4413-d7a6-e3f2-6e4bee7871cb.png">


# 事前準備
リソースを作成できるIAMユーザー
キーペア

# 参考にした記事

・CloudFormationによるネットワークリソース（VPC、Internet Gatewayなど）の作成
https://dev.classmethod.jp/articles/cloudformation-beginner01/

・CloudFormationによるEC2作成
https://qiita.com/tyoshitake/items/c5176c0ef4de8d7cf5d8


# テンプレート内容
テンプレートはJSONまたはYAML形式で記述することができます。
今回はYAML形式で記述しています。

## AWSTemplateFormatVersion、Description

テンプレートファイルの始めに形式のバージョン（AWSTemplateFormatVersion）とテンプレート内容（Description）を記述します。

```yaml
AWSTemplateFormatVersion: '2010-09-09'
Description: Provision VPC,PubSub, and EC2
```

## Parameters
Parametersに、EC2のキーペアの情報を記述します。
（Parametersに記載することで、テンプレートファイル内にキーペア名を直接書く必要がなくなり、テンプレートの修正が楽になります。）

```yaml
Parameters: 
  KeyName:
    Description: The EC2 Key Pair to allow SSH access to the instance
    Type: "AWS::EC2::KeyPair::KeyName"
```

## Resources

Resourcesに作成するリソースを記述します。
今回作成するリソースは以下です。
　・VPC
　・InternetGateway
　・パブリックサブネット
　・ルーティングテーブル
　・EC2
　・セキュリティグループ

各リソースの記述内容を以下に記載します。
Resources全体の記述内容はGithubのテンプレートファイルをご参照ください。


### VPC、InternetGateway
VPC、InternetGatewayの記述内容は以下です。
AttachGatewayで、VPCにInternetGatewayをアタッチします。
```yaml
  # VPCの作成
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      Tags:
      - Key: Name
        Value: VPC
  # InternetGatewayの作成
  InternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
      - Key: Name
        Value: VPC-IGW
  # VPCにInternetGatewayをアタッチ
  AttachGateway:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref VPC
      InternetGatewayId: !Ref InternetGateway
```

### ルーティングテーブル
ルーティングテーブルの記述内容は以下です。
PubSubToInternetでパブリックサブネット-インターネット間のルートを作成します。

```yaml
  # ルートテーブルの作成
  PubSubRouteTable:
    Type: AWS::EC2::RouteTable
    DependsOn: AttachGateway
    Properties:
      VpcId: !Ref VPC
      Tags:
      - Key: Name
        Value: PubSubRouteTable
  # PubSub-インターネット間のルーティング
  PubSubToInternet:
    Type: AWS::EC2::Route
    DependsOn: AttachGateway
    Properties:
      RouteTableId: !Ref PubSubRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref InternetGateway
```

### パブリックサブネット
パブリックサブネットの記述内容は以下です。
SubnetRouteTableAssociationで、パブリックサブネットと↑で作成したルートテーブルの関連付けをします。

```yaml
  # パブリックサブネットの作成
  PublicSubnet:
    Type: AWS::EC2::Subnet
    DependsOn: AttachGateway
    Properties:
      CidrBlock: 10.0.1.0/24
      MapPublicIpOnLaunch: 'true'
      VpcId: !Ref VPC
      Tags:
      - Key: Name
        Value: VPC-PublicSubnet
  # パブリックサブネットにルートテーブルを関連付け
  SubnetRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnet
      RouteTableId: !Ref PubSubRouteTable
```

### EC2
EC2の記述内容は以下です。
UserDataに、nginxのインストール・起動設定を記述します。

```yaml
  # EC2の作成
  EC2: 
    Type: AWS::EC2::Instance
    DependsOn: SubnetRouteTableAssociation
    Properties: 
      ImageId: ami-00d101850e971728d
      KeyName: !Ref KeyName
      InstanceType: t2.micro
      NetworkInterfaces: 
        - AssociatePublicIpAddress: "true"
          DeviceIndex: "0"
          SubnetId: !Ref PublicSubnet
          GroupSet:
            - !Ref EC2SG
      # nginxのインストール・起動設定
      UserData: !Base64 |
        #!/bin/bash
        sudo amazon-linux-extras install -y nginx1
        sudo systemctl start nginx
        sudo systemctl enable nginx
      Tags:
          - Key: Name
            Value: ec2-nginx
```

### セキュリティグループ
セキュリティグループの記述内容は以下です。
インバウンドルールで、全ての送信元に対して、httpおよびsshの通信を許可します。

```yaml
  # SGの作成
  EC2SG:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: ec2-sg-cf
      GroupDescription: Allow SSH and HTTP access only MyIP
      VpcId: !Ref VPC
      SecurityGroupIngress:
        # http
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: 0.0.0.0/0
        # ssh
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: 0.0.0.0/0
```

## Outputs

Outputの記述内容は以下です。
作成したEC2インスタンスのパブリックIPを返します。
パブリックIPは、後述の接続確認で使用します。

```yaml
Outputs:
  EC2PublicIP:
    Value: !GetAtt EC2.PublicIp
    Description: Public IP of EC2 instance
```


# 実行
CloudFormationのWebコンソールを開き、スタックの作成をクリックします。
![2022-06-25_19h01_21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/20003ff5-3967-5f5c-7107-d5370c03c3f2.png)

「テンプレートファイルのアップロード」を選択し、「ファイルの選択」をクリックします。
![2022-06-25_19h02_59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/4ed34e8f-7779-3e5f-0228-279ce901e2a1.png)


ファイルを選択したら、次へをクリックします。
![2022-06-25_19h06_49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/cde1d215-af0c-c94a-c643-0184d4b8e06e.png)


スタックの名前を入力します。
パラメータのKeyNameに、EC2へのssh接続で使用するキーペアを選択します。
（キーペアは事前に作成する必要があります）
![2022-06-25_19h07_24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/d6633f3b-2698-ce78-a25a-abe1cddfe217.png)

オプションの設定は何もせずにスルーします。
![2022-06-25_19h08_36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/30c5ae80-bb50-86d3-7501-616df8734f01.png)

確認画面で設定内容を確認し、「スタックの作成」をクリックします。
![2022-06-25_19h12_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/90961685-0f23-c3ed-953f-d88cabe0fc26.png)

実行後、緑文字で「CREATE_COMPLETE」と表示されれば成功です。
<img width="400" alt="2022-06-25_19h19_35.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/04deb60f-8101-34b8-50f9-b8bc35e81641.png">

# 接続確認

作成したEC2インスタンスにNginxがインストールされ、サービスが起動しているか確認します。

↑のコンソール画面の、出力欄に記載されているパブリックIPをコピーします。
<img width="400" alt="2022-06-25_19h23_31.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/6462ac26-019c-63b6-2e25-e247ebb31d14.png">

ブラウザに、「http\://パブリックIP」と入力します。
以下の画面が表示されればOKです。
<img width="400" alt="2022-06-25_19h26_33.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/150d474d-9c7d-3d9d-9ac0-eb86256bd9b0.png">