ALBから自身のEC2インスタンスが切り離されるのを待つ
すごく限定的な用途ですが、自身のEC2インスタンスが、ALB(Application Load Balancer)から切り離されるのを待つシェルスクリプトを作成しました。
やりたかったこと(背景)
Webアプリケーションをデプロイ後に起動するが、しばらくの間、諸々の事情でリクエストを受け付けてほしくない。
(遭遇したケースの一例は、Webアプリケーションの起動直後にリクエストを多数受け付けると、データベースコネクションプールの処理が追い付かず、コネクション数が跳ね上がるという現象だった。)
AWS CLI で ALB(ターゲットグループ)から一時的に削除する方が手っ取り早いが、その権限が付与されていない。
なので、ALBのヘルスチェックでNGになったことによって、切り離されたことを確認してから、Webアプリケーションを起動したい。
(切り離されてから自動で復帰するまでの間に、対処できるので)
AWSマネジメントコンソールで、ALBのヘルス状態を確認するのは面倒。
AWS CLI を使って、指定のEC2インスタンスのALB上のヘルス状況を確認する
aws elbv2 describe-target-health
を使って、確認する。
権限を付与されているなら、下記でターゲットグループから一旦削除して再登録した方が手っ取り早い。
aws elbv2 deregister-targets
aws elbv2 register-targets
が、今回は、上記の通り、事情があり、待つことに。
ヘルス状態を確認して、Unhealthy になるまで待つシェルスクリプトを作成してみる。
動作確認環境
$ uname -r
4.14.305-227.531.amzn2.x86_64
$ bash --version
GNU bash, version 4.2.46(2)-release (x86_64-koji-linux-gnu)
$ aws --version
aws-cli/1.18.147 Python/2.7.18 Linux/4.14.305-227.531.amzn2.x86_64 botocore/1.18.6
免責事項
- スクリプトの実行は自己責任でお願いします。本スクリプトを実行することにより生じるいかなる問題に関しましても、筆者は一切責任を負いません。
#!/bin/bash
# ALBから自身のEC2インスタンスが切り離されるのを待つ
#
# ヘルスチェック設定 例
# 非正常のしきい値: 2ヘルスチェックの連続的な失敗
# タイムアウト: 5秒
# 間隔: 30秒
# 非正常のヘルスチェック状態を確認する回数
MAX_CHECK_COUNT=7
# 非正常のヘルスチェック状態を確認する間のスリープ秒数
SLEEP_SECONDS=10
# ALB ターゲットグループ ARN
ALB_TG_ARN=${1:-"ターゲットグループのARN"}
# 指定のインスタンスのALBのヘルス状況を返す
function check_alb_health() {
local TARGET_GROUP_ARN=$1
local TARGET_ID=$2
local STATE=$(aws elbv2 describe-target-health --target-group-arn "${TARGET_GROUP_ARN}" --output text \
--query "TargetHealthDescriptions[?Target.Id == '${TARGET_ID}'].TargetHealth.State | [0]")
echo "${STATE}"
}
# ALB から切り離されるまで待つ(関数の呼出し元でリターンコードで成否判定分岐する)
function wait_until_unhealthy() {
# 自身のEC2インスタンスのIDをインスタンスメタデータから取得する (※1)
INSTANCE_ID=$(curl -s http://169.254.169.254/latest/meta-data/instance-id)
# スリープしながら繰り返しALBターゲットグループのヘルスチェック状態を確認する
for (( i = 0; i < ${MAX_CHECK_COUNT}; i++ )); do
local STATE=$(check_alb_health "${ALB_TG_ARN}" "${INSTANCE_ID}")
echo -n "${STATE}"
if [[ "${STATE}" != "healthy" ]]; then
echo "[OK]"
return 0
fi
echo "ALBのヘルスチェック状態を確認しています ... "
sleep ${SLEEP_SECONDS}
done
echo "ALBから切り離されませんでした。" >&2
return 1
}
# (ここで、Webアプリケーションのデプロイ作業などが実行される。)
# ALB から切り離されるまで待つ
wait_until_unhealthy || exit 1
# (ここで、Webアプリケーションを起動する。)
※1 のEC2インスタンスIDの取得については、下記の公式の情報を参考に。
あとがき
cron などで定期的に実行して、ALBのターゲットグループからヘルス状態を確認し、SlackのWebhookなどに、curl などでリクエストを送れば、簡単に異常通知を送ることができそうですね。
CloudWatchアラーム と Amazon SNS と AWS Chatbot とか組み合わせれば、詳細な情報を含めて通知が可能ですが、単に通知を送るだけなら、そんな方法もありかなと。