いまさらながらEC2でAutoScalingをやってみました
そのときのメモ
要件
手順
- LaunchConfigurationの作成
- AutoScalingGroupの作成
- SNSの作成
- SQSの作成
- lifecyclehookの登録
- lifecyclehookをコントロールするためのスクリプト作成
Launch Configuration
AutoScaling時に立ち上げるインスタンスの設定をしていく
設定項目
IP Address Type
- VPCで構築しているので
Do not assign a public IP address to any instances.
を選択(PublicIPは設定しない)
- VPCで構築しているので
あとは通常のインスタンスを作成する手順と同様に設定していく
Auto Scaling Group
何台インスタンスがある状態が正常か(desire)、どのAMIからインスタンスを起動していくのかなどの設定をしていく
Auto Scaling Groupの選択
- 立ち上げるインスタンスの設定(launch configuration)を選択
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やサーバ数が変更されるか確認するだけですね
こことか
こことか
lifecyclehookの設定
通常だけならこれだけでもいいのですが、サービスとなるとログどうするの?とか現在処理中のタスクが完了してからでないと整合性が取れなくなってしまったりと問題がありますね
そこでlifecyclehookの登場です
lifecyclehookを用いることで下記のようなことができるようになります
スケールアウト時
- デプロイ作業が終わってからLBに投入
- リクエストを受け付けられない状態のときにLBに入ってしまったら問題
スケールイン時
- 各種ログのバックアップ作業をしてからシャットダウン
- Terminateされてログが途中までしか転送されてなかったら調査で問題
下記のイメージでやってみました
- workerを動かしてるサーバ群をautoscaleで扱う
- groupのdesireが減ったらlifecyclehookでSQSに通知
- 通知を受け取ったスクリプトがTerminate対象のサーバに対してTerminate前作業を実行
- サーバで動いているdaemonの停止
- td-agentの停止
- lifecyclehookを進めるコマンドを叩く
- 対象サーバがTerminateされる
これでスケールイン時のTerminate対象のサーバはアプリケーションログを全てログサーバに送ってからTerminateされるように出来るはずです
参考
SQSの設定
lifecyclehookの通知で使うためSQSの作成を行います
特に特殊な設定はしませんでした
IAM Roleの登録
Autoscaling関連の通知へのアクセス権を持っているRoleを追加しておきます
- 登録
Autoscaling Notification Accessを選択してアタッチする
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に)変わったことを確認
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
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
まとめ
SQS
- あんまり記事とか見ることがないけど使い方次第で色々出来そう
lifecyclehook
- 使えそうな用途
- Terminage前のログの退避
- サービスイン前のデプロイ
- consoleから実行できるようになるとより便利?
- 使えそうな用途
SQSのポーリングはlambdaでも実現可能
- 最近だとSQS -> lambdaでやる記事が多い
- 流行に乗ってlambdaを使いたかったものの対応してるリージョンではなかったので断念、、、
ただ単にautoscaleを入れるだけなら簡単ですが、現状動いているサービスに乗っけていくのはなかなか大変でした
AutoScaleを導入するとimmutableが前提になってくるのと、そもそものサービスの作り自体がクラウドを使っていく前提ではなかったので、考えることが多かったです
勉強になりました