【Fargate】Rails + Redis構成のタスクを作成する
問題
アプリケーションコンテナとワーカーコンテナを同時に起動させようとすると、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で行っているので今回は使用しませんでした。
タスク定義のパラメータについて、詳しくは以下の公式ドキュメントを読んでください。
参考
Discussion