ECSタスクでRakeタスクを定期実行する

ECSサービスとしてRailsアプリケーションを運用しているとき、定期実行したいRakeタスクはcronで管理するよりもECS scheduled taskとして管理すると思う。

まず、RakeタスクをECS(Fargate)上で実行するため、ECSタスク定義をつくる。

resource "aws_ecs_task_definition" "rake" {
  family                   = "rake"
  task_role_arn            = aws_iam_role.ecs_task.arn
  execution_role_arn       = aws_iam_role.ecs_execution.arn
  network_mode             = "awsvpc"
  cpu                      = 256
  memory                   = 512
  requires_compatibilities = ["FARGATE"]

  container_definitions  = <<DOCUMENT
[
  {
    "name": "rails",
    "image": "${aws_ecr_repository.rails.repository_url}:latest",
    "command": ["exit", "1"],
    "environment": [
      { "name": "RAILS_ENV", "value": "production" }
    ],
    "logConfiguration": {
      "logDriver": "awslogs",
      "options": {
        "awslogs-group": "${aws_cloudwatch_log_group.rails.name}",
        "awslogs-region": "ap-northeast-1",
        "awslogs-stream-prefix": "rake"
      }
    }
  }
]
DOCUMENT
}
  • 定期実行したいRakeタスクごとにECSタスク定義を作るのは非効率なので、Rakeタスク専用のタスク定義をつくる。
  • 後ほど、実行するコマンドをoverrideするため、タスク定義のコマンドではexit 1を実行するようにしている。
resource "aws_cloudwatch_event_rule" "push_notifications_schedule" {
  name                = "push-schedule"
  schedule_expression = "cron(0 20 * * ? *)"
}

resource "aws_cloudwatch_event_target" "push_notifications" {
  rule     = aws_cloudwatch_event_rule.push_notifications_schedule.name
  arn      = aws_ecs_cluster.production.arn
  role_arn = aws_iam_role.ecs_events.arn

  ecs_target {
    launch_type         = "FARGATE"
    task_count          = 1
    task_definition_arn = aws_ecs_task_definition.rake.arn

    network_configuration {
      subnets         = [aws_subnet.private_a.id, aws_subnet.private_c.id]
      security_groups = [aws_security_group.internal.id]
    }
  }

  input = <<DOCUMENT
{
  "containerOverrides": [
    {
      "name": "rails",
      "command": ["bin/rails", "push_notifications"]
    }
  ]
}
DOCUMENT
}
  • aws_cloudwatch_event_ruleはスケジュールごとに書き、そのスケジュールで実行するRakeタスクごとにaws_cloudwatch_event_targetを書くことになる。なので、production環境とstaging環境で同じスケジュールを使う場合は、aws_cloudwatch_event_ruleは共用することになる。
  • aws_cloudwatch_event_targetでは、ecs_targetでFargate上でECSタスクを実行するためのオプションを指定する必要がある。inputでコンテナ定義のoverrideができるので、ここでexit 1としていた実行コマンドをoverrideしている。