terraformとecs-cliを使ってデプロイ

# はじめに
terraformでecsのタスクを作成する場合、ecsのタスク定義を書く必要がありますが、docker-compose.ymlを再度ecs用に書き直す感じがどうにも気が乗りませんでした。
なので、ecs-cliを使ってdocker-compose.ymlを利用しつつ、terraformも活用する方法の例です。

イメージとしては、terraformでvpc、サブネット、セキュリティグループ、ALB、ターゲットグループ、ecsのクラスターを作成し、ecs-cliでecsのサービス、タスクを作成する感じです。また作成したタスクは既存のターゲットグループにひもづくようにします。

terraformで各リソースを作成する手順は[この本](https://www.amazon.co.jp/dp/B07XT7LJLC/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1)が参考になります。

以下からはterraformでのリソース作成は終わってる前提です。

# ecs-cliの設定
まず、terraformで作成したecsのクラスターに対してecs-cli configureコマンドを実行します。
以降のecs-cliコマンドがここで指定したclusterに対して実行されるようになります。
また、ecsはec2とfargateのどちらかを選べますが、ここではfargateを選んでいます。

```terminal
$ ecs-cli configure \
--cluster <作成したclusterを指定> \
--region ap-northeast-1 \
--default-launch-type FARGATE
```

# タスク定義の元を作成
まずタスク定義の元となるdocker-compose.ymlです。
appが実際のアプリケーションのコードで、リバースプロキシとしてnginxのイメージがあるような構成です。
最終的にはnginxのポート80をコンテナのポートとしていきます。
事前にコンテナのイメージはecrやdocker hubに上げておき、そのパスをimageに指定します。

また、ecs-cliでdocker-compose.ymlを利用する場合、docker-composeのversionにも気をつける必要があります。
参考：https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/ECS_CLI.html

```yml:docker-compose.prod.yml
version: "3" # ecs-cliがサポートしているversionは3まで。

services:
  app:
    image: <ecrのパス>
    ports:
      - 7777:7777
  nginx:
    image: <ecrのパス>
    ports:
      - 80:80
    depends_on:
      - app
```

# ecsのパラメータの作成
docker-compose.ymlだけでは対応しきれない設定などはecsパラメータとして別のymlを用意し定義することができます。
参考：https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/cmd-ecs-cli-compose-ecsparams.html

ここでfargateに割り当てる割り当てるリソースの値や、サブネット、セキュリティグループの指定ができます。
事前にterraformで作成しておいたサブネットやセキュリティグループをここで指定します。

またfargateの場合、必須項目となっているcpu_limitとmem_limitは可能な組み合わせが存在し、その組み合わせの中で選ぶ必要があります。
参考: https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/task-cpu-memory-error.html


```yml:ecs-params.yml
version: 1
task_definition:
  task_execution_role: ecs-task-execution
  ecs_network_mode: awsvpc
  task_size:
    cpu_limit: "256"
    mem_limit: "0.5GB"
run_params:
  network_configuration:
    awsvpc_configuration:
      subnets:
        # fargateを配置するサブネット。terraformで事前に作っておく。
        - subnet-*****************
        - subnet-*****************
      security_groups:
        # fargateのセキュリティグループ。
        # ecs-cliで --container-port 80 としているので80のポートをインバウンドで開けているようなセキュリティグループをterraformで事前に作っておく。
        - sg-*****************
      assign_public_ip: ENABLED
```


# ecs-cli compose service コマンドの作成
ecs-cliには `--target-group-arn`、`--container-name`、`--container-port`というoptionがあり、これを指定することで既存のターゲットグループをecsのタスクと紐づけることができます。

`--target-group-arn` には事前に作っておいたターゲットグループのarn、
`--container-name` にはdocker-compose.ymlに記載したコンテナ名、
`--container-port` にはコンテナのポートとする80、
を指定しています。

参考: [https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/cmd-ecs-cli-compose-service-up.html#cmd-ecs-cli-compose-service-up-examples](https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/cmd-ecs-cli-compose-service-up.html#cmd-ecs-cli-compose-service-up-examples)


```terminal
$ ecs-cli compose \
--file docker-compose.prod.yml \
--project-name <サービス名> \
--ecs-params ./ecs_params.yml \
service up \
--vpc <vpcのid> \
--target-group-arn <ecsのタスクをぶら下げるターゲットグループのarnを指定> \
--container-name nginx \
--container-port 80
```

このecs-cliコマンドを実行すれば、ecsのサービス、タスクが作成されます。
また作成したタスクはterraformで作成したターゲットグループにひもづきます。

これで冒頭の `terraformでecsのクラスターまでを作成し、ecs-cliでecsのサービス、タスクを作成` ができました。

実際にこれを活用する場合はecs-params.ymlにコンテナのヘルスチェックを追加したり、ecs-cliコマンドをそのまま打つのではなくもっと安全にデプロイできるフローの整備もする必要があると思います。が、一旦これでリリースはできます。