EC2 CloudFormation

## EC2 CloudFormationの例

この記事では、CloudFormationを使用してEC2の構築するときの実際的な例をいくつか紹介したいと思います。CloudFormation、EC2、EIP、VPC、およびVPCについてある程度の知識が必要です。この記事ではYAMLも使用していますので、その構文に精通している必要があります。以下の項目についてYAMLファイルを書いて説明します。

- 既存のVPCを利用してInstance作成
- セキュリティグループを作成
- Elastic IPを作成してEC2インスタンスに接続する
- CloudFormationのEC2インスタンス
- VPC作成（public及びprivateサブネット）

## EC2 Instances in CloudFormation

`AWS::EC2::Instance`リソースは EC2 インスタンスを作成する際に利用します。
[ドキュメント](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-instance.html)を参照すると、ImageIdは必須パラメータがであることがわかります。

`ImageId` プロパティは、インスタンスのために使用されるAMIを指します。
例えば `ami-0c3fd0f5d33134a76` では、HVM仮想化を使用するAmazon Linux 2 AMI (HVM)イメージであるAMIとインスタンスストア用のEBSバックアップSSDドライブ `hvm：ebs-ssd` を使用するために指定できるパラメタです。

#### 既存のVPCを利用してInstance作成

この例では、既存のVPCを利用してInstance作ることを説明します。SecurityGroupIdsそしてSubnetIdのプロパティを含める必要があります。

- SecurityGroupIdsはインスタンスが属するVPCセキュリティグループのリストです。
- SubnetId インスタンスをVPC内の特定のサブネットと対応するAvailabilityZoneに配置します。

すでに作成されているKeyName（キー）を再利用できるように、インスタンスにも設定したいと思います。
InstanceTypeプロパティも設定することができます。[利用可能なインスタンスタイプ](https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/instance-types.html#AvailableInstanceTypes) を参照はこちらにしてください。インスタンスタイプはEC2のためのt2.nano、t2.microおよびt2.smallみたいな感じで選べることができます。

##### 既存のVPCを利用してInstanceを作るテンプレート例

```yaml


AWSTemplateFormatVersion: "2010-09-09"  
Resources:  
  WebInstance:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: t2.micro
      ImageId: ami-0c3fd0f5d33134a76
      KeyName: my-key
      SecurityGroupIds:
        - sg-sctv01234
      SubnetId: subnet-sctv01234
```


#### インスタンスにタグつける

インスタンス名を設定するために `Tag` 属性を使って`Key` と `value`にpropertyを入れる。これでTagつけることができます。

#####　Tagの例：

```yaml

AWSTemplateFormatVersion: "2010-09-09"  
Resources:  
  WebInstance:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: t2.micro
      ImageId: ami-0c3fd0f5d33134a76
      KeyName: my-key
      SecurityGroupIds:
        - sg-sctv01234
      SubnetId: subnet-sctv01234
      Tags:
        -
          Key: Name
          Value: sctvーwebserver
```

#####　拡張モニタリングを有効にする方法

もう1つやりたいのは、拡張モニタリングを有効にすることです。Monitoringのプロパティが`true`に設定することによって拡張モニタリングすることができます。

```yaml
AWSTemplateFormatVersion: "2010-09-09"  
Resources:  
  WebInstance:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: t2.micro
      ImageId: ami-0c3fd0f5d33134a76
      KeyName: my-key
      Monitoring: true
      SecurityGroupIds:
        - sg-sctv01234
      SubnetId: subnet-sctv01234
      Tags:
        -
          Key: Name
          Value: sctvーwebserver
```

####　削除保護の設定する方法

もう一つのベストプラクティスとして、リソースの誤った除去を防ぐために削除保護を有効にすることです。これはCloudFormationテンプレートにも同様に当てはまり、誤って本番用サーバーのスタック全体を一掃する可能性があります。
`DisableApiTermination`のプロパティが`true`に設定することによって、削除保護を有効にすることができる。

```yaml
AWSTemplateFormatVersion: "2010-09-09"  
Resources:  
  WebInstance:
    Type: AWS::EC2::Instance
    Properties:
      DisableApiTermination: true
      InstanceType: t2.micro
      ImageId: ami-0c3fd0f5d33134a76
      KeyName: my-key
      Monitoring: true
      SecurityGroupIds:
        - sg-sctv01234
      SubnetId: subnet-sctv01234
      Tags:
        -
          Key: Name
          Value: sctvーwebserver
```

DisableApiTerminationをtrueにすると、ロールバック操作中にインスタンスが削除またはクリーンアップすることができなくなります。何らかの理由でスタックを削除しようとするときは、スタックを削除する前に手動で削除保護を無効にする必要になります。

## CloudFormationのセキュリティグループ
セキュリティグループを作成するには、`AWS::EC2::SecurityGroup` リソースを使用します。
- VpcId：VPCのIDを指定。
- SecurityGroupIngress
- Amazon EC2 セキュリティグループの Ingress ルールのリスト。

すべてのIPv4アドレスに対してポート80と443ポートを開けるためのテンプレートです。

```yaml

AWSTemplateFormatVersion: "2010-09-09"  
Resources:  
  WebSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: sctv Webserver
      GroupName: web     
      VpcId: vpc-sctv01234
      SecurityGroupIngress:
        -
          IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: 0.0.0.0/0
        -
          IpProtocol: tcp
          FromPort: 443
          ToPort: 443
          CidrIp: 0.0.0.0/0
```
`CidrIP`代わりに`SourceSecurityGroupId`が指定することができます。これにより、指定したセキュリティグループに属するリソースからの接続が許可されます。

例えば、WebSecurityGroupからDatabaseSecurityGroupの3306ポートへのtcpアクセス許可するような設定を行うことができます。

```yaml

AWSTemplateFormatVersion: "2010-09-09"  
Resources:  
  DatabaseSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: SCTV Database server
      GroupName: database     
      VpcId: vpc-sctv01234
      SecurityGroupIngress:
        -
          IpProtocol: tcp
          FromPort: 3306
          ToPort: 3306
          SourceSecurityGroupId: sg-sctv01234
```

WebSecurityGroupとDatabaseSecurityGroupて同じテンプレートにしている場合`Ref`を使用してWebSecurityGroupのリソースを参照できるように設定する方法もできます。

```yaml

AWSTemplateFormatVersion: "2010-09-09"  
Resources:  
  WebSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Web server
      GroupName: web     
      VpcId: vpc-sctv01234
      SecurityGroupIngress:
        -
          IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: 0.0.0.0/0

  DatabaseSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: SCTV Database server
      GroupName: database     
      VpcId: vpc-sctv01234
      SecurityGroupIngress:
        -
          IpProtocol: tcp
          FromPort: 3306
          ToPort: 3306
          SourceSecurityGroupId: !Ref WebSecurityGroup
```

Refの使用すると別のリソースや指定したパラメータの値を参照することができます。

##セキュリティグループとEC2の連携

セキュリティグループ付きのEC2インスタンスをcloudformationで作成する例を見ましょう。この例では新規security groupを作成して、Instance作成するときにRefを使用してセキュリティグループの参照するようにYaml書くことができます。

```yaml

AWSTemplateFormatVersion: "2010-09-09"  
Resources:  
  WebSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Web server
      GroupName: web     
      VpcId: vpc-abc01234
      SecurityGroupIngress:
        -
          IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: 0.0.0.0/0

  WebInstance:
    Type: AWS::EC2::Instance
    Properties:
      AvailabilityZone: ap-northeast-1
      InstanceType: t2.micro
      ImageId: ami-0c3fd0f5d33134a76
      KeyName: my-key
      SecurityGroupIds:
        - !Ref WebSecurityGroup
      SubnetId: subnet-sctv01234
```

今回の例では、SecurityGroupをWebInstanceに付属させることができました。

##EIP
ElasticIPをEC2インスタンスにアタッチすることで固定なIPアドレスを作成することができる。
EIPをcloudformationで書くときは`AWS::EC2::EIP`リソースを使用して、２つのプロパティを定義します。

- InstanceId: EIPを割り当てるインスタンスへの参照
- Domain: vpcに設定する。　
それでおしまい。これは次のようなものです。

```yaml

AWSTemplateFormatVersion: "2010-09-09"  
Resources:  
  WebInstance:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: t2.nano
      ImageId: ami-0c3fd0f5d33134a76
      KeyName: my-key
      SecurityGroupIds:
        - sg-sctv01234
      SubnetId: subnet-sctv01234

  ElasticIp:
    Type: AWS::EC2::EIP
    Properties:
      InstanceId: !Ref WebInstance
      Domain: vpc
```

## SecurityGroupとEC2インスタンスとEIPの連携。

最後の例になりますが上で説明してた全てのリソースを作成できるように同じテンプレート書いて見ましょう。
1. セキュリティグループを作成する
2. EC2インスタンスを作成する
3. インスタンスにElastic IPをアタッチする

```yaml


AWSTemplateFormatVersion: "2010-09-09"  
Resources:
  ## 全てのIPアドレスから８０ポートへアクセス許可する
  WebSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Sctv Web server
      GroupName: web     
      VpcId: vpc-sctv01234
      SecurityGroupIngress:
        -
          IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: 0.0.0.0/0

  WebInstance:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: t2.micro
      ImageId: ami-0c3fd0f5d33134a76
      KeyName: my-key
   ## keyNameは既存で発行済みにキーを使う時利用する
      Monitoring: true
      SecurityGroupIds:
        - !Ref WebSecurityGroup
      SubnetId: subnet-sctv01234
      Tags:
        -
          Key: Name
          Value: sctvーwebserver     

  ## インスタンスにElastic IPをアタッチする
  WebElasticIp:
    Type: AWS::EC2::EIP
    Properties:
      InstanceId: !Ref WebInstance
      Domain: vpc

```


##VPC作成（public及びprivateサブネット）

最後には少し細かい部分になりますが、VPC内にpublicとprivateサブネット類を作成しをしてt2.microでEC２インスタンスを作成するCloudFormationのサンプルです。

```yaml

AWSTemplateFormatVersion: 2010-09-09
Description: Create AWS CloudFormation Customize Virtual Private Cloud

Resources:
## VPCの作成をする
  VPC:
    Type: 'AWS::EC2::VPC'
    Properties:
      CidrBlock: 10.0.0.0/16
      EnableDnsSupport: 'true'
      EnableDnsHostnames: 'true'
      Tags:
        - Key: Name
          Value: example-vpc
## MultiAZに配置するための複数のPublicサブネット(SubnetPublic1aとSubnetPublic１d)の作成
  SubnetPublic1a:
    Type: 'AWS::EC2::Subnet'
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: ap-northeast-1a
      CidrBlock: 10.0.1.0/24
      MapPublicIpOnLaunch: true

  SubnetPublic1d:
    Type: 'AWS::EC2::Subnet'
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: ap-northeast-1d
      CidrBlock: 10.0.2.0/24
      MapPublicIpOnLaunch: true
## MultiAZに配置するための複数のPrivateサブネット(SubnetPrivate1aとSubnetPrivate１d)の作成
  SubnetPrivate1a:
    Type: 'AWS::EC2::Subnet'
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: ap-northeast-1a
      CidrBlock: 10.0.3.0/24
      MapPublicIpOnLaunch: false
      Tags:
        - Key: Name
          Value: example-vpc-private-subnet-1a

  SubnetPrivate1d:
    Type: 'AWS::EC2::Subnet'
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: ap-northeast-1d
      CidrBlock: 10.0.4.0/24
      MapPublicIpOnLaunch: false
      Tags:
        - Key: Name
          Value: example-vpc-private-subnet-1d
## InternetGatewayの作成
  InternetGateway:
    Type: 'AWS::EC2::InternetGateway'
    Properties:
      Tags:
        - Key: Name
          Value: example-vpc-igwg

## VPC にゲートウェイをアタッチします。
  GatewayToInternet:
    Type: 'AWS::EC2::VPCGatewayAttachment'
    Properties:
      VpcId: !Ref VPC
      InternetGatewayId: !Ref InternetGateway
## VPC内に新しいルートテーブルの作成
  PublicRouteTable:
    Type: 'AWS::EC2::RouteTable'
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Application
          Value: !Ref 'AWS::StackId'
        - Key: Network
          Value: Public

  PublicRoute:
    Type: 'AWS::EC2::Route'
    DependsOn: GatewayToInternet
    Properties:
      RouteTableId: !Ref PublicRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref InternetGateway

## サブネットをルートテーブルに関連付ける
  PublicSubnetRouteTableAssociatio1a:
    Type: 'AWS::EC2::SubnetRouteTableAssociation'
    Properties:
      SubnetId: !Ref SubnetPublic1a
      RouteTableId: !Ref PublicRouteTable

  PublicSubnetRouteTableAssociation1c:
    Type: 'AWS::EC2::SubnetRouteTableAssociation'
    Properties:
      SubnetId: !Ref SubnetPublic1c
      RouteTableId: !Ref PublicRouteTable

## Vpcに新しいネットワークACLの作成
  PublicNetworkAcl:
    Type: 'AWS::EC2::NetworkAcl'
    Properties:
      VpcId: !Ref VPC

  PublicNetworkAclEntry:
    Type: 'AWS::EC2::NetworkAclEntry'
    Properties:
      CidrBlock: 10.0.0.0/16
      Egress: 'true'
      NetworkAclId: !Ref PublicNetworkAcl
      Protocol: '-1'
      RuleAction: allow
      RuleNumber: '100'

  PublicSubnetNetworkAclAssociatio1a:
    Type: 'AWS::EC2::SubnetNetworkAclAssociation'
    Properties:
      SubnetId: !Ref SubnetPublic1a
      NetworkAclId: !Ref PublicNetworkAcl

  PublicSubnetNetworkAclAssociatio1c:
    Type: 'AWS::EC2::SubnetNetworkAclAssociation'
    Properties:
      SubnetId: !Ref SubnetPublic1c
      NetworkAclId: !Ref PublicNetworkAcl

## SecurityGroupの作成
  InstanceSecurityGroup:
    Type: 'AWS::EC2::SecurityGroup'
    Properties:
      VpcId: !Ref VPC
      GroupDescription: Enable SSH access via port 22
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: '22'
          ToPort: '22'
          CidrIp: 10.0.0.0/16

## EC2インスタンスの作成
  EC2Instance:
    Type: 'AWS::EC2::Instance'
    Properties:
      ImageId: ami-0c3fd0f5d33134a76
      SecurityGroupIds:
        - !Ref InstanceSecurityGroup
      SubnetId: !Ref SubnetPrivate1a
      InstanceType: !Ref InstanceType
      KeyName: !Ref KeyName
      Tags:
        - Key: Application
          Value: string
        - Key: Name
          Value: !Ref NameTags


```

## 参考サイト


https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-instance.html
https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-security-group.html
http://docs.aws.amazon.com/ja_jp/AmazonVPC/latest/UserGuide/VPC_Subnets.html
http://docs.aws.amazon.com/ja_jp/AmazonVPC/latest/UserGuide/VPC_Route_Tables.html#RouteTables