Closed12
特定タグのEC2インスタンスを特定の時間に停止する
参考
要件
- 以下タグのついたEC2インスタンスを停止する
- タグキー: AutoStop
- タグバリュー: True
- 起動はさせなくていい
- 決まった時間に実行するようにする
- Terraform化したい
案
- 🆗Lambda + EventBridge Scheduler
- タグの指定を出来るのはLambdaだけ?
- そのLambdaをEventBridge Schedulerで起動すればよさげ
- ❌EventBridge Scheduler
- タグ指定ができない?。単体では無理
- ❌Resource Scheduler(Systems Manager)
- Systems Managerからもできるのか!
- Terraformでできるか不安だったので今回は見送るが、いずれ試してみたい
- https://dev.classmethod.jp/articles/ssm-quick-setup-resource-scheduler/
- ❌サーバのCronで管理
- OSの管理したくないので却下
特定のタグを持ったEC2を停止させるLambda
lambda.tf
import boto3
def lambda_handler(event, context):
ec2 = boto3.resource('ec2')
filters = [{
'Name': 'tag:AutoStop',
'Values': ['True']
},
{
'Name': 'instance-state-name',
'Values': ['running']
}
]
instances = ec2.instances.filter(Filters=filters)
RunningInstances = [instance.id for instance in instances]
if len(RunningInstances) > 0:
# perform the shutdown
stoppingInstances = ec2.instances.filter(InstanceIds=RunningInstances).stop()
print("Stopped instances: " + str(RunningInstances))
else:
print("No instances to stop")
- タグキーが「AutoStop」、タグバリューが「True」であり、状態が「running」であるEC2のインスタンスIDを取得
- filterの内容はここを見れば良さげ
- そのインスタンスIDのインスタンスを
stop
メソッドで停止させる
filterのサンプル
stop
メソッド
ポイント① タイムアウトの設定
Lambdaのタイムアウトはデフォルトで3秒です。
このようなタイムアウトのログが出る場合は設定しましょう。
{"errorMessage":"2023-07-22T11:53:57.896Z 86702c62-5722-4403-9038-c8f433cc13d2 Task timed out after 3.02 seconds"}~
本環境では10秒に設定しました。
resource "aws_lambda_function" "example_lambda" {
// 略
timeout = 10
}
ログ
ポイント② EC2停止用のIAMポリシ適用
resource "aws_iam_policy" "ec2_stop_policy" {
name = "ec2_stop_policy"
path = "/"
description = "IAM policy for stopping EC2 instances"
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ec2:DescribeInstances",
"ec2:StopInstances"
],
"Resource": "*"
}
]
}
EOF
}
EventBridge Scheduler設定
IAMポリシー
Lambda関数をInvoke出来るポリシーを作成し、Schedulerに使ってもらいます
resource "aws_iam_role" "schedule_role" {
name = "schedule-role"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "scheduler.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}
resource "aws_iam_role_policy_attachment" "schedule_policy_attachment" {
role = aws_iam_role.schedule_role.name
policy_arn = aws_iam_policy.schedule_policy.arn
}
resource "aws_iam_policy" "schedule_policy" {
name = "schedule_policy"
path = "/"
description = "IAM policy for invoking Lambda Function"
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"lambda:InvokeFunction"
],
"Resource": "${aws_lambda_function.example_lambda.arn}"
}
]
}
EOF
}
スケジュール
resource "aws_scheduler_schedule" "cron" {
name = "ec2-stop-schedule"
flexible_time_window {
mode = "OFF"
}
target {
arn = aws_lambda_function.example_lambda.arn
role_arn = aws_iam_role.schedule_role.arn
}
schedule_expression = "cron(50 23 ? * * *)"
schedule_expression_timezone = "Asia/Tokyo"
}
- 23:50分にLambda関数を起動する
- 日本タイムゾーンを指定
- フレックスタイムウインドウはoff
aws_lambda_permission
が不要
ポイント③ てっきり必要なものだと思っていたのですが、使ってところなくても動作するようです。
理由はわからないので後日調べてみます。
resource "aws_lambda_permission" "allow_eventbridge-scheduler" {
statement_id = "AllowExecutionFromCloudWatch"
action = "lambda:InvokeFunction"
function_name = aws_lambda_function.example_lambda.function_name
principal = "scheduler.amazonaws.com"
}
ポイント④ ログ確認
Lambda関数をSchedulerがInvokeした記録を見れればいいのだが、コンソールからは見つけられなかった。
次回の課題
とりあえずLambda関数のロググループから起動時間を確認し、スケジューラの設定時間+20秒前後で実行されていればよし
このスクラップは2023/07/23にクローズされました