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


各種バージョン情報

$ terraform -v
Terraform v0.14.6

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

チェックポイント

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

  • ECRのイメージを利用する場合は、ECSから以下2つのECRエンドポイントへアクセスができること
  • awslogdriverを利用する場合は、ECSからlogsエンドポイントへアクセスができること
    • com.amazonaws.ap-northeast-1.logs
  • ECSタスク実行IAMロールがSecretManagerが参照でき、その暗号化に利用したKMSの利用ができること
  • ECSタスクのcpuとmemoryが正しい組み合わせかどうか
    • cpu→256、memory→256などは✗
    • 組み合わせ可能リストはこちら
  • ECSタスク起動時にLatest指定すると1.3.0で起動してしまうので注意
    • 20210307確認
  • Fargate 1.3.0で、SecretManagerを利用するには1工夫が必要で同じ使い方ができない
    • 具体的には1つの環境変数にすべての値が挿入されてしまうのでコンテナ起動後にシェルスクリプトなどで分解する必要がある
    • 1.4.0からは特定の値を1つの環境変数に挿入できるようになった

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

ファイル数多いので全体はGitHubに置きました

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

コンテナに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/[email protected]
  aws-ecs: circleci/[email protected]

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の値が環境変数に入りました。