【AWS】CloudFormationでEC2をデプロイしつつ運用も考える

Terraformに続いてCloudFormationも触ってみたいと思い、とりあえず**EC2**をたててみました。実際にたててみて、**今後どう使っていけばいいか**というポイントも書いておきます:bulb:

## テンプレートの基本構文
突然コードかいてもわかりにくいと思うので、ざっくり書き方だけ記載します。
JSONかYAMLでかけるようですが、今回は**YAML**で記述しました。

#### AWSTemplateFormatVersion:
テンプレート形式のバージョンです。現状では"2010-09-09"と固定で記述すればOK。

#### Description:
その名の通りテンプレートの説明を記載します。

#### Parameters:
入力値を記述します。環境変数みたいなもので、あとからこのコードを流すときに
パラメーターを渡してあげることができます。（どこで渡すかは後述します）

#### Resources:
ここがメイン部分です。実際に構築するリソースを記載します。
**Type**でリソースの種別、**Properties**で実際の設定値を記載します。

#### Outputs:
コードを流した後に出力させるパラメータを記載します。

## 実際のコード

#### VSCode拡張機能
コードを書く前に、以下２つの拡張をぜひ導入しましょう。

**・VS Code Plugin for CloudFormation**
コードの補完とかしてくれます。

**・CloudFormation Linter**
エラーのあぶり出しやってくれます。スタック流さないとエラーがわからないというのはかなりつらいので、必須の拡張機能です。

![スクリーンショット 2023-05-18 5.20.18.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/984662/0d985f09-50ca-55ff-f3b4-1afffc45704f.jpeg)

#### コード
https://qiita.com/tyoshitake/items/c5176c0ef4de8d7cf5d8 から拝借させていただきました。解説用ということでコメント多めにいれてます。

```yaml
AWSTemplateFormatVersion: "2010-09-09"
Description: Provision 

Parameters:
  KeyName: # キーペアはスタック時に入力する
    Description: The EC2 Key Pair to allow SSH access to the instance
    Type: "AWS::EC2::KeyPair::KeyName"

  MyIP: # 変動するものなので外だし。コードを流す時にベット入力する。
    Description: IP address allowd to access EC2
    Type: String

Resources:
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      Tags:
        - Key: Name
          Value: vpc-cf

  IGW:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: igw-cf

# IGWをVPCにアタッチ
  AttachGateway:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref VPC # ID関連は関数Refで取得
      InternetGatewayId: !Ref IGW

  PubSub:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: ap-northeast-1a
      VpcId: !Ref VPC
      CidrBlock: 10.0.1.0/24
      Tags:
        - Key: Name
          Value: pub-sub-a-cf
    
  PubSubRT:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: pub-sub-a-rt-cf
  
  # PubSub-インターネット間のルーティング
  PubSubfToInternet:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref PubSubRT
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref IGW

  # ルートテーブルをサブネットに関連付け
  AssoPubSubRT:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PubSub 
      RouteTableId: !Ref PubSubRT

  EC2:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: ami-00d101850e971728d # AL2のAMI
      KeyName: !Ref KeyName
      InstanceType: t2.micro
      NetworkInterfaces:
        - AssociatePublicIpAddress: "true" # 自動割り当てのパブリックIP
          DeviceIndex: "0" # 自動割り当ての場合０で固定
          SubnetId: !Ref PubSub
          GroupSet:
            - !Ref EC2SG
      UserData: !Base64 | # インスタンス構築時に実行されるスクリプトと必要なエンコード
        #!/bin/bash
        sudo yum install -y git: #gitをインストール
      Tags: 
        - Key: Name
          Value: ec2-a-cf

  EC2SG:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: ec2-sg-cf
      GroupDescription: Allow SSH and HTTP access only MyIP # SSHとHTTPを許可
      VpcId: !Ref VPC
      SecurityGroupIngress:
        # http
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: !Ref MyIP # 自分のIPからだけ許可
        # ssh
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: !Ref MyIP

Outputs:
  EC2PublicIP: # EC2のパブリックIPをスタック後に出力させる
    Value: !GetAtt EC2.PublicIp
    Description: Public IP of EC2 instance
```

## スタックの作成
ここからはAWSコンソール上で実際に上記で作成したコードをCloudFormationに流していきます。

まずはCloudFomationから**スタックの作成**に進みます。ここで選択するのは**新しいリソース**で良いです。
![スクリーンショット 2023-05-18 3.46.45.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/984662/f02534ab-59c0-efe6-966f-3c6fc85ec6b4.jpeg)

#### ①上記で作成したコードを（yaml）をアップロードしてスタックを作成
![スクリーンショット 2023-05-18 3.49.18.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/984662/ed28894e-ffd8-11f9-d4f1-501737fdeadc.jpeg)

#### ②スタックの詳細を設定
ここで**Parameters:** の内容を入力します。IPは利用してるネットワークのIPをいれましょう。ここで注意なのは、IPをいれるときに一緒に**CIDR**もいれてあげる必要があることです。
![スクリーンショット 2023-05-18 3.51.37.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/984662/788c02e3-758d-7703-626d-3ac09014909f.jpeg)

#### ③スタックオプションの設定→送信
特に設定は不要です。特に設定したい項目がなければ次へ進みましょう。その後確認内容が表示されるので、問題なければ送信します。

送信するとイベントが流れます。最終的にスタックの情報からステータスが**CREATE_COMPLETE**になれば完了です！
![スクリーンショット 2023-05-18 4.03.18.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/984662/e71304a3-883e-b41d-07f5-97161a3986b4.jpeg)

#### 補足
・もしスタックが失敗した場合は、**スタックを削除**してから最後スタックを送信する必要があります。
・作成したリソースを削除する場合は、スタックを削除すれば消すことができます。

## 運用するにあたってのポイント
#### AWSコンソール上で操作
導入もクレデンシャルも設定不要なのはやっぱり強いです。**サクッと作ってコード流す**だけならTerraformよりも断然早そうです。

#### スタックの削除
上記でも記載しましたが、スタックが失敗したときに都度消さないといけない&スタックを作り直さないといけないです。CLIを使えば削除は回避できなさそうですが、**スタック入力し直しの手間は省くことができそう**です。

#### ファイル（コード）の分割
今回の手順だと１ファイルしかアップロードできませんが、S3を使った**ネストでファイルの分割**もできるようです。

まだまだCloudformtionの可能性を探って行きます:fire: