✍️

【Fargate】Rails + Redis構成のタスクを作成する

2023/06/04に公開

問題

アプリケーションコンテナとワーカーコンテナを同時に起動させようとすると、1つのコンテナのマイグレーションが終わらないうちに続けてもう1つのコンテナでマイグレーションが走ってしまう。

Cannot run migrations because another migration process is currently running 

結論

タスク定義に起動オプションを設定する必要がある。

実装方法

Redisの作成

以下のように記述してterraform apply。
node_type、replicas_per_node_groupあたりは要件に合わせて変更します。

resource "aws_elasticache_replication_group" "main" {
  automatic_failover_enabled = true
  replication_group_id       = "app-env"
  description                = "app-elasticache-replication-group-env"
  node_type                  = "cache.t3.micro"
  replicas_per_node_group    = 1
  parameter_group_name       = "default.redis3.2"
  engine_version             = "6.2"
  port                       = 6379
  subnet_group_name          = aws_elasticache_subnet_group.main.name
  security_group_ids         = [
      aws_security_group.ecs.id #aws_security_groupの作成は省略
    ]
}

resource "aws_elasticache_subnet_group" "main" {
  name       = "elasticache-subnet-group-env"
  subnet_ids = [aws_subnet.private.id] #aws_subnetの作成は省略
}

タスク定義

[ #アプリケーションコンテナ
  {
    "name": "ecs-container-app-env",
    "image": "${aws_account_id}.dkr.ecr.ap-northeast-1.amazonaws.com/${container_repository_name}",
    "revision": "latest",
    "essential": true,
    "workingDirectory": "/webapp",
    "logConfiguration": {
      "logDriver": "awslogs",
      "secretOptions": null,
      "options": {
        "awslogs-group": "${app_log_group_name}",
        "awslogs-region": "ap-northeast-1",
        "awslogs-stream-prefix": "app"
      }
    },
    "portMappings": [
      {
        "protocol": "tcp",
        "hostPort": 80,
        "containerPort": 80
      }
    ],
    "environment": ${environments},
    "secrets": [
      {
        "name": "SECRET_KEY_BASE",
        "valueFrom": "${secret_key_base}"
      },
      {
        "name": "RAILS_MASTER_KEY",
        "valueFrom": "${rails_master_key}"
      },
      {
        "name": "DATABASE_HOST",
        "valueFrom": "${rds_cluster_endpoint}"
      },
      {
        "name": "DATABASE_USER",
        "valueFrom": "${db_username}"
      },
      {
        "name": "DATABASE_PASSWORD",
        "valueFrom": "${db_password}"
      },
      {
        "name": "REDIS_URL",
        "valueFrom": "${redis_url}" #先程作成したRedisのエンドポイント
      }
    ],
    "command": ["bundle","exec","puma","-C","config/puma.rb"]
  },
   #ワーカーコンテナ
  {
    "name": "ecs-container-worker-env",
    "image": "${aws_account_id}.dkr.ecr.ap-northeast-1.amazonaws.com/${container_repository_name}",
    "essential": true,
    "dependsOn": [
      {
        "containerName": "ecs-container-app-env", #アプリケーションコンテナを指定する
        "condition": "START" #アプリケーションコンテナが起動したら起動を開始する
      }
    ],
    "workingDirectory": "/webapp",
    "logConfiguration": {
      "logDriver": "awslogs",
      "secretOptions": null,
      "options": {
        "awslogs-group": "${app_log_group_name}",
        "awslogs-region": "ap-northeast-1",
        "awslogs-stream-prefix": "worker"
      }
    },
    "environment": ${environments},
    "secrets": [
      {
        "name": "SECRET_KEY_BASE",
        "valueFrom": "${secret_key_base}"
      },
      {
        "name": "RAILS_MASTER_KEY",
        "valueFrom": "${rails_master_key}"
      },
      {
        "name": "DATABASE_HOST",
        "valueFrom": "${rds_cluster_endpoint}"
      },
      {
        "name": "DATABASE_USER",
        "valueFrom": "${db_username}"
      },
      {
        "name": "DATABASE_PASSWORD",
        "valueFrom": "${db_password}"
      },
      {
        "name": "REDIS_URL",
        "valueFrom": "${redis_url}" #先程作成したRedisのエンドポイント
      }
    ],
    "command":["bundle","exec","sidekiq","-C","config/sidekiq.yml"]
  }
]

環境変数に作成したRedisのエンドポイントを設定したアプリケーションとワーカーの2つのコンテナを記述します。
ほぼ同じ設定ですが、大事なのはワーカーコンテナにdependsOnパラメータを設定することです。
dependsOnはコンテナの依存関係を設定するもので、依存対象のコンテナと依存関係の条件を記述することで起動条件を設定することができます。

"dependsOn": [
      {
        "containerName": "ecs-container-app-env", #アプリケーションコンテナを指定する
        "condition": "START" #アプリケーションコンテナが起動したら起動を開始する
      }
    ]

今回は"START"を指定していますが、他にはCOMPLETE(依存コンテナの実行が完了 (終了) することを検証)、SUCCESS(COMPLETE と同じだが、コンテナがzeroステータスで終了していることも必要)、HEALTHY(依存コンテナがそのコンテナのヘルスチェックに合格したことを検証)のオプションがあります。
COMPLETEとSUCCESSは一見良さそうですが、簡単なスクリプトを単発で実行した後の状態を検証するものなのでRailsサーバーの起動オプションには不適切です。HEALTHYの場合はアプリケーションコンテナにhealthCheckパラメータを追加する必要があります。healthCheckを追加してもいいのですがアプリケーションに対してのヘルスチェック自体はALBで行っているので今回は使用しませんでした。

タスク定義のパラメータについて、詳しくは以下の公式ドキュメントを読んでください。
https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/task_definition_parameters.html

参考

https://christina04.hatenablog.com/entry/ecs-fargate-dependson-parameter

https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/task_definition_parameters.html

Discussion