Auto Scaling Group 内のインスタンス最新化を定期的に実行するLambda関数を作ってみた

2020.11.26

どーもsutoです。

以下の記事にあるように、Auto Scaling Group 内のインスタンスを置き換える際に使える機能が実装されています。

定期的なインスタンスRefreshを実行したいという要望に対し、上記の機能をEvent Bridge+Lambdaでスケジューリングと実行ができるので、実際に試してみました。

前準備

検証用の起動テンプレートとAuto Scaling Groupをあらかじめ作成しています。

Lambda用実行ロールの作成

作成するLambdaにアタッチするIAMロールを以下のとおり作成します。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "logs:CreateLogGroup",
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": [
                "*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "autoscaling:StartInstanceRefresh",
                "autoscaling:Describe*",
                "ec2:CreateLaunchTemplateVersion",
                "ec2:DescribeLaunchTemplates"
            ],
            "Resource": [
                "*"
            ]
        }
    ]
}

EventBridgeを作成

検証用としてLambdaの実行スケジュールを以下のように作成しました。

Lambda関数の作成

インスタンスRefreshを行うためのコードは以下となります。

import boto3
from botocore.exceptions import ClientError
import json
import logging
import os

logger = logging.getLogger()
logger.setLevel(logging.INFO)

asg_client = boto3.client('autoscaling')

def trigger_auto_scaling_instance_refresh(asg_name, strategy="Rolling",
                                          min_healthy_percentage=90, instance_warmup=300):

    try:
        response = asg_client.start_instance_refresh(
            AutoScalingGroupName=asg_name,
            Strategy=strategy,
            Preferences={
                'MinHealthyPercentage': min_healthy_percentage,
                'InstanceWarmup': instance_warmup
            })
        logging.info("Triggered Instance Refresh {} for Auto Scaling "
                     "group {}".format(response['InstanceRefreshId'], asg_name))
    
    except ClientError as e:
        logging.error("Unable to trigger Instance Refresh for "
                      "Auto Scaling group {}".format(asg_name))
        raise e

def lambda_handler(event, context):

    asg_name = os.environ['AutoScalingGroupName']
    
    trigger_auto_scaling_instance_refresh(asg_name)
    
    return("Success")

また、環境変数を作成し、対象のAuto Scaling Group名を入力します。

アクセス権限で作成したIAMロールをアタッチしたら設定完了です。

実際にLambdaを実行してみた

Lambda実行前のインスタンスの状態

スケジュールでLambdaが実行された際のAuto Scaling Groupの状態を見てみます。

しっかり実行プロセスが動いていますね。

プロセス完了後のインスタンス一覧を見てみましょう。

インスタンスが置き換わっていることが確認できました。

まとめ

Cronのみならず様々なイベントが発生した際に、上記Lambdaを実行するようにトリガーを設定できます。定期的にインスタンスの置き換え作業を自動化したいときなどにご活用できればと思います。

参考

https://docs.aws.amazon.com/cli/latest/reference/autoscaling/start-instance-refresh.html https://github.com/aws-samples/ec2-auto-scaling-instance-refresh-sample