notebook

都内でWEB系エンジニアやってます。

Auto Scaling(lifecyclehook)を使ってみる

いまさらながらEC2でAutoScalingをやってみました

そのときのメモ

要件

  • VPC内のバッチ処理をするサーバのスケーリング
  • 忙しい時間帯が決まっているのでその時間帯のみスケールアウト

    • スケジューリング
  • lifecyclehookを使ってスケールイン時に処理の正常終了を待つ

手順

  • LaunchConfigurationの作成
  • AutoScalingGroupの作成
  • SNSの作成
  • SQSの作成
  • lifecyclehookの登録
  • lifecyclehookをコントロールするためのスクリプト作成

Launch Configuration

AutoScaling時に立ち上げるインスタンスの設定をしていく

設定項目

参考: swfz.hatenablog.com

  • IP Address Type

    • VPCで構築しているのでDo not assign a public IP address to any instances.を選択(PublicIPは設定しない)
  • あとは通常のインスタンスを作成する手順と同様に設定していく

Auto Scaling Group

何台インスタンスがある状態が正常か(desire)、どのAMIからインスタンスを起動していくのかなどの設定をしていく

  • Auto Scaling Groupの選択

  • Group size

    • いくつ立ち上げるか
  • Create Auto Scaling Group

    • 時間スケールなのでKeep this group at its initial sizeを選択

notificationの追加

スケール(イン,アウト)した際の通知先

あらかじめSNSトピックを作成しておく

ここで設定したSNSトピックへ通知が送られる(下記から複数選択可能)

  • launch
  • terminate
  • fail to launch
  • fail to terminate

スケジュールでスケール

Scheduled Actionsのタブで新たにスケジュールを決めて設定を変更することが出来る

  • Min
    • 最小
  • Max
    • 最大
  • Desired Capacity
    • 指定台数
  • Recurrence(実行間隔)
    • Crontabでの設定も行える
    • UTC
  • Start Time
    • いつからはじめるか

単純なautoscalingの設定ならここまでです

指定の時間になったらDesireやサーバ数が変更されるか確認するだけですね

こことか

f:id:swfz:20160525100920p:plain

こことか

f:id:swfz:20160525100930p:plain

lifecyclehookの設定

通常だけならこれだけでもいいのですが、サービスとなるとログどうするの?とか現在処理中のタスクが完了してからでないと整合性が取れなくなってしまったりと問題がありますね

そこでlifecyclehookの登場です

lifecyclehookを用いることで下記のようなことができるようになります

スケールアウト時

  • デプロイ作業が終わってからLBに投入
    • リクエストを受け付けられない状態のときにLBに入ってしまったら問題

スケールイン時

  • 各種ログのバックアップ作業をしてからシャットダウン
    • Terminateされてログが途中までしか転送されてなかったら調査で問題

下記のイメージでやってみました

f:id:swfz:20160525100941p:plain

  • workerを動かしてるサーバ群をautoscaleで扱う
  • groupのdesireが減ったらlifecyclehookでSQSに通知
  • 通知を受け取ったスクリプトがTerminate対象のサーバに対してTerminate前作業を実行
    • サーバで動いているdaemonの停止
    • td-agentの停止
    • lifecyclehookを進めるコマンドを叩く
  • 対象サーバがTerminateされる

これでスケールイン時のTerminate対象のサーバはアプリケーションログを全てログサーバに送ってからTerminateされるように出来るはずです

参考

dev.classmethod.jp

dev.classmethod.jp

SQSの設定

lifecyclehookの通知で使うためSQSの作成を行います

特に特殊な設定はしませんでした

参考: swfz.hatenablog.com

IAM Roleの登録

Autoscaling関連の通知へのアクセス権を持っているRoleを追加しておきます

  • 登録

Autoscaling Notification Accessを選択してアタッチする

f:id:swfz:20160525101055p:plain

ARNのメモ

後のlifecyclehookの設定で使うのでARNの値をメモしておく

  • autoscaling notification用のIAM Roleの ARN
  • lifecyclehookで使用するSQSのARN

lifecyclehookの登録

lifecyclehook自体はLaunch(EC2起動)時とTerminate(EC2シャットダウン)時の設定ができる

今回インスタンス起動時は特に何かチェックする必要はないので終了時のみ登録する(CLIで)

  • terminate時のhook登録
aws autoscaling put-lifecycle-hook \
--lifecycle-hook-name TerminateHook \
--auto-scaling-group-name sandbox-worker \
--lifecycle-transition autoscaling:EC2_INSTANCE_TERMINATING \
--notification-target-arn arn:aws:sqs:ap-southeast-1:111111111111:autoscale-worker \
--role-arn arn:aws:iam::111111111111:role/autoscale-worker
  • auto-scaling-group-name に対象のautoscaling groupを指定
  • notification-target-arn にSQSのARNを指定
  • role-arn にIAMRoleのARNを指定

スケールイン

AutoScaleGroupのDesireの値を下げてみる

Terminate対象のインスタンスのステータスが(Terminating:Waitに)変わったことを確認

f:id:swfz:20160525101114p:plain

SQSに通知が行くように登録したのでSQSの中身も確認します

aws sqs receive-message --queue-url https://ap-southeast-1.queue.amazonaws.com/111111111111/autoscale-worker  --region ap-southeast-1
{
    "Messages": [
        {
            "Body": "{\"AutoScalingGroupName\":\"sandbox-worker\",\"Service\":\"AWS Auto Scaling\",\"Time\":\"2016-05-14T17:11:05.965Z\",\"AccountId\":\"111111111111\",\"LifecycleTransition\":\"autoscaling:EC2_INSTANCE_TERMINATING\",\"RequestId\":\"d534e046-3c83-40a9-889c-ed198430892b\",\"LifecycleActionToken\":\"4789bd11-4ecb-4f22-9ae8-d44579420f9a\",\"EC2InstanceId\":\"i-da11111e\",\"LifecycleHookName\":\"TerminateHook\"}",
            "ReceiptHandle": "AQEBREd1OY6JGZJa3szHHYBayLaPrJ2pEEQGPBoRa+XMhun+A2Qd27JAZEgzS34P0JNUyz8BsPFHQ76nNk8KcWfukS0rYhUEn3fdTjSAj5Xd3wF6yQSyG6nV5DuKbF3QLG9h3cerWsy+1R9AWz7UlXt9Rur25EOS2+N8jmqZ66k7UPmBeMRkQCqZLteQ4OqwJ7oW3UD2FMjzuKn97eQvp5XRUWnhbqJIQqYp+K2rozt9ElSrkoOyIv8IyjKZgqMvgr6BFpL8cQSbfBGteh9DIYpUcm9uMYpyD/xI5Z2fDv/LPDLIs5a39uTbxgBJT52/Wk94H9zt+Gbsueebt66T5TbAaf3Ig6zKOYTLECfNLAtLwkGzSZI7wxe6OLKOZ/lLbWxwitAnP+Q8FUz0ThSruduP3A==",
            "MD5OfBody": "c4b93d2488c806492dd24238d6ed26cc",
            "MessageId": "5aa16c01-0d1d-4ead-b598-b453872ef90e"
        }
    ]
}

確認できました

この間にTerminate前作業を行います

Wait間に行う作業

lifecyclehookでTerminateされる前に作業が出来るようになりました

スケールインのトリガー起動時の通知先をSQSにしたのでSQSのキューをポーリングして逐次処理していくスクリプトを書きます

処理内容を簡単にまとめると下記

  • scriptの停止
perl bin/hogedaemon stop
  • td-agentの停止
sudo /etc/init.d/td-agent stop

これをのshellscriptにまとめました(stop_as_worker.sh)

  • lifecycleの完了通知を送る

SQSから受け取ったBodyの中身からlifecycle-action-token,auto-scaling-group-name,lifecyclehook-hook-nameなどを取得しlifecycleの完了通知を送る

aws autoscaling complete-lifecycle-action \
--lifecycle-action-token 4789bd11-4ecb-4f22-9ae8-d44579420f9a \
--auto-scaling-group-name sandbox-worker \
--lifecycle-hook-name TerminateHook \
--lifecycle-action-result CONTINUE

f:id:swfz:20160525101134p:plain

Terminating:Proceedに変わりました、しばらく経つと表示が消えます(インスタンスもTerminateされます)

  • SQSメッセージの削除

処理した後はメッセージを削除する

aws sqs delete-message --queue-url https://ap-southeast-1.queue.amazonaws.com/111111111111/autoscale-worker --region ap-southeast-1 --receipt-handle AQEBREd1OY6JGZJa3szHHYBayLaPrJ2pEEQGPBoRa+XMhun+A2Qd27JAZEgzS34P0JNUyz8BsPFHQ76nNk8KcWfukS0rYhUEn3fdTjSAj5Xd3wF6yQSyG6nV5DuKbF3QLG9h3cerWsy+1R9AWz7UlXt9Rur25EOS2+N8jmqZ66k7UPmBeMRkQCqZLteQ4OqwJ7oW3UD2FMjzuKn97eQvp5XRUWnhbqJIQqYp+K2rozt9ElSrkoOyIv8IyjKZgqMvgr6BFpL8cQSbfBGteh9DIYpUcm9uMYpyD/xI5Z2fDv/LPDLIs5a39uTbxgBJT52/Wk94H9zt+Gbsueebt66T5TbAaf3Ig6zKOYTLECfNLAtLwkGzSZI7wxe6OLKOZ/lLbWxwitAnP+Q8FUz0ThSruduP3A==

これで完了!!!

script

一連の流れをスクリプト化します

  • lifecycle_controller.sh

後は作成したスクリプトをデーモン化して起動するなりジョブスケジューラで管理するなりしておけばスケールイン時にスクリプトを実行してくれるのでより厳密に管理できるようになります

今回はrundeckで毎分スクリプトを実行させ続けるようにしました

ちょうど記事を書いてる途中で見つけたので最初に書いた図をcloudcraftでも書いてみましたw

f:id:swfz:20160525101153p:plain

まとめ

  • SQS

    • あんまり記事とか見ることがないけど使い方次第で色々出来そう
  • lifecyclehook

    • 使えそうな用途
      • Terminage前のログの退避
      • サービスイン前のデプロイ
    • consoleから実行できるようになるとより便利?
  • SQSのポーリングはlambdaでも実現可能

    • 最近だとSQS -> lambdaでやる記事が多い
    • 流行に乗ってlambdaを使いたかったものの対応してるリージョンではなかったので断念、、、

ただ単にautoscaleを入れるだけなら簡単ですが、現状動いているサービスに乗っけていくのはなかなか大変でした

AutoScaleを導入するとimmutableが前提になってくるのと、そもそものサービスの作り自体がクラウドを使っていく前提ではなかったので、考えることが多かったです

勉強になりました