読者です 読者をやめる 読者になる 読者になる

AWS CLI で ALB 配下のインスタンスを deregister / register する

AWS CLI で ELB 配下のインスタンスをローリングデプロイする方法は去年にまとめた.aws elb deregister-instances-from-load-balanceraws elb register-instances-with-load-balancer を使うだけじゃなく,aws elb describe-instance-health を使って waiter を実装した点がポイントだった.ちなみに EC2 だと waiter を実装する必要はなく aws ec2 wait で完了を待つことができる.

kakakakakku.hatenablog.com

ALB の場合 aws elbv2 を使う

1年が経過し,今度は ALB 配下のインスタンスをローリングデプロイしようと考えていて,調べたところ ALB の場合は aws elbv2 を使う必要があった.さらに,ターゲットグループなど ELB とは違う概念があるため,サブコマンドもオプションも異なっていた.

ドキュメント

今回,以下の3コマンドを使った.

オプションは --target-group-arn にターゲットグループの ARN を指定し,--targets にインスタンス ID を指定する.ただし --targets に指定するときはフォーマットが決まっているため,以下のようにする.なお,ポートは省略することができる.

Id=string,Port=integer …

ALB のステータス

ELB は InServiceOutOfService のステータスしか存在しなかったが,ALB の場合はもっと多くある.

  • initial
  • healthy
  • unhealthy
  • unused
  • draining

ALB から deregister すると healthy → draining → unused と遷移する.register すると unused → initial → healthy と遷移する.unhealthy はヘルスチェックに失敗したときに出るため,通常 deregister / register をするときには出ない.

(正確に言うと他の遷移もあると思う)

f:id:kakku22:20170422233304j:plain

docs.aws.amazon.com

ALB ターゲットグループのドレインに注意する

ターゲットグループのデフォルトのドレインは 300 秒に設定されているため,deregister すると,毎回 300 秒 draining のままになる.アプリケーションの特性次第だけど,基本的には長いと思うので,30 秒などに短くした方が良いと思う.

docs.aws.amazon.com

ドレインに関しては前に検証した記事が参考になると思う.

kakakakakku.hatenablog.com

aws_utils.sh

共通機能は去年と同じで ALB を操作する部分を追加した.

#!/bin/sh

# ALB の状態を確認する間隔(秒)
SLEEP=3

#######################################
# AWS CLI をチェックする
#######################################
check_awscli() {
  if ! which aws >/dev/null; then
    echo 'awscli not found'
    exit 2
  fi
}

#######################################
# ホスト名からインスタンス ID を取得する
# Arguments:
#   $1 HOST NAME
# Returns:
#   INSTANCE ID
#######################################
get_instance_id() {
  instance_id=$(/usr/bin/aws ec2 describe-instances --filter "Name=tag:Name,Values=$1" --query Reservations[].Instances[].InstanceId --output text)
  if [ -z "$instance_id" ]; then
    echo 'host not found'
    exit 2
  fi
  echo ${instance_id}
}

#######################################
# インスタンスが ALB に反映されるまで待機する
# https://docs.aws.amazon.com/cli/latest/reference/elbv2/describe-target-health.html
# Arguments:
#   $1 TARGET GROUP ARN
#   $2 INSTANCE ID
#   $3 STATE (healthy or unused)
#######################################
alb_waiter() {
  while :
  do
    # 状態(healthy or unused)を取得する
    state=$(/usr/bin/aws elbv2 describe-target-health --target-group-arn $1 --targets Id=$2 --query TargetHealthDescriptions[].TargetHealth.State --output text)
    if [ "$3" = "${state}" ]; then
      echo "  TargetGroupARN: $1 InstanceId: $2 State:$3"
      break
    else
      echo "  TargetGroupARN: $1 InstanceId: $2 State:$state"
    fi
    sleep ${SLEEP}
  done
}

#######################################
# ALB からインスタンスを外す
# https://docs.aws.amazon.com/cli/latest/reference/elbv2/deregister-targets.html
# Arguments:
#   $1 TARGET GROUP ARN
#   $2 INSTANCE ID
#######################################
alb_deregister() {
  /usr/bin/aws elbv2 deregister-targets --target-group-arn $1 --targets Id=$2 > /dev/null
}

#######################################
# ALB にインスタンスを付ける
# https://docs.aws.amazon.com/cli/latest/reference/elbv2/register-targets.html
# Arguments:
#   $1 TARGET GROUP ARN
#   $2 INSTANCE ID
#######################################
alb_register() {
  /usr/bin/aws elbv2 register-targets --target-group-arn $1 --targets Id=$2 > /dev/null
}

start.sh

汎用的に書くとこのようになる.

#!/bin/sh

# スクリプトをインポートする
. ./aws_utils.sh

# コマンドチェックと定数の設定
check_awscli
ALB_TARGET_GROUP_ARN ='arn:aws:elasticloadbalancing:ap-northeast-1:111111111111:targetgroup/xxxxx/2222222222222222'

HOSTS=(web01 web02)

for host in ${HOSTS[@]}
do
  # インスタンス ID を取得する
  INSTANCE_ID=$(get_instance_id ${host})

  # unused になるまで待機
  echo " deregister : ${INSTANCE_ID}"
  alb_deregister ${ALB_TARGET_GROUP_ARN} ${INSTANCE_ID}
  alb_waiter ${ALB_TARGET_GROUP_ARN} ${INSTANCE_ID} 'unused'

  #
  # ホストごとにデプロイなどを実行する
  #

  # healthy になるまで待機
  echo " register : ${INSTANCE_ID}"
  alb_register ${ALB_TARGET_GROUP_ARN} ${INSTANCE_ID}
  alb_waiter ${ALB_TARGET_GROUP_ARN} ${INSTANCE_ID} 'healthy'
done

実行すると,以下のように waiter をして,期待通りに動く.

 deregister : i-xxxxxxxx
  TargetGroupARN: arn:aws:elasticloadbalancing:ap-northeast-1:111111111111:targetgroup/xxxxx/2222222222222222 InstanceId: i-xxxxxxxx State:draining
  TargetGroupARN: arn:aws:elasticloadbalancing:ap-northeast-1:111111111111:targetgroup/xxxxx/2222222222222222 InstanceId: i-xxxxxxxx State:draining
  TargetGroupARN: arn:aws:elasticloadbalancing:ap-northeast-1:111111111111:targetgroup/xxxxx/2222222222222222 InstanceId: i-xxxxxxxx State:draining
  TargetGroupARN: arn:aws:elasticloadbalancing:ap-northeast-1:111111111111:targetgroup/xxxxx/2222222222222222 InstanceId: i-xxxxxxxx State:draining
  TargetGroupARN: arn:aws:elasticloadbalancing:ap-northeast-1:111111111111:targetgroup/xxxxx/2222222222222222 InstanceId: i-xxxxxxxx State:draining
  TargetGroupARN: arn:aws:elasticloadbalancing:ap-northeast-1:111111111111:targetgroup/xxxxx/2222222222222222 InstanceId: i-xxxxxxxx State:draining
  TargetGroupARN: arn:aws:elasticloadbalancing:ap-northeast-1:111111111111:targetgroup/xxxxx/2222222222222222 InstanceId: i-xxxxxxxx State:draining
  TargetGroupARN: arn:aws:elasticloadbalancing:ap-northeast-1:111111111111:targetgroup/xxxxx/2222222222222222 InstanceId: i-xxxxxxxx State:draining
  TargetGroupARN: arn:aws:elasticloadbalancing:ap-northeast-1:111111111111:targetgroup/xxxxx/2222222222222222 InstanceId: i-xxxxxxxx State:draining
  TargetGroupARN: arn:aws:elasticloadbalancing:ap-northeast-1:111111111111:targetgroup/xxxxx/2222222222222222 InstanceId: i-xxxxxxxx State:unused
 register : i-xxxxxxxx
  TargetGroupARN: arn:aws:elasticloadbalancing:ap-northeast-1:111111111111:targetgroup/xxxxx/2222222222222222 InstanceId: i-xxxxxxxx State:initial
  TargetGroupARN: arn:aws:elasticloadbalancing:ap-northeast-1:111111111111:targetgroup/xxxxx/2222222222222222 InstanceId: i-xxxxxxxx State:initial
  TargetGroupARN: arn:aws:elasticloadbalancing:ap-northeast-1:111111111111:targetgroup/xxxxx/2222222222222222 InstanceId: i-xxxxxxxx State:initial
  TargetGroupARN: arn:aws:elasticloadbalancing:ap-northeast-1:111111111111:targetgroup/xxxxx/2222222222222222 InstanceId: i-xxxxxxxx State:initial
  TargetGroupARN: arn:aws:elasticloadbalancing:ap-northeast-1:111111111111:targetgroup/xxxxx/2222222222222222 InstanceId: i-xxxxxxxx State:healthy

 deregister : i-xxxxxxxx
  TargetGroupARN: arn:aws:elasticloadbalancing:ap-northeast-1:111111111111:targetgroup/xxxxx/2222222222222222 InstanceId: i-xxxxxxxx State:draining
  TargetGroupARN: arn:aws:elasticloadbalancing:ap-northeast-1:111111111111:targetgroup/xxxxx/2222222222222222 InstanceId: i-xxxxxxxx State:draining
  TargetGroupARN: arn:aws:elasticloadbalancing:ap-northeast-1:111111111111:targetgroup/xxxxx/2222222222222222 InstanceId: i-xxxxxxxx State:draining
  TargetGroupARN: arn:aws:elasticloadbalancing:ap-northeast-1:111111111111:targetgroup/xxxxx/2222222222222222 InstanceId: i-xxxxxxxx State:draining
  TargetGroupARN: arn:aws:elasticloadbalancing:ap-northeast-1:111111111111:targetgroup/xxxxx/2222222222222222 InstanceId: i-xxxxxxxx State:draining
  TargetGroupARN: arn:aws:elasticloadbalancing:ap-northeast-1:111111111111:targetgroup/xxxxx/2222222222222222 InstanceId: i-xxxxxxxx State:draining
  TargetGroupARN: arn:aws:elasticloadbalancing:ap-northeast-1:111111111111:targetgroup/xxxxx/2222222222222222 InstanceId: i-xxxxxxxx State:draining
  TargetGroupARN: arn:aws:elasticloadbalancing:ap-northeast-1:111111111111:targetgroup/xxxxx/2222222222222222 InstanceId: i-xxxxxxxx State:draining
  TargetGroupARN: arn:aws:elasticloadbalancing:ap-northeast-1:111111111111:targetgroup/xxxxx/2222222222222222 InstanceId: i-xxxxxxxx State:draining
  TargetGroupARN: arn:aws:elasticloadbalancing:ap-northeast-1:111111111111:targetgroup/xxxxx/2222222222222222 InstanceId: i-xxxxxxxx State:unused
 register : i-xxxxxxxx
  TargetGroupARN: arn:aws:elasticloadbalancing:ap-northeast-1:111111111111:targetgroup/xxxxx/2222222222222222 InstanceId: i-xxxxxxxx State:initial
  TargetGroupARN: arn:aws:elasticloadbalancing:ap-northeast-1:111111111111:targetgroup/xxxxx/2222222222222222 InstanceId: i-xxxxxxxx State:initial
  TargetGroupARN: arn:aws:elasticloadbalancing:ap-northeast-1:111111111111:targetgroup/xxxxx/2222222222222222 InstanceId: i-xxxxxxxx State:initial
  TargetGroupARN: arn:aws:elasticloadbalancing:ap-northeast-1:111111111111:targetgroup/xxxxx/2222222222222222 InstanceId: i-xxxxxxxx State:initial
  TargetGroupARN: arn:aws:elasticloadbalancing:ap-northeast-1:111111111111:targetgroup/xxxxx/2222222222222222 InstanceId: i-xxxxxxxx State:healthy

まとめ

  • ELB (elb) と ALB (elbv2) では AWS CLI のサブコマンドが異なる
  • オプションも異なる
  • ALB ターゲットグループのドレインに注意する
  • aws elbv2 describe-target-health を使って waiter を実装すると正確に状態を把握しながら deregister / register ができる