Fargate(BGDeploy)+Rails：Deploy設定編

#概要
ECS上でコンテナ化したRailsアプリをデプロイ
（ダラダラ書いてるので分割予定）

ECSの設定は以下で
https://qiita.com/kinoshita-yu/items/5ea52b922b877813e806

#前提
・GitHub
・rails
・RDS
・ECS(Fargate)


#構成図

![リリース手順.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309388/b400052d-a54d-1d0c-25d8-affe35cbf49c.jpeg)


#設定

##CodeBuild設定

###AWS側の対応

CodePipelineと同時に行うのでこの節での記述は割愛

###ブランチ側の対応

以下のイメージビルド用の定義を作成し、ブランチの直下に配置
<details><summary>docker-compose-aws.yml</summary><div>

```
version: '3'
volumes:
  unuse:
services:
  web: &app_base
    env_file: .env
    image: ${WEB_IMAGE:「イメージ名」/「システム名」:latest}
    build: .
    ports:
      - "3000:3000"
    command: /bin/sh -c 'rm -f /「システム名」/tmp/pids/server.pid && rails s -p 3000 -b 0.0.0.0'
```

</div></details>


migrate用のタスク定義を作成し、ブランチの直下に配置
<details><summary> migrate-compose.yml</summary><div>

```
version: '3'
services:
  web:
    logging:
      driver: "awslogs"
      options:
        awslogs-group: "/ecs/XXX-app"
        awslogs-region: "ap-northeast-1"
        awslogs-stream-prefix: "XXX-app-migrate"
    image: XXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/XXX/app:XXXXXXXXX
    command: ["/bin/sh", "-c", "rake db:migrate"]
```

</div></details>




##CodeDeploy設定

###AWS側の対応：アプリケーションの作成
|設定項目|設定内容|
|:-:|:-:|
|アプリケーション名|任意| 
|コンピューティングプラットフォーム|Amazon ECS| 

###AWS側の対応：デプロイグループの作成

※サービスロールは https://qiita.com/kinoshita-yu/items/5ea52b922b877813e806#codedeploy%E7%94%A8%E3%81%AE%E3%83%AD%E3%83%BC%E3%83%AB%E4%BD%9C%E6%88%90 で作成したロール

|設定項目|設定内容|
|:-:|:-:|
|デプロイグループ名|任意| 
|サービスロール|作成したロール| 
|ECSクラスタ名|デプロイ対象クラスタ| 
|ECSサービス名|デプロイ対象サービス| 
|ロードバランサ|デプロイ対象が属しているロードバランサー| 
|本稼働リスナーポート|上記のリスナーポート| 
|テストリスナーポート|上記のリスナーポート| 
|ターゲットグループ１|上記のターゲットグループ| 
|ターゲットグループ２|上記のターゲットグループ| 
|トラフィックの再ルーティング|任意| 
|元のリビジョンの終了|任意| 


###ブランチ側の対応

BGデプロイ用の定義ファイルを作成し、ブランチの直下に配置
<details><summary>appspec.yaml</summary><div>

```
version: 0.0
Resources:
  - TargetService:
      Type: AWS::ECS::Service
      Properties:
        TaskDefinition: <TASK_DEFINITION>
        LoadBalancerInfo:
          ContainerName: "XXX-app"
          ContainerPort: 3000
```

</div></details>


<details><summary>ecs-params.yml</summary><div>

```
version: 1
task_definition:
  task_execution_role: ecsTaskExecutionRole
  ecs_network_mode: awsvpc
  task_size:
    mem_limit: 2048
    cpu_limit: 1024
  services:
    web:
      secrets:
        - value_from: "/XXX/RAILS_ENV"
          name: "RAILS_ENV"
        - value_from: "/XXX/APP_DATABASE_HOST"
          name: "APP_DATABASE_HOST"
        - value_from: "/XXX/APP_DATABASE_NAME"
          name: "APP_DATABASE_NAME"
        - value_from: "/XXX/APP_DATABASE_PASSWORD"
          name: "APP_DATABASE_PASSWORD"
        - value_from: "/XXX/APP_DATABASE_USER"
          name: "APP_DATABASE_USER"
run_params:
  network_configuration:
    awsvpc_configuration:
      subnets:
        - "subnet-XXXXX"
        - "subnet-YYYYY"
      security_groups:
        -  "sg-AAAAA"
        -  "sg-BBBBB"
        -  "sg-CCCCC"
        -  "sg-DDDDD"
      assign_public_ip: ENABLED
```

</div></details>

<details><summary>taskdef.json</summary><div>

```
{
  "taskRoleArn": "arn:aws:iam::XXXXXXXXXX:role/ecs_XXX",
  "executionRoleArn": "arn:aws:iam::XXXXXXXXXX:role/ecs_XXX",
  "containerDefinitions": [
    {
      "name": "XXX-app",
      "image": "<IMAGE1_NAME>",

      "secrets": [
        {
          "valueFrom": "/XXX/RAILS_ENV",
          "name": "RAILS_ENV"
        },
        {
          "valueFrom": "/XXX/APP_DATABASE_HOST",
          "name": "APP_DATABASE_HOST"
        },
        {
          "valueFrom": "/XXX/APP_DATABASE_NAME",
          "name": "APP_DATABASE_NAME"
        },
        {
          "valueFrom": "/XXX/APP_DATABASE_PASSWORD",
          "name": "APP_DATABASE_PASSWORD"
        },
        {
          "valueFrom": "/XXX/APP_DATABASE_USER",
          "name": "APP_DATABASE_USER"
        },
      ],

      "command": ["/bin/sh", "-c", "rm -f /XXX/tmp/pids/server.pid && rails s -p 3000 -b 0.0.0.0"],
      "logConfiguration": {
        "logDriver": "awslogs",
        "secretOptions": null,
        "options": {
          "awslogs-group": "/ecs/XXX-app",
          "awslogs-region": "ap-northeast-1",
          "awslogs-stream-prefix": "ecs"
        }
      },
      "portMappings": [
        {
          "containerPort": 3000,
          "hostPort": 3000,
          "protocol": "tcp"
        }
      ],
      "essential": true
    }
  ],
  "requiresCompatibilities": ["FARGATE"],
  "networkMode": "awsvpc",
  "cpu": "1024",
  "memory": "2048",
  "family": "XXX"
}

```

</div></details>

※ロードバランサの設定を変更した場合、デプロイグループの設定に自動反映はされないため、気をつけること



##CodePipeLine作成
1. https://ap-northeast-1.console.aws.amazon.com/codesuite/codepipeline/pipelines?region=ap-northeast-1 に移動
1. 「パイプラインを作成する」をクリック

###「パイプラインの設定を選択する」画面
1. 任意の「パイプライン名」を入力
1. 他の項目は特に変更せず「次へ」をクリック

※作成されたロールは全権限が付与されているので、必要なものだけに絞っておく

###「ソースステージを追加する」画面

1. 以下のように設定を行う

|設定項目|設定内容|
|:-:|:-:|
|ソースプロバイダ|Amazon ECR| 
|リポジトリ名|デプロイ対象のECRリポジトリ| 
|画像タグ|デプロイ対象ECRイメージタグ|

####「ビルドステージを追加する」画面
1. 「プロバイダーを構築する」に「AWS CodeBuild」を選択
1. 「リージョン」で利用するリージョンを選択
1. 「プロジェクト名」で「プロジェクトを作成する」をクリック

####「ビルドプロジェクトを作成する」画面

1. 以下のように設定を行う

|設定項目|設定内容|
|:-:|:-:|
|プロジェクト名|任意| 
|説明|任意| 
|環境イメージ|マネージド型イメージ|
|オペレーティングシステム|Amazon Linux2| 
|ランタイム|Standard| 
|イメージ|選択肢の中から任意| 
|イメージのバージョン|選択肢の中から任意|
|特権付与|チェックしない|
|サービスロール|既存のサービスロール|
|Role Arn|作成したCodeDeploy用のロール|
|ビルド仕様|※1参照|
|CloudWatch Logs - オプショナル|チェックを入れる|
|グループ名|任意|
|ストリーム名|任意|

※1 選択により対応内容が変わる
「buildspec ファイルを使用する」場合は以下のymlをブランチ直下に配置
「ビルドコマンドの挿入」の場合は以下のymlの内容を直接記述

<details><summary> buildspec.yml</summary><div>

```
version: 0.2

phases:
  install:
    runtime-versions:
      docker: 18
  pre_build:
    commands:
      - echo Logging in to Amazon ECR...
      - $(aws ecr get-login --no-include-email --region ap-northeast-1)
  build:
    commands:
      - echo Building the Docker image...
      - docker build  -f docker-compose-aws.yml -t xxxxx .
      - docker tag docker_test:latest XXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/XXXXX:latest
  post_build:
    commands:
      - echo Pushing the Docker image...
      - docker push XXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/xxxxx:latest
      - echo Writing image definitions file...
      - printf '{"Version":"1.0","ImageURI":"%s"}' XXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/xxxxx:latest > imageDetail.json
      - ecs-cli compose -f migrate-compose.yml  --ecs-params ecs-params.yml --project-name xxxxx-migrate up --cluster xxxxx --region ap-northeast-1 --launch-type FARGATE
artifacts:
  files:
    - imageDetail.json
```

</div></details>

### 「デプロイステージを追加する」画面

1. 「デプロイプロバイダー」に「AWS CodeDeploy」を選択
1. 「リージョン」で利用するリージョンを選択
1. 「アプリケーション名」で作成したアプリケーションの名前を選択
1. 「デプロイグループ」で作成したデプロイグループの名前を選択
1. 「次に」をクリック

### 「レビュー」画面

1. 「パイプラインを作成する」をクリック

|設定項目|設定内容|
|:-:|:-:|
|アクション名|任意 |
|アクションプロバイダ|Amazon S3| 
|バケット|gitlab-ciからのsetting.zipコピー先|
|S3オブジェクトキー|gitlab-ciで作成したsetting.zip|
|検出オプションを変更する|Amazon CloudWatch Events|
|出力アーティファクト|SettingArtifact|

##Buildの設定編集

1. https://ap-northeast-1.console.aws.amazon.com/codesuite/codepipeline/pipelines?region=ap-northeast-1 に移動
1. 作成したパイプラインをクリック
1. 「編集する」をクリック
2. 「編集する：Build」の「ステージを編集する」をクリック
3. 対象のBuildの編集マークをクリック
4. 以下のように設定

|設定項目|設定内容|
|:-:|:-:|
|入力アーティファクト|SourceArtifact| 
|出力アーティファクト|BuildArtifact|
※上記以外は修正なし

##Deployの設定編集

1. https://ap-northeast-1.console.aws.amazon.com/codesuite/codepipeline/pipelines?region=ap-northeast-1 に移動
1. 作成したパイプラインをクリック
1. 「編集する」をクリック
2. 「編集する：Deploy」の「ステージを編集する」をクリック
3. 対象のDeployの編集マークをクリック
4. 以下のように設定

|設定項目|設定内容|
|:-:|:-:|
|アクション名|変更なし |
|アクションプロバイダ|Amazon ECS(ブルー/グリーン)|
|リージョン|変更なし|  
|入力アーティファクト|SourceArtifact|  
|入力アーティファクトその２|BuildArtifact|  
|AWS CodeDeploy アプリケーション名|作成したもの|  
|AWS CodeDeploy デプロイグループ|作成したもの| 
|Amazon ECS タスク定義|SourceArtifact ※1|  
|AWS CodeDeploy AppSpec ファイル|SourceArtifact ※2|  
|入力アーティファクトを持つイメージの詳細|BuildArtifact|  
|タスク定義のプレースホルダー文字|IMAGE1_NAME|   

※1 デフォルトでtaskdef.json
※2 デフォルトでappspec.yaml