CloudFormationで起動テンプレートとEC2の構築

## はじめに
CloudFormationで起動テンプレートを構築する資料があまりなかったので、
解説をつけてまとめました。

## 対象者
- AWSの管理コンソールから起動テンプレートを構築された経験がある方
- CloudFormationの知見がある方

## 構築されるもの
- VPC
- InternetGateway
- Subnet
- RouteTable
- EC2
- SecurityGroup
- 起動テンプレート

## 構成図
![aws のコピー (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502753/bd022838-9904-d7e8-4e21-6140dc457066.png)


## セクション説明
|  セクション| 意味  |備考  |
| ---- | ---- | ---- |
|  AWSTemplateFormatVersion  | テンプレートバージョン  | 2010-09-09 であり、現時点で唯一の有効な値 |
|  Description  |  テンプレートを説明するテキスト | ---- |
|  Metadata  | テンプレートバージョン  | ---- |
|  Parameters  |  パラメーターの定義| ---- |
|  Resources  | スタックに含める AWS リソースの宣言 | ---- |
|  Outputs  |  出力値を宣言| 他のスタックでインポートできる|

## 組み込み関数説明
|  組み込み関数| 意味  |備考  |
| ---- | ---- | ---- |
|  Ref  | 指定したパラメータまたはリソースの値| --- |
|  Sub  |  特定した値の入力文字列にある変数の代わりになる| 文字列内に変数を挿入する |
|  GetAtt  |  テンプレートのリソースから属性の値を返す|  --- |

## その他用語説明
### 起動テンプレート
EC2インスタンス起動時に指定するAmazon マシンイメージ (AMI) の ID、インスタンスタイプ、キーペアなどのパラメータを事前に定義し、再利用可能な形で保管するサービス

## テンプレートファイル
下記においてあります。ご自由にお使いください
https://github.com/toyoyuto/cloudformation_template

## テンプレートファイル(解説付き)
``` launchtemplate.yml
AWSTemplateFormatVersion: 
  "2010-09-09"
Description:
  Amazon Web Services LaunchTemplate & Network & server construction
  
Metadata:
  # コンソールでパラメータをグループ化およびソートする方法を定義するメタデータキー
  "AWS::CloudFormation::Interface":
    # パラメーターグループとそのグループに含めるパラメーターの定義
    ParameterGroups: 
      # Project名に関するグループ
      - Label: 
          default: "Project Name Prefix"
        Parameters: 
          - PJPrefix
      # ネットワーク設定に関するグループ
      - Label: 
          default: "Network Configuration"
        # 記述された順番に表示される
        Parameters: 
          - KeyName

# ------------------------------------------------------------#
# Input Parameters
# ------------------------------------------------------------# 
Parameters:
  PJPrefix:
    Type: String
  KeyName:
    Type: "AWS::EC2::KeyPair::KeyName"
  
Resources: 
# ------------------------------------------------------------#
#  VPC
# ------------------------------------------------------------#
# VPC Create
  VPC: 
    Type: "AWS::EC2::VPC"
    Properties:
      CidrBlock: "10.0.0.0/16"
      # VPC に対して DNS 解決がサポートされているか
      EnableDnsSupport: "true"
      # VPC 内に起動されるインスタンスが DNS ホスト名を取得するか
      EnableDnsHostnames: "true"
      # VPC 内に起動されるインスタンスの許可されているテナンシー
      InstanceTenancy: default
      Tags: 
        - Key: Name
          Value: !Sub "${PJPrefix}-vpc"

# InternetGateway Create
  InternetGateway: 
    Type: "AWS::EC2::InternetGateway"
    Properties: 
      Tags: 
        - Key: Name
          Value: !Sub "${PJPrefix}-igw"

# IGW Attach
  InternetGatewayAttachment: 
    Type: "AWS::EC2::VPCGatewayAttachment"
    Properties: 
      InternetGatewayId: !Ref InternetGateway
      VpcId: !Ref VPC 

# ------------------------------------------------------------#
#  Subnet
# ------------------------------------------------------------#          
# Public Subnet Create
  PublicSubnet: 
    Type: "AWS::EC2::Subnet"
    Properties: 
      AvailabilityZone: "ap-northeast-1a"
      CidrBlock:  "10.0.0.0/24"
      VpcId: !Ref VPC 
      Tags: 
        - Key: Name
          Value: !Sub "${PJPrefix}-public-subnet"
                    
# ------------------------------------------------------------#
#  RouteTable
# ------------------------------------------------------------#          
# Public RouteTable Create
  PublicRouteTable: 
    Type: "AWS::EC2::RouteTable"
    Properties: 
      VpcId: !Ref VPC 
      Tags: 
        - Key: Name
          Value: !Sub "${PJPrefix}-public-route"

# ------------------------------------------------------------#
# Routing
# ------------------------------------------------------------# 
# PublicRoute Create
  PublicRoute: 
    Type: "AWS::EC2::Route"
    Properties: 
      RouteTableId: !Ref PublicRouteTable 
      DestinationCidrBlock: "0.0.0.0/0"
      GatewayId: !Ref InternetGateway 

# ------------------------------------------------------------#
# RouteTable Associate
# ------------------------------------------------------------# 
# PublicRouteTable Associate PublicSubnet
  PublicSubnetRouteTableAssociation: 
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties: 
      SubnetId: !Ref PublicSubnet
      RouteTableId: !Ref PublicRouteTable

# ------------------------------------------------------------#
# EC2
# ------------------------------------------------------------#
  # 起動テンプレート
  Ec2InstanceLaunchTemplate:
    Type: AWS::EC2::LaunchTemplate
    Properties:
      # 起動テンプレートの名前
      LaunchTemplateName: !Sub "${PJPrefix}-web-server-template"
      # 起動テンプレートの情報
      LaunchTemplateData:
        # リソースの作成時にリソースに適用するタグを指定
        TagSpecifications:
        # ------------------------------------------------------
        # タグ付けするリソースのタイプ。
        # 現在、作成中のタグ付けをサポートするリソースタイプは、instance および volume 
        # ------------------------------------------------------
        - ResourceType: instance
          Tags:
          - Key: Name
            Value: !Sub "${PJPrefix}-web-server"
        UserData:
          Fn::Base64: |
               #!/bin/bash
               sudo yum -y update
               sudo yum -y install httpd
               sudo systemctl start httpd.service
               sudo systemctl enable httpd.service
        KeyName: !Ref KeyName
        ImageId: ami-01748a72bed07727c
        InstanceType: t2.micro
        NetworkInterfaces: 
        # IPv4 アドレスを割り当てるか
        - AssociatePublicIpAddress: "true"
          # ------------------------------------------------------
          # アタッチの順序におけるネットワークインターフェイスの位置。
          # ネットワークインターフェイスを指定する場合必須
          # ------------------------------------------------------
          DeviceIndex: "0"
          SubnetId: !Ref PublicSubnet
          Groups:
            - !Ref WebServerSG

  # WebServerセキュリティグループ
  WebServerSG:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: web-sg-cf
      GroupDescription: web server sg
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: 0.0.0.0/0
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: 0.0.0.0/0
      Tags:
        - Key: Name
          Value: !Sub "${PJPrefix}-web-server-sg"
  # EC2インスタンス
  Ec2Instance:
    Type: AWS::EC2::Instance
    Properties:
      # 起動テンプレートの設定
      LaunchTemplate:
        # 起動テンプレートのID
        LaunchTemplateId: !Ref 'Ec2InstanceLaunchTemplate'
        # 起動テンプレートのバージョン番号
        Version: !GetAtt 'Ec2InstanceLaunchTemplate.LatestVersionNumber'
      NetworkInterfaces: 
        # IPv4 アドレスを割り当てるか
        - AssociatePublicIpAddress: "true"
          # ------------------------------------------------------
          # アタッチの順序におけるネットワークインターフェイスの位置。
          # ネットワークインターフェイスを指定する場合必須
          # ------------------------------------------------------
          DeviceIndex: "0"
          SubnetId: !Ref PublicSubnet
          GroupSet:
            - !Ref WebServerSG
            
# # # ------------------------------------------------------------#
# # # Output Parameters
# # # ------------------------------------------------------------#                
Outputs:
  VPC:
    Value: !Ref VPC
    Export:
      Name: !Sub "${PJPrefix}-vpc"
  PublicSubnet:
    Value: !Ref PublicSubnet
    Export:
      Name: !Sub "${PJPrefix}-public-subnet"
  Ec2InstanceLaunchTemplate:
    Value: !Ref Ec2InstanceLaunchTemplate
    Export:
      Name: !Sub "${PJPrefix}-web-server-template"
  Ec2Instance:
    Value: !Ref Ec2Instance
    Export:
      Name: !Sub "${PJPrefix}-web-server"

```

## 参考
[CloudFormationに対応したEC2の起動テンプレートを試してみた](https://dev.classmethod.jp/articles/cfn-launch-template-ec2/a)