※この記事はサーバーワークスAdvent Calendar 2016、12月13日の記事として書いています。
AWSは全部CLIで操作したい
サーバーワークスといえばAWS、AWSといえばAPIが豊富。APIの操作といえばCLI、ですよね?そうですよね。
ALB最高だけどさ
AWSのApplication Load Balancing(ALB)について。
パス毎に異なるターゲットにアクセスを振り分けたり非常に便利なALBですが、ひとつだけ気になる点があったんですね。
機能が増えた分、これまでの**Elastic Load Balancing(ELB)**と比較して操作がちょっとめんどくさいなー、と思っていました。
まずELBと根本的に違うのはターゲットグループの存在です。
バックエンドインスタンスはターゲットグループに所属し、フロントのALBはルールに基づいてターゲットグループへリクエストをルーティングします。
なので、平易に書くと
ALB <---> ターゲットグループ <---> インスタンス
となるわけです。
というわけで、バックエンドのEC2インスタンスを取り外したりする際には、ALBではなくターゲットグループを操作する必要があります。処理にはターゲットグループのARNが必要となります。
例えば
あるALBに紐付いているターゲットグループのARNを引っ張ってこようと思うと、以下のようなシェルコマンドになります。
$ aws elbv2 describe-load-balancers ¥
--query 'LoadBalancers[].[LoadBalancerName,LoadBalancerArn]' ¥
--output text | grep -E "^<ALB名>¥t.*" | cut -f2 | ¥
xargs -i aws elbv2 describe-listeners ¥
--load-balancer-arn {} ¥
--query 'Listeners[].DefaultActions[].TargetGroupArn' --output text
長い。ALBと言いつつ、APIのサブコマンドはelbv2ってのもなかなかややこしいっすよね。
こうして取得したARNに対して、さらにインスタンスを追加したり取り外したりといった指示を出すことになります。長い。
スクリプト作成
なので、このへんを単純化するシェルスクリプトをいくつか書きました。コメント部に引数とか書いといたんで適当な名前で保存して使ってやって下さい。
実行にはAWS CLIのインストールが必要です。インストール方法やら何やらはこのへんを参考にどうぞ。今回紹介するスクリプトはいずれもプロファイルの指定が必要ですのでご注意を。
やりたいこと
- ALBとそこに紐付いたターゲットグループ、そしてその下のインスタンスのステータスをずらっと表示させたい
- インスタンスIDだけじゃなくてインスタンスName Tagを表示させたい
- インスタンス名を指定してALBターゲットグループへのAttach, Detachをしたい
- ターゲットグループのARN取得するのがめんどくさいので、ターゲットグループ名だけを指定して済ませたい
ALBのステータス表示
#/bin/bash
#
# ./alb_show_health.sh Profile ALBName
#
alb_show_health() {
local profile=$1;
local alb=$2
# ALB名からALBのARNを取得
local alb_arn=`aws elbv2 describe-load-balancers \
--profile $profile \
--query 'LoadBalancers[].[LoadBalancerName,LoadBalancerArn]' \
--output text | grep -E "^${alb}[[:space:]].*" | cut -f2` || return $?
if [ -z $alb_arn ] ; then
echo "ALB \"$alb\" is not exist."
exit 1
fi
# ALB ARNからTarget Groupを取得
local target_groups=`aws elbv2 describe-listeners \
--profile $profile \
--load-balancer-arn $alb_arn \
--query 'Listeners[].DefaultActions[].TargetGroupArn' \
--output text` || return $?
# Target Groupsに紐付いたホストの状態を一覧表示
for target_group_arn in ${target_groups[@]}
do
local target_group_name=`sed 's%^.*:.*/\(.*\)\.*/.*%\1%' <<< $target_group_arn`
echo "--- Health Status of Target Group \"$target_group_name\" ---"
#次のループのため空白をIFSにしないよう一時的に変更
IFS_BACKUP=$IFS
IFS=$'\n'
# 可視性のため、EC2のNameタグを取得するループ
for instance in `aws elbv2 describe-target-health \
--target-group-arn $target_group_arn \
--profile $profile \
--query 'TargetHealthDescriptions[].[Target.Id,TargetHealth.State]' \
--output text`
do
# instance=インスタンスID\tステータス
local instance_id=`echo $instance | cut -f1`
local instance_state=`echo $instance | cut -f2`
local instance_name=`aws ec2 describe-tags \
--profile $profile \
--filters "Name=resource-id,Values=$instance_id" "Name=tag-key,Values=Name" \
--query "Tags[].Value" \
--output text`
echo "$instance_name $instance_id $instance_state"
done
IFS=$IFS_BACKUP
done
}
# メイン実行部
if [ $# -ne 2 ] ; then
echo "Missing Argument"
echo 'Usage: ./alb_show_health Profile ALBName'
exit 1
fi
alb_show_health $@
実行結果例
--- Health Status of Target Group "admin" ---
admin-001 i-0123456789abcdef0 healthy
admin-002 i-123456789abcdef01 healthy
--- Health Status of Target Group "web" ---
web-001 i-23456789abcdef012 healthy
web-002 i-3456789abcdef0123 healthy
web-003 i-456789abcdef01234 draining
ALBにくっついたターゲットグループごとに、紐付いたインスタンスの情報をだらだらっと出力してくれます。
※めっちゃAPIコールしまくってるんでうまい方法があったら知りたい
上記スクリプトでインスタンス名とインスタンスIDが表示されるので、以下のスクリプトでよしなにALBから追加したり削除してあげることができます。
ALBターゲットグループにカジュアルにインスタンスを追加する
#/bin/bash
#
# ./alb_register_instance.sh Profile TargetGroupName InstanceName
#
alb_register_instance() {
local profile=$1;
local target_group_name=$2
local target_instance_name=$3
local target_group_arn=`aws elbv2 describe-target-groups \
--profile $profile \
--query 'TargetGroups[].[TargetGroupName,TargetGroupArn]' \
--output text | grep -E "^$target_group_name[[:space:]]" | cut -f2`
if [ -z $target_group_arn ] ; then
echo "Target Group \"$target_group_name\" is not found"
exit 1
fi
# インスタンス名の重複対策でID指定を許可
if [[ "$target_instance_name" =~ ^i-[0-9a-f]{17}$ ]]; then
target_instance_id=$target_instance_name
else
local target_instance_id=`aws ec2 describe-instances \
--profile $profile \
--filters "Name=tag-key,Values=Name" "Name=tag-value,Values=$target_instance_name" \
--query 'Reservations[].Instances[].InstanceId' \
--output text`
fi
if [ -z $target_instance_id ] ; then
echo "Instance \"$target_instance_name\" is not found"
exit 1
fi
# register
aws elbv2 register-targets \
--profile $profile \
--target-group-arn $target_group_arn \
--targets Id=$target_instance_id
return $?
}
# メイン実行部
if [ $# -ne 3 ] ; then
echo "Missing Argument"
echo 'Usage: ./alb_register_instance.sh Profile TargetGroup InstanceName'
exit 1
fi
alb_register_instance $@
ALBターゲットグループからカジュアルにインスタンスを削除する
#/bin/bash
#
# ./alb_deregister_instance.sh Profile TargetGroupName InstanceName
#
alb_deregister_instance() {
local profile=$1;
local target_group_name=$2
local target_instance_name=$3
local target_group_arn=`aws elbv2 describe-target-groups \
--profile $profile \
--query 'TargetGroups[].[TargetGroupName,TargetGroupArn]' \
--output text | grep -E "^$target_group_name[[:space:]]" | cut -f2`
if [ -z $target_group_arn ] ; then
echo "Target Group \"$target_group_name\" is not found"
exit 1
fi
# インスタンス名の重複対策でID指定を許可
if [[ "$target_instance_name" =~ ^i-[0-9a-f]{17}$ ]]; then
target_instance_id=$target_instance_name
else
local target_instance_id=`aws ec2 describe-instances \
--profile $profile \
--filters "Name=tag-key,Values=Name" "Name=tag-value,Values=$target_instance_name" \
--query 'Reservations[].Instances[].InstanceId' \
--output text`
fi
if [ -z $target_instance_id ] ; then
echo "Instance \"$target_instance_name\" is not found"
exit 1
fi
# deregister
aws elbv2 deregister-targets \
--profile $profile \
--target-group-arn $target_group_arn \
--targets Id=$target_instance_id
return $?
}
# メイン実行部
if [ $# -ne 3 ] ; then
echo "Missing Argument"
echo 'Usage: ./alb_deregister_instance.sh Profile TargetGroup InstanceName'
exit 1
fi
alb_deregister_instance $@
〆
以上。
どちらかといえば実用的な方面に寄せ、Advent Calendarに載せるにしては非常に地味な記事となってしまってごめんなさい感溢れてますが、明日はきっとokochang氏がかっ飛ばしてくれるのでどうぞご期待ください!