0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

株式会社ゆめみAdvent Calendar 2024

Day 21

EventBridge Scheduler で ECS を平日だけ動かす仕組みを Terraform で作る

Last updated at Posted at 2024-12-20

前書き

株式会社ゆめみでエンジニアをしていますむろです。
今回は,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 のバージョンは以下になります。

versions.tf
terraform {
 required_providers {
   aws = {
     source  = "hashicorp/aws"
     version = ">= 5.70.0"
   }
 }
 required_version = ">= 1.9"
}

記事で使用する ECS の作成

Scheduler の設定を読みたい方はこちらまで移動してください。
ではまず,ECS クラスターを作成します。

ecs_cluster.tf
resource "aws_ecs_cluster" "ecs_cluster" {
  name = "ecs-cluster-for-eventbridge-scheduler"
}

次に,ECS サービスを作成していきます。今回はモジュールを使用していますので,変数の設定をしていきます。

ecs_service.tf
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
}
modules/ecs_service/variables.tf
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 サービスを作成する際には公式ドキュメントなどを参照した上で作成する方が良いかと思います。

modules/ecs_service/ecs_service.tf
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 を設定します。

modules/ecs_service/output.tf
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 サービスのモジュールや変数として受け取りたい値定義しておきます。

event_bridge.tf
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
}
modules/event_bridge/variables.tf
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
}
modules/event_bridge/iam_role_for_event_bridge_scheduler.tf
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形式で渡してあげるものになります。

modules/event_bridge/event_bridge_scheduler.tf
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で管理できることにメリットはあると思います。今回の記事が誰かの一助になると嬉しいです。
誤りなどありましたらご指摘いただけますと嬉しいです。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?