docker-compose.ymlでのECSタスク定義方法

2020/7にdokcer-compose形式のyamlファイルからECSのタスク定義ができるようになったのですが、まだまだ実用している例が少なかったので、実際にwebアプリケーションのデプロイ時に作成した際の注意点を残しておきます。Fargateインスタンスタイプでの利用例となります。

## 前提
docker-compose形式のファイルでタスク定義する際には、下記のファイルが必要になります。

- docker-compose.yml  
    - コンテナ定義を行うためのファイル。通常のDocker利用時とほとんど同じだが、一部ECSで対応していない項目があるため、ECS用に修正する必要がある。
     
- ecs-params.yml
    - docker-compose.ymlだけでは設定しきれないタスク、サービスの設定を行う。

## 設定例
今回作成したアプリケーションは、db, api(Django), nginx, vueの4コンテナで構成されます。

### docker-compose.yml
```yaml:docker-compose.yml
version: '3'

services:
  db:
    image: postgres
    ports: 
      - "5432:5432"
    environment:
      - POSTGRES_DB=postgres
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=postgres
    volumes:
      - db_efs:/var/lib/postgresql/data
    logging:
      driver: awslogs
      options: 
          awslogs-group: test
          awslogs-region: ap-northeast-1
          awslogs-stream-prefix: db
  api:
    image: [ECRのイメージURL]:[タグ名]
    command: /bin/sh -c "
      ./entrypoint.sh;"
    env_file:
      - ./api/.env
    ports:
      - 8000:8000
    logging:
      driver: awslogs
      options: 
          awslogs-group: test
          awslogs-region: ap-northeast-1
          awslogs-stream-prefix: api 
  vue:
    image: [ECRのイメージURL]:[タグ名]
    ports:
      - "8080:8080"
    logging:
      driver: awslogs
      options: 
          awslogs-group: test
          awslogs-region: ap-northeast-1
          awslogs-stream-prefix: vue 
  nginx: [ECRのイメージURL]:[タグ名]
    image: 
    ports:
      - 80:80
    logging:
      driver: awslogs
      options: 
          awslogs-group: test
          awslogs-region: ap-northeast-1
          awslogs-stream-prefix: nginx 

volumes:
  db_efs:
  
```

### ecs-params.yml
```yaml:ecs-params.yml
version: 1
task_definition:
  task_execution_role: ecsTaskExecutionRole
  ecs_network_mode: awsvpc
  task_size:
    mem_limit: 0.5GB
    cpu_limit: 256
  services:
    db:
      essential: true
      healthcheck:
        test: ["CMD-SHELL", "pg_isready -U postgres"]
        interval: 10s
        timeout: 5s
        retries: 5
    api:
      essential: true
      depends_on:
        - container_name: db
          condition: HEALTHY
    vue:
      essential: true
    nginx:
      essential: true
      depends_on:
        - container_name: api
          condition: START
  efs_volumes:
    - name: db_efs
      filesystem_id: [EFS ID]
run_params:
  network_configuration:
    awsvpc_configuration:
      subnets:
        - "サブネットID"
        - "サブネットID"
      security_groups:
        - "セキュリティグループ名"
      assign_public_ip: ENABLED
```

## 注意点
下記の点に注意が必要です。

### イメージの利用
ECSではdocker-coompose.ymlのbuild項目がサポートされておらず、必ずECRやdocker-hubにあるイメージをpullする形となります。

```yaml
image: [ECRのイメージURL]:[タグ名]
```

### コンテナ間の依存関係
ECSではdocker-composeでのdepends_onがサポートされていません。
代わりに、ecs-params.ymlに記載します。この際、コンテナ間の依存関係はヘルスチェックの状態に基づいて定義します。

```yaml
    api:
      essential: true
      depends_on:
        - container_name: db
          condition: HEALTHY
```
```yaml
    db:
      essential: true
      healthcheck:
        test: ["CMD-SHELL", "pg_isready -U postgres"]
        interval: 10s
        timeout: 5s
        retries: 5
```
上記のように設定することで、dbコンテナでは起動時にヘルスチェックが行われ、dbコンテナがHEALTHY状態になってからapiコンテナが起動するという依存関係を定義することができます。

### EFS Volumeの利用
Fargateインスタンスタイプで永続ボリュームを利用する際は、EFSをマウントさせる必要があります。
ecs-params.ymlで下記を記載することで、あらかじめ作成しておいたEFSをマウントさせることができ、

```yaml
  efs_volumes:
    - name: db_efs
      filesystem_id: [EFS ID]
```

下記のようにdocker-compose.ymlからvolumesを指定することができます。

```yaml
services:
  db:
    image: postgres
    volumes:
      - db_efs:/var/lib/postgresql/data

volumes:
  db_efs:
```


### Cloudwatch Logsの利用
Cloudwatch Logsと連携させることで、コンテナのログを出力させることができます。
例えば、docker-compose.ymlのdbコンテナの設定で下記を記載することで、
testロググループが作成され、dbというprefixでログが記録されます。

```yaml
  db:
    logging:
      driver: awslogs
      options: 
          awslogs-group: test
          awslogs-region: ap-northeast-1
          awslogs-stream-prefix: db
```

## サービスのデプロイ
上記のファイルを用意した後は、下記コマンドでデプロイを行います。
この際に、ELBでターゲットとなるtargetGroupを指定しています。
ecs-params.ymlは、このファイル名にしておくとデフォルトで設定ファイルとして選択されます。

```shell
ecs-cli compose \
--file docker-compose.yml \
--project-name test service up \
--create-log-groups \
--cluster-config test \
--ecs-profile test-profile \
--target-groups targetGroupArn=[targetGroupのARN],containerName=vue,containerPort=8080 \
--target-groups targetGroupArn=[targetGroupのARN],containerName=nginx,containerPort=80
```