Terraformを使ってECS on Fargate 1.4.0を構築するときに気をつけたポイント

# 各種バージョン情報

```
$ terraform -v
Terraform v0.14.6

# FARGATEプラットフォームのバージョン 1.4.0
```


# チェックポイント

自分が特に気にしたポイントを列挙します。

- ECRのイメージを利用する場合は、ECSから以下２つのECRエンドポイントへアクセスができること
    - 詳細は[Amazon ECR VPC エンドポイントに関する考慮事項より](https://docs.aws.amazon.com/ja_jp/AmazonECR/latest/userguide/vpc-endpoints.html)
    - com.amazonaws.ap-northeast-1.ecr.api
    - com.amazonaws.ap-northeast-1.ecr.dkr
- awslogdriverを利用する場合は、ECSからlogsエンドポイントへアクセスができること
    - com.amazonaws.ap-northeast-1.logs
-  ECSタスク実行IAMロールがSecretManagerが参照でき、その暗号化に利用したKMSの利用ができること
    - [Amazon ECS シークレットで必須の IAM アクセス許可より](https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/specifying-sensitive-data-secrets.html)
- ECSタスクのcpuとmemoryが正しい組み合わせかどうか
    - cpu→256、memory→256などは✗
    - 組み合わせ可能リストは[こちら](https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/task-cpu-memory-error.html)
- ECSタスク起動時にLatest指定すると1.3.0で起動してしまうので注意
    - 20210307確認
- Fargate 1.3.0で、SecretManagerを利用するには１工夫が必要で同じ使い方ができない
    - 具体的には１つの環境変数にすべての値が挿入されてしまうのでコンテナ起動後にシェルスクリプトなどで分解する必要がある
    - 1.4.0からは特定の値を１つの環境変数に挿入できるようになった

# とりまTerraformで書いてみましょ

ファイル数多いので全体は[GitHubに置きました](https://github.com/YutaOkoshi/ecs_on_fargate)

重要なポイントだけ以下に書きます。

### コンテナにSecretManagerの値を渡す部分


- ECSタスクの定義

```sample_ecs_fargate/_modules/app/ecstaskdefinition.tf
resource "aws_ecs_task_definition" "debug" {
  container_definitions = templatefile("${path.module}/template/debug.json", {
    env        = var.env
    version    = var.image_version
    image      = var.image_name
    debug_log  = aws_cloudwatch_log_group.debug.name
    app_name   = var.project
    secret_arn = aws_secretsmanager_secret.my_sandbox.arn
  })
〜略〜

```

```sample_ecs_fargate/_modules/app/template/debug.json
[
〜〜略〜〜
        "networkMode": "awsvpc",
        "environment": [
            {
                "name": "ENV",
                "value": "${env}"
            },
            {
                "name": "APP_NAME",
                "value": "${app_name}"
            }
        ],
        "secrets": [
            {
                "name": "HOGE",
                "valueFrom": "${secret_arn}:HOGE::"
                # ↑こんなかんじにARN＋キー名で指定してあげるとできる
            }
        ]
〜〜略〜〜
``` 

- SecretManagerの定義

```sample_ecs_fargate/_modules/app/secretmanager.tf
resource "aws_secretsmanager_secret" "my_sandbox" {
  name        = "tmp/sandbox/secret"
  description = "my_sandbox secret"
  recovery_window_in_days = 0
}

resource "aws_secretsmanager_secret_version" "my_sandbox" {
  secret_id = aws_secretsmanager_secret.my_sandbox.id
  secret_string = templatefile("${path.module}/template/secretmanager.json", {
    env = var.env
  })
}

```

```sample_ecs_fargate/_modules/app/template/secretmanager.json
{
    "ENV": "${env}",
    "HOGE": "SECRET!!"
}
```

### コンテナイメージのLatest運用をやめる

- CircleCI側のJobでDockerイメージの作成、ECRへの登録、ECSサービスとECSタスクの更新を行っている
- ※terraform apply直後はLatest運用になってしまう問題は残っているがCircleCIからイメージとECSサービスのアップデートをすれば更新される

```.circleci/config.yml
version: 2.1

orbs:
  aws-ecr: circleci/aws-ecr@6.15.2
  aws-ecs: circleci/aws-ecs@1.4.0

workflows:

  build_and_push_image_dev:
    jobs:
      # approval使っているのは完全にぼくの好み
      # 自動デプロイはまだ正直コワイ
      - approval-to-build-and-deploy:
          type: approval
      - aws-ecr/build-and-push-image:
          requires:
            - approval-to-build-and-deploy
          name: build-and-push-debug-image
          account-url: AWS_ECR_HOST # 12341234.dkr.ecr.ap-northeast-1.amazonaws.com
          aws-access-key-id: AWS_ACCESS_KEY_ID
          aws-secret-access-key: AWS_SECRET_ACCESS_KEY
          create-repo: true
          dockerfile: "docker/debug/Dockerfile"
          no-output-timeout: 20m
          repo: "my-sandbox/debug"
          skip-when-tags-exist: false
          tag: "latest,${CIRCLE_SHA1}"

      - aws-ecs/deploy-service-update:
          name: deploy-service-update
          requires:
            - build-and-push-debug-image
          aws-region: "ap-northeast-1"
          aws-access-key-id: "${AWS_ACCESS_KEY_ID}"
          aws-secret-access-key: "${AWS_SECRET_ACCESS_KEY}"
          family: "my-sundbox-debug-family"
          service-name: "my-sundbox-debug"
          cluster-name: "arn:aws:ecs:ap-northeast-1:12341234:cluster/my-sundbox-cluster"
          container-image-name-updates: "container=debug,tag=${CIRCLE_SHA1}"
                                                             # ↑ここでtagを指定してECSサービスとECSタスクをアップデートしているのが肝

# 渡すべきパラメーターがStringだったりenv_var_nameだったりして少し使いにくかったのでそこらへんよしなにやってほしい。。。
```

# AWS CLIからECSタスクの起動方法

今回はWebページを作ってないので、コマンドでECSタスクを起動してみましょう

```
# subnet-aaaaaaaはECSタスクを配置したいサブネットID
# sg-bbbbbbbはECSタスクにアタッチするセキュリティグループID
# --platform-versionは指定しないとデフォルトの1.3.0になるので注意
aws ecs run-task \
    --cluster "my-sundbox-cluster" \
    --task-definition "my-sundbox-debug-family" \
    --launch-type "FARGATE" \
    --platform-version "1.4.0" \
    --network-configuration "awsvpcConfiguration={subnets=['subnet-aaaaaaa'],securityGroups=['sg-bbbbbbb'],assignPublicIp='DISABLED'}" \
    --profile ${AWSプロファイル名}

{
    "tasks": [
        {
            "attachments": [
〜後略〜
# コマンドが成功すると起動したタスク情報が表示されます
```

ちゃんとSecretManagerの値が環境変数に入りました。

![スクリーンショット 2021-03-07 2.41.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319433/6e9d1f9b-6f4c-3e3f-8224-5b7ad1baa2a5.png)