LoginSignup
8
1

開発環境のECS Serviceを夜間に自動で停止させる

Last updated at Posted at 2024-04-23

コスト削減のため、開発環境のECS Serviceを夜間と休日は停止する際に行った内容のメモです

AuroraやEC2を夜間に停止するというのは、以下の SSM Automation を EventBridge 経由で実行することで可能ですが、ECS Serviceは対応するAutomationがないため SSM Document を自作してみました

SSM Documentの作成

SSM Document でAWS APIを実行するため以下の Automation Action を使用します

ECS Service を停止するためにはDesired Countを 0 にすることで停止できるため、UpdateService でDesiredCount だけを変更するようにします
parameters で受け取る引数と mainSteps で実際の処理を書きます

resource "aws_ssm_document" "start_stop_ecs_service" {
  name            = "StartStopECSService"
  document_format = "YAML"
  document_type   = "Automation"

  content = <<EOT
description: ecs service start and stop automation runbook
schemaVersion: '0.3'
parameters:
  EcsClusterName:
    type: String
  EcsServiceName:
    type: String
  DesiredCount:
    type: Integer
    default: 1
mainSteps:
  - name: ECS
    action: 'aws:executeAwsApi'
    inputs:
      Service: ecs
      Api: UpdateService
      cluster: '{{ EcsClusterName }}'
      service: '{{ EcsServiceName }}'
      desiredCount: '{{ DesiredCount }}'
EOT
}

SSM Automationを実行するIAMロールを作成

EventBridge から実行させるためのIAMロールを作成します

data "aws_iam_policy_document" "events" {
  statement {
    actions = ["sts:AssumeRole"]
    effect  = "Allow"
    principals {
      type        = "Service"
      identifiers = [
        "events.amazonaws.com"
      ]
    }
  }
}

resource "aws_iam_role" "ecs_automation" {
  name               = "ecs-automation"
  path               = "/"
  assume_role_policy = data.aws_iam_policy_document.events.json
}

上記のIAMロールに SSM Document を実行する権限とECSの UpdateService の権限を付与します

data "aws_iam_policy_document" "ecs_stop_start" {
  statement {
    actions   = [
      "ecs:Describe*",
      "ssm:*"
    ]
    effect    = "Allow"
    resources = ["*"]
  }
  statement {
    actions   = [
      "ecs:UpdateService"
    ]
    effect    = "Allow"
    resources = [
      (停止させたいECS ServiceのARN)
    ]
  }
}

resource "aws_iam_role_policy" "ecs_stop_start" {
  name   = "ecs-stop-start"
  role   = aws_iam_role.ecs_automation.name
  policy = data.aws_iam_policy_document.ecs_stop_start.json
}

EventBridgeの作成

月曜~金曜の22時に ECS Service を停止します
aws_ecs_service の cluster はARNなので split でCluster名を取得しています

resource "aws_cloudwatch_event_rule" "ecs_service_stop" {
  name                = "ecs-service-stop"
  schedule_expression = "cron(0 13 * * MON-FRI *)"
  is_enabled          = true
}

resource "aws_cloudwatch_event_target" "ecs_service_stop" {
  target_id = aws_ecs_service.api.name
  rule      = aws_cloudwatch_event_rule.ecs_service_stop.name
  arn       = "${aws_ssm_document.ecs_service_stop_start.arn}:$DEFAULT"
  role_arn  = aws_iam_role.ecs_automation.arn
  input     = <<EOT
{
  "EcsClusterName": ["${split("/", aws_ecs_service.api.cluster)[-1]}"],
  "EcsServiceName": ["${aws_ecs_service.api.name}"],
  "DesiredCount": ["0"]
}
EOT
}

月曜~金曜の9時30分に ECS Service を起動させます

resource "aws_cloudwatch_event_rule" "ecs_service_start" {
  name                = "ecs-service-start"
  schedule_expression = "cron(30 0 ? * * *)"
  is_enabled          = true


resource "aws_cloudwatch_event_target" "ecs_service_start" {
  target_id = aws_ecs_service.api.name
  rule      = aws_cloudwatch_event_rule.ecs_service_start.name
  arn       = "${aws_ssm_document.ecs_service_stop_start.arn}:$DEFAULT"
  role_arn  = aws_iam_role.ecs_automation.arn
  input     = <<EOT
{
  "EcsClusterName": ["${split("/", aws_ecs_service.api.cluster)[-1]}"],
  "EcsServiceName": ["${aws_ecs_service.api.name}"],
  "DesiredCount": ["1"]
}
EOT
}

応用として

今回は開発環境を停止するという用途でしたが、本番環境で深夜のようなほぼアクセスが来ない状況では desiredCount を 1 にするということや、特定の時間帯だけ増やすということが可能になりそうです
スケジュールで desiredCount を増減するというのは AotoScaling で可能でありますが、この手順のほうがお手軽かなと個人的には思います

8
1
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
8
1