AutoScalingグループのEC2インスタンスを定期リブート運用する

AWS

AutoScallingグループで構成されたEC2インスタンスを
決められたスケジュールでリブート運用してみます。

AutoScallingで構成されたEC2を単純にリブートしてしまうとヘルスチェックに失敗してしまうため
以下のいずれかの対応を行う必要があります。

  • インスタンスの状態をスタンバイにする
  • AutoScallingグループからインスタンスをデタッチする
  • AutoScallingのヘルスチェックプロセスを停止する

今回はインスタンスの状態をスタンバイにする方法でやってみます。
スタンバイ状態にすることでAutoScalingのインスタンスのヘルスチェックが実行されなくなります。
スケジューリングにはCloudWatchEventsを利用し、毎月第3日曜日の02:00時にリブートするよう設定します。

■参考URL
Auto Scalingグループからのインスタンスの一時的な削除

利用するサービス

  • CloudWatchEvents
  • Lambda
  • EC2 AutoScalling

処理の流れ

  1. EC2インスタンスをスタンバイ状態に設定し、リブートを行うLambda関数を作成
  2. 「1」で作成したLambdaをスケジューリング実行するCloudWatchEventsルールを作成

今回はAutoScallingグループ配下に2つのインスタンスを起動した状態でテストします。
スケーリングの設定は以下に設定しておきます。
希望する容量;2
最小キャパシティ:0
最大キャパシティ;2

Lambda関数実行用のIAM作成

Lambda関数実行用のIAMポリシーとロールを作成します。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "logs:CreateLogGroup",
        "logs:CreateLogStream",
        "logs:PutLogEvents"
      ],
      "Resource": "arn:aws:logs:*:*:*"
    },
    {
      "Effect": "Allow",
            "Action": [
                "ec2:StartInstances",
                "ec2:StopInstances",
                "ec2:RebootInstances"
            ],
            "Resource": "*"
    }
  ]
}

EC2をスタンバイ状態に変更するLambda関数の作成

指定したAutoScalling配下のインスタンスをスタンバイ状態に変更するLambda関数を作成します。
EnteringStandby ⇒ Standby状態に変更になるまでは結構時間がかかります。

このサンプルではenter_standbyを呼び出しした際に「希望する容量」がデクリメントされます。
デクリメントしたくない場合は「shouldDecrementDesiredCapacity=False」とします。

import boto3

def lambda_handler(event, context):

    # get autoscaling client
    as_client = boto3.client('autoscaling')

    as_groups = as_client.describe_auto_scaling_groups(
       AutoScalingGroupNames=[
           'asg-nginx'
    ])

    # List to hold the instance-ids
    instance_ids = []

    for i in as_groups['AutoScalingGroups']:
        for k in i['Instances']:
            instance_ids.append(k['InstanceId'])

    # enter standby            
    response = as_client.enter_standby(
        InstanceIds=instance_ids,
        AutoScalingGroupName='asg-nginx',
        ShouldDecrementDesiredCapacity=True
    )

EC2を停止するLambda関数

ここでは指定したオートスケーリンググループ配下のインスタンス一覧を
取得し停止しています。ここはタグから取得するなど色々なやり方もあると思います。

import boto3

def lambda_handler(event, context):

    # get autoscaling client
    as_client = boto3.client('autoscaling')

    as_groups = as_client.describe_auto_scaling_groups(
       AutoScalingGroupNames=[
           'asg-nginx'
    ])

    # List to hold the instance-ids
    instance_ids = []

    for i in as_groups['AutoScalingGroups']:
        for k in i['Instances']:
            instance_ids.append(k['InstanceId'])

    # get ec2 client
    ec2_client = boto3.client('ec2')
    ec2_client.stop_instances(InstanceIds=instance_ids)

EC2を開始するLambda関数

import boto3

def lambda_handler(event, context):

    # get autoscaling client
    as_client = boto3.client('autoscaling')

    as_groups = as_client.describe_auto_scaling_groups(
       AutoScalingGroupNames=[
           'asg-nginx'
    ])

    # List to hold the instance-ids
    instance_ids = []

    for i in as_groups['AutoScalingGroups']:
        for k in i['Instances']:
            instance_ids.append(k['InstanceId'])

    # get ec2 client
    ec2_client = boto3.client('ec2')
    ec2_client.start_instances(InstanceIds=instance_ids)

Lambda関数のスケジューリング

Lambdaをスケジューリング実行するCloudWatchEventsルールを作成します。
例えば毎月第3日曜日の02:00時(UTC)に実行するのでcron式には以下を指定します。

0 2 ? * 1#3 *

参考:ルールのスケジュール式

時間的な制約が無く、厳密な状態チェック等も不要で単純に実施するだけなら
ルールを3つ準備し、スタンバイ状態変更⇒EC2停止⇒EC2開始をそれぞれ
時間を開けてスケジューリングすればOKです。

以上

タイトルとURLをコピーしました