ENECHANGE Developer Blog

ENECHANGE開発者ブログ

CloudWatch Eventsのスケジュールトリガーを使用してサーバの起動管理を行う

こんにちは。断捨離を進めていくなかで家にある廃棄対象の物がリモートワーク関連で驚きの価格で取引されてるのを見てニヤニヤしているCTO室のkazです。 今回は、CloudWatchを使用したインスタンスの起動管理をお伝えしたいと思います。

概要

弊社開発者が任意のタイミングでサーバ起動・停止できるように取り入れた仕組みとしてAWSSimpleConsoleがあります。 github.com

ただ、dockerの使用やElasticBeanstalkでの起動管理など、新しい仕組みを取り入れていく環境の中で、AWSSimpleConsoleで運用するサーバも数台になったことから、今回、CloudWatchのEvents機能を利用した起動制御にリプレイスしました。 また、マネージメントコンソールにおける表示と設定についても注意点がありますので記述します。

要件

  • 開発上必要なサーバに対して、夜間は不要なため毎日、時間を指定して停止させておく
  • 起動は不定期であるため、都度、APIを実行して起動させる

方法

  • CloudWatch Eventsでスケジュールを使用し、ターゲットにインスタンスを指定する
  • Terraformを用いて設計・実装する

注意点

  • InstanceIdはStringList形式で指定する必要がある
  • 一度に指定できる数は最大5つという制限がある
  • cronライクにスケジュールを定義できるがUTCのタイムゾーンで記述する必要がある

docs.aws.amazon.com

設定

  • Event SourceとTargetsの設定をすることでスケジュールがトリガーされたときに起動するターゲットを選択します。そのターゲットとしてSystems Managerには定義済みオートメーションドキュメントが用意されているので arn = "arn:aws:ssm:ap-northeast-1::automation-definition/AWS-StopEC2Instance" として定義します。

docs.aws.amazon.com

cloudwatch_event_rule.tf

resource "aws_cloudwatch_event_rule" "stop_rule_1" {
  name        = "stop-rule-1"
  description = "server stop the dev server at 22:00(JST)"

  schedule_expression = "cron(0 13 * * ? *)"
}

// The number of InstanceId constants is limited within 5
resource "aws_cloudwatch_event_target" "stop_target_1" {
  target_id = "StopInstance"
  arn       = "arn:aws:ssm:ap-northeast-1::automation-definition/AWS-StopEC2Instance"
  rule      = aws_cloudwatch_event_rule.stop_rule_1.name
  role_arn  = aws_iam_role.cloudwatch_event_ssm_role.arn

  input = <<EOF
{
  "InstanceId": ["i-00000000000000000", "i-11111111111111111", "i-22222222222222222", "i-33333333333333333", "i-44444444444444444"]
}
EOF
}

resource "aws_cloudwatch_event_rule" "stop_rule_2" {
  name        = "stop-rule-2"
  description = "server stop the dev server at 22:00(JST)"

  schedule_expression = "cron(0 13 * * ? *)"
}

// The number of InstanceId constants is limited within 5
resource "aws_cloudwatch_event_target" "stop_target_2" {
  target_id = "StopInstance"
  arn       = "arn:aws:ssm:ap-northeast-1::automation-definition/AWS-StopEC2Instance"
  rule      = aws_cloudwatch_event_rule.stop_rule_2.name
  role_arn  = aws_iam_role.cloudwatch_event_ssm_role.arn

  input = <<DOC
{
  "InstanceId": ["i-55555555555555555"]
}
DOC
}

iam_role.tf

resource "aws_iam_role" "cloudwatch_event_ssm_role" {
  name = "cloudwatch_event_ssm_role"

  assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "sts:AssumeRole",
      "Principal": {
        "Service": [
         "events.amazonaws.com"
         ]
     },
      "Effect": "Allow",
      "Sid": ""
    }
  ]
}
EOF
}

resource "aws_iam_role_policy" "cloudwatch_event_ssm_rds_policy" {
  name = "cloudwatch_event_ssm_rds_policy"
  role = aws_iam_role.cloudwatch_event_ssm_role.id

  policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Action": [
        "rds:StopDBInstance",
        "rds:StartDBInstance",
        "rds:DescribeDBInstances"
      ],
      "Resource": "*"
    }
  ]
}
EOF
}

resource "aws_iam_role_policy_attachment" "AmazonSSMAutomationRole" {
  role       = aws_iam_role.cloudwatch_event_ssm_role.id
  policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonSSMAutomationRole"
}

tips

  • AWS管理のRoleであるcloudwatch_event_ssm_roleだが、なぜかRDSについての権限がないので、RDSインスタンスを指定する場合は別途ポリシーを作成する必要がある。 また、RDSインスタンスのID指定はDB identifierを記述する。

cloudwatch_event_ssm_role

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "lambda:InvokeFunction"
            ],
            "Resource": [
                "arn:aws:lambda:*:*:function:Automation*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "ec2:CreateImage",
                "ec2:CopyImage",
                "ec2:DeregisterImage",
                "ec2:DescribeImages",
                "ec2:DeleteSnapshot",
                "ec2:StartInstances",
                "ec2:RunInstances",
                "ec2:StopInstances",
                "ec2:TerminateInstances",
                "ec2:DescribeInstanceStatus",
                "ec2:CreateTags",
                "ec2:DeleteTags",
                "ec2:DescribeTags",
                "cloudformation:CreateStack",
                "cloudformation:DescribeStackEvents",
                "cloudformation:DescribeStacks",
                "cloudformation:UpdateStack",
                "cloudformation:DeleteStack"
            ],
            "Resource": [
                "*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "ssm:*"
            ],
            "Resource": [
                "*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "sns:Publish"
            ],
            "Resource": [
                "arn:aws:sns:*:*:Automation*"
            ]
        }
    ]
}

  • マネージメントコンソールにおいてルールを編集するとInstanceIdの入力値がStringList形式ではないカンマ区切りの文字列へと変更されている。(機能改善要求済み)

f:id:dev-enechange:20200609195514p:plain

確認

  • 指定時間に指定したインスタンスが停止していることが確認できる

f:id:dev-enechange:20200609195547p:plain