AutoScaleを設定し、lambdaでAMIとAutoScaleの設定を自動更新する
今回はAuto Scaleの設定のまとめです。
概要
負荷分散のためにAutoScaleを検討することはよくあることです。
ゲームのイベントなどでは負荷がかかる時間帯が決まっているので、常時起動しているサーバーを減らしAutoScaleのスケージュールで設定することで費用を抑えることが出来ます。
※AutoScaleは起動に時間がかかるので、スケーリングポリシーでは突発的な負荷に対応できないのでスケジュールを使っています。
問題点
AutoScaleを設定した場合、設定しているAMIのassetやsourceが起動中のインスタンスと違うといった事が起こります。
そういった場合にAMIを更新し、自動的AutoScaleに割り当てる設定を行います。
AutoScaleグループの作成
今回の設定は元々あるAutoScaleグループの設定を置き換えるので先にAutoScaleグループを作成しておきます。
・AWSコンソールの[AUTO SCALING]→[起動設定]→[起動の作成]
※ここの起動設定は最終的に使わないので適当でOKです
・AWSコンソールの[AUTO SCALING]→[AUTO SCALINGグループ]→[AUTO SCALINGグループの作成]
上記の起動設定を選択、下記を設定
・ネットワーク
・グループ名
・ロードバランシング
※今回はスケジュールなのでスケーリングポリシーは設定しない ※通知を使用するとauto scaleの情報をlambda等に引き渡して色々出来ます。 ※タグを使いauto scaleで作成されたインスタンスに適用できます。
※ここで作成したAUTO SCALINGグループの名前を控えておきます。
lambdaを設定
・[Blank Function]→リストから[CloudWatch Events]を選択 ・ルール:新規のルール ・ルール名:任意 ・ルール説明:任意 ・ルールタイプ:スケジュール ・スケジュール式:cron(0 * * * ? *) ※cronの設定と同じ、上記は1時間毎 ・トリガーの有効化にチェック
・名前:任意 ・説明:任意 ・ランタイム:python
・ロール:[カスタムロールの作成]を選択、IAMに下記をアタッチし作成、再度[既存のロールを選択]で作成したIAMを選択
・コード:下記を貼り付けて***の部分を自分の環境に置き換える
import boto3 import time from botocore.client import ClientError from datetime import datetime, timedelta, tzinfo import logging logger = logging.getLogger() logger.setLevel(logging.INFO) ec2 = boto3.client('ec2') autoscaling = boto3.client('autoscaling') instance = "***" #コピー元のec2インスタンスID(例:i-22a9edc2ted27d2a1) device_name = "***" #コピー元のec2のブロックデバイス(例:/dev/sda1) image_prefix = "***" #amiの名前の識別子(任意※他のAMIで使っていない文字) launch_prefix = "***" #auto scaleの起動設定の名前の識別子(任意※他の起動設定で使っていない文字) ec2_volume_size = *** #ebsのボリュームサイズ(単位:GB) ec2_volume_type = "***" #ebsのボリュームタイプ(例:gp2) secrity_group = [***] #ec2インスタンスのセキュリティグループ ec2_instance_type = "***", #ec2インスタンスタイプ(例:c4.2xlarge) ec2_key_name = "***", #ec2インスタンスのキーペア名 auto_scaling_group_name ="***",#作成したAutoScaleGroup名 def lambda_handler(event, context): try: dstr = datetime.now().strftime('_%Y-%m-%d-%H-%M-%S_') + instance logger.warning("create ami:%s" % (dstr)) new_ami = ec2.create_image(Name=image_prefix + dstr ,InstanceId=instance,NoReboot=True,DryRun=False) recv = ec2.describe_images(Owners=['self']) list=[] target = image_prefix for img in recv['Images']: if target in img['ImageLocation']: list.append(img) s_list = sorted(list,key=lambda h: h['CreationDate']) if len(s_list) > 0: del_target = s_list[0] logger.info("delete ami:%s" % (del_target['Name'])) ec2.deregister_image(ImageId=del_target['ImageId'],DryRun= False) dstr = datetime.now().strftime('_%Y-%m-%d-%H-%M-%S') logger.info("create auto scale launch config:%s" % (dstr)) device = {} device['DeviceName'] = device_name ebs = {} ebs['VolumeSize'] = ec2_volume_size ebs['VolumeType'] = ec2_volume_type ebs['DeleteOnTermination'] = True device['Ebs'] = ebs device_mapping = [device] launch_name = launch_prefix + dstr res = autoscaling.create_launch_configuration( LaunchConfigurationName = launch_name, ImageId = new_ami['ImageId'], InstanceType = ec2_instance_type, SecurityGroups = secrity_group, KeyName = ec2_key_name, BlockDeviceMappings = device_mapping, AssociatePublicIpAddress = True ); logger.info("update auto scale group name:%s" % (launch_name)) res = autoscaling.update_auto_scaling_group( AutoScalingGroupName=auto_scaling_group_name LaunchConfigurationName = launch_name ); target = launch_prefix recv = autoscaling.describe_launch_configurations() list=[] for launch in recv['LaunchConfigurations']: if target in launch['LaunchConfigurationName']: list.append(launch) s_list = sorted(list,key=lambda h: h['CreatedTime']) if len(s_list) > 2: del_target = s_list[0] logger.info("delete launch config:%s" % (del_target['LaunchConfigurationName'])) autoscaling.delete_launch_configuration( LaunchConfigurationName=del_target['LaunchConfigurationName'], ) logger.info("end ami update") except ClientError as e: logger.error( e ) return 'end'
auto scaleのスケジュールを登録する
以上
注意事項
※最初はelbのhealthチェックだけじゃなくwebサーバーのログやawsコンソールで正常な起動を確認すること
※デプロイがAMIの更新と被らないようにすること