AWS ECS ～ demo

#1.CloudFormation　で環境を準備する#

入力する箇所は、次のとおりで他の内容はデフォルトとする。

|キー|バリュー|
|---|---|
|スタックの名前|任意|
|MasterUserName|任意（後でDBで使う。）|
|MasterUserPassword|任意（後でDBで使う）|


```json
{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Description": "VPC Template For Multi-AZ",
  "Parameters": {
    "MasterUserName": {
      "Description": "RDS master user name",
      "Type": "String"
    },
    "MasterUserPassword": {
      "Description": "RDS master user password",
      "Type": "String"
    }
  },
  "Resources": {
    "VPC": {
      "Type"       : "AWS::EC2::VPC",
      "Properties" : {
        "CidrBlock"          : "10.0.0.0/16",
        "InstanceTenancy"    : "default",
        "EnableDnsSupport"   : "true",
        "EnableDnsHostnames" : "false",
        "Tags"               : [ { "Key": "Name", "Value": "SimplechatVPC" } ]
      }
    },
    "eip": {
      "Type"       : "AWS::EC2::EIP",
      "Properties" : { "Domain" : "vpc" }
    },
    "subnetPub1": {
      "Type"       : "AWS::EC2::Subnet",
      "Properties" : {
        "CidrBlock"        : "10.0.0.0/24",
        "AvailabilityZone" : { "Fn::Select" : [ "0", { "Fn::GetAZs" : { "Ref" : "AWS::Region" }}]},
        "VpcId"            : { "Ref": "VPC" },
        "Tags"             : [ { "Key": "Name", "Value": "Public-Subnet-1" } ]
      }
    },
    "subnetPub2": {
      "Type"       : "AWS::EC2::Subnet",
      "Properties" : {
        "CidrBlock"        : "10.0.1.0/24",
        "AvailabilityZone" : { "Fn::Select" : [ "1", { "Fn::GetAZs" : { "Ref" : "AWS::Region" }}]},
        "VpcId"            : { "Ref": "VPC" },
        "Tags"             : [ { "Key": "Name", "Value": "Public-Subnet-2" } ]
      }
    },
    "subnetPrv1": {
      "Type"       : "AWS::EC2::Subnet",
      "Properties" : {
        "CidrBlock"        : "10.0.2.0/24",
        "AvailabilityZone" : { "Fn::Select" : [ "0", { "Fn::GetAZs" : { "Ref" : "AWS::Region" }}]},
        "VpcId"            : { "Ref": "VPC" },
        "Tags"             : [ { "Key": "Name", "Value": "Private-Subnet-1" } ]
      }
    },
    "subnetPrv2": {
      "Type"       : "AWS::EC2::Subnet",
      "Properties" : {
        "CidrBlock"        : "10.0.3.0/24",
        "AvailabilityZone" : { "Fn::Select" : [ "1", { "Fn::GetAZs" : { "Ref" : "AWS::Region" }}]},
        "VpcId"            : { "Ref": "VPC" },
        "Tags"             : [ { "Key": "Name", "Value": "Private-Subnet-2" } ]
      }
    },
    "Nat": {
      "Type"       : "AWS::EC2::NatGateway",
      "Properties" : {
        "AllocationId"     : { "Fn::GetAtt" : ["eip", "AllocationId"] },
        "SubnetId"         : { "Ref" : "subnetPub1" }
      },
      "DependsOn"  : "eip"
    },
    "IGW": {
      "Type"       : "AWS::EC2::InternetGateway",
      "Properties" : {
        "Tags"             : [ { "Key": "Name", "Value": "Simplechat-IG" } ]
      }
    },
    "RouteTablePublic": {
      "Type"           : "AWS::EC2::RouteTable",
      "Properties"     : {
        "VpcId"            : { "Ref": "VPC" },
        "Tags"             : [ { "Key": "Name", "Value": "Public-RT" } ]
      }
    },
    "RouteTablePrivate": {
      "Type"           : "AWS::EC2::RouteTable",
      "Properties"     : {
        "VpcId"            : { "Ref": "VPC" },
        "Tags"             : [ { "Key": "Name", "Value": "Private-RT" } ]
      }
    },
    "gw": {
      "Type"           : "AWS::EC2::VPCGatewayAttachment",
      "Properties"     : {
        "VpcId"             : { "Ref": "VPC" },
        "InternetGatewayId" : { "Ref": "IGW" }
      }
    },
    "subnetRoutePub1": {
      "Type"           : "AWS::EC2::SubnetRouteTableAssociation",
      "Properties"     : {
        "RouteTableId"     : { "Ref": "RouteTablePublic" },
        "SubnetId"         : { "Ref": "subnetPub1" }
      }
    },
    "subnetRoutePub2": {
      "Type"           : "AWS::EC2::SubnetRouteTableAssociation",
      "Properties"     : {
        "RouteTableId"     : { "Ref": "RouteTablePublic" },
        "SubnetId"         : { "Ref": "subnetPub2" }
      }
    },
    "subnetRoutePrv1": {
      "Type"           : "AWS::EC2::SubnetRouteTableAssociation",
      "Properties"     : {
        "RouteTableId"     : { "Ref": "RouteTablePrivate" },
        "SubnetId"         : { "Ref": "subnetPrv1" }
      }
    },
    "subnetRoutePrv2": {
      "Type"           : "AWS::EC2::SubnetRouteTableAssociation",
      "Properties"     : {
        "RouteTableId"     : { "Ref": "RouteTablePrivate" },
        "SubnetId"         : { "Ref": "subnetPrv2" }
      }
    },
    "routePublic": {
      "Type"           : "AWS::EC2::Route",
      "Properties"     : {
        "DestinationCidrBlock"  : "0.0.0.0/0",
        "RouteTableId"          : { "Ref": "RouteTablePublic" },
        "GatewayId"             : { "Ref": "IGW" }
      },
      "DependsOn"      : "gw"
    },
    "routePrivate": {
      "Type"           : "AWS::EC2::Route",
      "Properties"     : {
        "DestinationCidrBlock"  : "0.0.0.0/0",
        "RouteTableId"          : { "Ref": "RouteTablePrivate" },
        "NatGatewayId"          : { "Ref" : "Nat" }
      },
      "DependsOn"      : [ "Nat" , "subnetRoutePrv1", "subnetRoutePrv2" ]
    },
    "LoadBalancerSecurityGroup": {
      "Type" : "AWS::EC2::SecurityGroup",
      "Properties" : {
        "GroupDescription": "simplechat_lb_sg",
        "GroupName" : "simplechat_lb_sg",
        "VpcId": { "Ref" : "VPC" },
        "SecurityGroupIngress" : [
          { "IpProtocol" : "tcp",
            "FromPort" : "80",
            "ToPort" : "80",
            "CidrIp" : "0.0.0.0/0" }
        ]
      }
    },
    "WebServerSecurityGroup": {
      "Type" : "AWS::EC2::SecurityGroup",
      "Properties" : {
        "GroupDescription": "simplechat_web_sg",
        "GroupName" : "simplechat_web_sg",
        "VpcId": { "Ref" : "VPC" },
        "SecurityGroupIngress" : [
          { "IpProtocol" : "tcp",
            "FromPort" : "80",
            "ToPort" : "80",
            "SourceSecurityGroupId" : { "Ref" : "LoadBalancerSecurityGroup" } }
        ]
      }
    },
    "RDSSecurityGroup" : {
      "Type" : "AWS::EC2::SecurityGroup",
      "Properties" : {
        "GroupDescription" : "simplechat_db_sg",
        "GroupName" : "simplechat_db_sg",
        "VpcId" : { "Ref" : "VPC" },
        "SecurityGroupIngress" : [
          { "IpProtocol" : "tcp",
            "FromPort" : "3306",
            "ToPort" : "3306",
            "SourceSecurityGroupId" : { "Ref" : "WebServerSecurityGroup" } }
        ]
      }
    },
    "DbSubnetGroup": {
      "Type": "AWS::RDS::DBSubnetGroup",
      "Properties": {
        "DBSubnetGroupName": "simplechat_db_subnet",
        "DBSubnetGroupDescription": "simplechat_db_subnet",
        "SubnetIds": [ {"Ref": "subnetPrv1"}, {"Ref": "subnetPrv2"} ]
      }
    },
    "DBParameterGroup": {
      "Type": "AWS::RDS::DBParameterGroup",
      "Properties": {
        "Description": "simplechat parameter group",
        "Family": "mysql5.7",
        "Parameters": {
          "character_set_client": "utf8mb4",
          "character_set_connection": "utf8mb4",
          "character_set_database": "utf8mb4",
          "character_set_results": "utf8mb4",
          "character_set_server": "utf8mb4",
          "collation_connection": "utf8mb4_bin",
          "collation_server": "utf8mb4_bin"
        }
      }
    },
    "DbInstance": {
      "Type": "AWS::RDS::DBInstance",
      "Properties": {
        "DBInstanceIdentifier": "simplechat-ecs-db",
        "Engine": "MySQL",
        "EngineVersion": "5.7.22",
        "AllocatedStorage": "5",
        "MasterUsername": { "Ref": "MasterUserName" },
        "MasterUserPassword": { "Ref": "MasterUserPassword" },
        "DBInstanceClass": "db.t2.micro",
        "DBSubnetGroupName": { "Ref": "DbSubnetGroup" },
        "DBParameterGroupName": { "Ref": "DBParameterGroup" },
        "VPCSecurityGroups": [ { "Ref": "RDSSecurityGroup"} ]
      }
    },
    "ALB" : {
      "Type" : "AWS::ElasticLoadBalancingV2::LoadBalancer",
      "Properties" : {
        "LoadBalancerAttributes" : [
          { "Key" : "access_logs.s3.enabled", "Value" : "false" },
          { "Key" : "deletion_protection.enabled", "Value" : "false" },
          { "Key" : "idle_timeout.timeout_seconds", "Value" : "60" }
        ],
        "Name" : "simplechat-alb",
        "Scheme" : "internet-facing",
        "SecurityGroups" : [
          { "Ref": "LoadBalancerSecurityGroup" }
        ],
        "Subnets" : [ {"Ref": "subnetPub1"}, {"Ref": "subnetPub2"} ],
        "Tags" : [
          {"Key": "Name", "Value": "simplechat-alb" }
        ]
      }
    },
    "Cloud9Env": {
      "Type": "AWS::Cloud9::EnvironmentEC2",
      "Properties": {
        "Name": "simplechat_cloud9_env",
        "Description": "simplechat_cloud9_env",
        "AutomaticStopTimeMinutes": "1440",
        "InstanceType": "t2.micro",
        "SubnetId": { "Ref": "subnetPub1" }
      }
    }
  }
}
```



#2.Dockerイメージを登録する#

---

##2-1.Amazon ECR にリポジトリを作成する##

適当なリポジトリ名で、リポジトリを作成する。（設定はデフォルト）

##2-2.Amazon ECR にDockerイメージを登録する##

【「1.CloudFormation　で環境を準備する#」】で、cloud9で**simplechat_cloud9_env** が作成されているので、「Open IDE」を選択し、次のとおりappを展開する。

```
wget https://ecs-for-aws-summit-online.workshop.aws/simplechat_app.tar.gz

tar zxvf simplechat_app.tar.gz

cd simplechat_ecs_app/
```

Amazon ECRから「プッシュコマンドの表示」をクリックし、後は手順どおり、ログイン→ビルド→タグ付け→プッシュする。


```
aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin .dkr.ecr.us-east-1.amazonaws.com

docker build -t simplechat .

docker tag simplechat:latest .dkr.ecr.us-east-1.amazonaws.com/simplechat:latest

docker push .dkr.ecr.us-east-1.amazonaws.com/simplechat:latest
```



#3.Dockerコンテナの作成#

##3-1.クラスターの作成##

「AWS Fargate」を指定。（他の設定はデフォルト）

##3-2.タスク定義##

次のとおり入力していく。
![キャプチャ100.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/6d1a4408-4be6-7c76-3063-75cdbfed8823.png)

イメージは先程作成したAmazon ECRのリポジトリのURIを指定する。ポートマッピングは80にする。
![キャプチャ200.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/c6186233-fca5-8e72-c462-7d153a8dbddc.png)

環境変数を設定する。

|キー|バリュー|
|---|---|
|DB_HOST| RDSインスタンスのURI|
|DB_USER| 【1.CloudFormation　で環境を準備する】で指定したもの|
|DB_PASS| 【1.CloudFormation　で環境を準備する】で指定したもの|

![キャプチャ300.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/65506ac5-7234-e747-c747-e932a16863d7.png)

##3-3.サービス##

次の通り入力する。
![スクリーンショット 2020-09-17 20.08.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/dc70199b-a38d-521e-30cf-84c35e86638e.png)

デプロイメントは[ローリングアップデート](https://qiita.com/NaokiIshimura/items/8e43135864f2518dcabc)
![スクリーンショット 2020-09-17 20.09.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/684fe0e5-46b1-e468-4898-f859b12f56da.png)

次の通りVPCやALBを指定する。
![スクリーンショット 2020-09-17 20.13.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/3eccd239-6b35-e46e-28d0-9eebb36f316d.png)
![スクリーンショット 2020-09-17 20.14.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/607138d6-6a57-ee0d-679e-368e19f3ed3c.png)
![スクリーンショット 2020-09-17 20.15.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/318608ab-24b6-a0c8-75e6-ffabee670b3e.png)

今回AutoScallingは特に設定しない。
![スクリーンショット 2020-09-17 20.16.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/527d8f36-a6e4-d635-b6ff-5bc590256e13.png)

「RUNNING」になったらOKです。
![スクリーンショット 2020-09-17 20.21.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/aedb21a7-6e95-21c7-69b5-ed53567d2ce7.png)


#4.アプリケーションの確認と修正#

ALBのDNS名にアクセスして、アプリケーションを色々触ってみる。

そのあと、Cloud9を開き、アプリケーションの適当な箇所を修正し、「File」から「Save」。その内容が反映されるか確認する。

【2-2.Amazon ECR にDockerイメージを登録する】の手順と同様にログイン→ビルド→タグ付け→プッシュする。
※実際はAmazon ECRのリポジトリにおいて「タグのイミュータビリティ」を「有効にする」に設定し、イメージ更新毎に一意のタグを付けるようにする。
※「タグのイミュータビリティ」→　有効にすると同じタグを上書きができなくなる。

今回は、ECSのサービスで「新しいデプロイの強制」のチェックボックスをオンにだけ変更し、更新する。
![スクリーンショット 2020-09-17 20.36.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/add2d57a-241d-46e5-3a39-28cb100ef93f.png)

タスクは2つになるはずですがしばらくすると、1つになります。（ローリングアップデート）

最後にalbのDNSにアクセスし、変更が反映されたか確認する。


#リンク#
[Amazon ECSネットワークモードを検証してみる](https://qiita.com/leomaro7/private/41c5dfb88ca48e5a3962)
[Amazon ECS 細かい箇所を整理してみた](https://qiita.com/leomaro7/items/6afd607f2df39f714a8e)