前書き
株式会社ゆめみでエンジニアをしていますむろです。
今回は,EventBridge Scheduler を使って,ECS サービスで動かしている Task を定期的に起動・停止する方法についての記事になります。Task は祝日を考慮せず,平日(月曜日 ~ 金曜日)の08:00 ~ 22:00に動かします。この記事では Terraform を使って ECS サービスや EventBridge Scheduler を管理することを目的としています。
AWS コンソールでも同様の Scheduler を作成することが可能ですので,用途などに応じて選択すると良いかと思います。
この記事では主として EventBridge Scheduler を設定することを目的としています。そのため,ECS サービスや Task の設定などは一部割愛します。
Terraform のディレクトリ構成は以下になります。なお,この記事で使用しないファイルなどは省略しています。
terraform
├── ecs_cluster.tf
├── ecs_service.tf
├── event_bridge.tf
├── modules
│ ├── ecs_service
│ │ ├── ecs_service.tf
│ │ ├── outputs.tf
│ │ └── variables.tf
│ └── event_bridge
│ ├── event_bridge_schedule_group.tf
│ ├── event_bridge_scheduler.tf
│ ├── iam_role_for_event_bridge_scheduler.tf
│ └── variables.tf
└── versions.tf
Terraform のバージョンは以下になります。
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 5.70.0"
}
}
required_version = ">= 1.9"
}
記事で使用する ECS の作成
Scheduler の設定を読みたい方はこちらまで移動してください。
ではまず,ECS クラスターを作成します。
resource "aws_ecs_cluster" "ecs_cluster" {
name = "ecs-cluster-for-eventbridge-scheduler"
}
次に,ECS サービスを作成していきます。今回はモジュールを使用していますので,変数の設定をしていきます。
module "ecs_service" {
source = "./modules/ecs_service"
app_name = "app"
name = "ecs-service-for-eventbridge-scheduler"
desired_count = 1
cluster_id = aws_ecs_cluster.ecs_cluster.id
}
variable "app_name" {
type = string
description = "Name of this application"
}
variable "name" {
type = string
description = "Name of this resource"
}
variable "desired_count" {
type = number
description = "Initial desired count"
default = 1
}
variable "cluster_id" {
type = string
description = "ECS Cluster ID"
}
モジュールの実態の方を用意します。なお,提示するパラメータは全てではありませんので,実際に ECS サービスを作成する際には公式ドキュメントなどを参照した上で作成する方が良いかと思います。
resource "aws_ecs_service" "default" {
name = var.name
cluster = var.cluster_id
desired_count = var.desired_count
launch_type = "FARGATE"
scheduling_strategy = "REPLICA"
propagate_tags = "SERVICE"
# ~~ 省略 ~~
}
また,IAM の設定や EventBridge Scheduler で用いるため output を設定します。
output "service_name" {
value = aws_ecs_service.default.name
description = "Name of ECS service"
}
output "service_arn" {
value = aws_ecs_service.default.id
descripion = "Arn of ECS service"
}
EventBridge Scheduler で使用する IAM を設定
それでは,ここから実際に EventBridge Scheduler で ECS サービスを操作するために必要な IAM を作成していきます。今回の記事では1ファイルにまとめていますが,適宜ファイルを分割するなどして,ご自身の管理都合が良いものにすると良いかと思います。
IAM の設定の際に,ECS サービスのモジュールや変数として受け取りたい値定義しておきます。
module "default_scheduler" {
source = "./modules/event_bridge"
cluster_name = aws_ecs_cluster.ecs_cluster.name
service = "default"
start_schedule = "cron(0 8 ? * MON-FRI *)"
stop_schedule = "cron(0 22 ? * MON-FRI *)"
ecs_service_arn = module.ecs_service_api.service_arn
desired_count = 1
}
variable "cluster_name" {
description = "Name of target for EventBridge Scheduler"
type = string
}
variable "ecs_service_arn" {
description = "Arn of target for EventBridge Scheduler"
type = string
}
variable "service" {
description = "Service of target for EventBridge Scheduler"
type = string
}
variable "start_schedule" {
description = "Starting schedule for ECS service. Type: Cron"
type = string
}
variable "stop_schedule" {
description = "Stopping schedule for ECS service. Type: Cron"
type = string
}
variable "desired_count" {
description = "Desired count for ECS service"
type = number
}
data "aws_iam_policy_document" "eventbridge_for_ecs_assume_policy_doc" {
statement {
principals {
type = "Service"
identifiers = ["scheduler.amazonaws.com"]
}
actions = ["sts:AssumeRole"]
effect = "Allow"
}
}
data "aws_iam_policy_document" "eventbridge_for_ecs_policy_doc" {
version = "2012-10-17"
statement {
resources = [
"${var.ecs_service_arn}",
]
actions = ["ecs:UpdateService"]
effect = "Allow"
}
}
resource "aws_iam_policy" "eventbridge_for_ecs_policy" {
name = "eventbridge_for_${var.stage_name}_${var.service}_policy"
description = "Policy for Eventbridge using ecs scheduler"
policy = data.aws_iam_policy_document.eventbridge_for_ecs_policy_doc.json
}
resource "aws_iam_role" "eventbridge_for_ecs_role" {
name = "${var.stage_name}_${var.service}_eventbridge_for_ecs_role"
assume_role_policy = data.aws_iam_policy_document.eventbridge_for_ecs_assume_policy_doc.json
}
resource "aws_iam_role_policy_attachment" "eventbridge_for_ecs_role_policy_attachment" {
role = aws_iam_role.eventbridge_for_ecs_role.name
policy_arn = aws_iam_policy.eventbridge_for_ecs_policy.arn
}
EventBridge Scheduler で ECS を操作する
event_bridge.tf
にもある通り,起動時刻と停止時刻はモジュールの引数として渡しています。 EventBridge Scheduler のリソースを作成していきます。 UpdateService に対し,必要な引数をjson形式で渡してあげるものになります。
esource "aws_scheduler_schedule" "stopper" {
name = "${var.service}_stopper"
state = "ENABLED"
schedule_expression = var.stop_schedule
schedule_expression_timezone = "Asia/Tokyo"
flexible_time_window {
mode = "OFF"
}
target {
arn = "arn:aws:scheduler:::aws-sdk:ecs:updateService"
role_arn = aws_iam_role.eventbridge_for_ecs_role.arn
input = jsonencode({
"Cluster" : "${var.stage_name}"
"Service" : "${var.service}",
"DesiredCount" : 0
})
}
}
resource "aws_scheduler_schedule" "starter" {
name = "${var.service}_starter"
state = "ENABLED"
schedule_expression = var.start_schedule
schedule_expression_timezone = "Asia/Tokyo"
flexible_time_window {
mode = "OFF"
}
target {
arn = "arn:aws:scheduler:::aws-sdk:ecs:updateService"
role_arn = aws_iam_role.eventbridge_for_ecs_role.arn
input = jsonencode({
"Cluster" : "${var.stage_name}"
"Service" : "${var.service}",
"DesiredCount" : "${var.desired_count}"
})
}
}
以上で必要なファイルの作成が完了したかと思います。表題を十分実現可能な状態を作成できました。
おわりに
AWSコンソールを操作することでも今回の内容と同様のことは可能ですが,Terraformで管理できることにメリットはあると思います。今回の記事が誰かの一助になると嬉しいです。
誤りなどありましたらご指摘いただけますと嬉しいです。