はじめに
アプリケーションには Application Load Balancer の背後に 2 台のサーバーがあります。EC2 インスタンスが稼働していても、アプリケーションは故障することがあります。このラボではヘルスチェックを設定し、実際の障害を起こして、正常なサーバーがリクエストを処理し続けることを確認します。その後、アプリケーションを復旧し、負荷分散リソースを削除します。
ALB リスナー、ターゲットグループ、EC2 の SSH 接続を理解していることが前提です。この新しい環境にはネットワーク、稼働中の 2 台、登録情報、ALB リスナーが用意されています。前のラボに依存せず、AWS CLI と接続ファイルも設定済みです。
認定試験との関連
このラボでは、次の試験項目に関する入門的な実践を行います。
- Solutions Architect – Associate (SAA-C03) · タスク 2.2:アプリケーションのヘルス状態と負荷分散がバックエンド障害時の可用性を支える仕組みの理解。
- CloudOps Engineer – Associate (SOA-C03) · タスク 2.2:ELB ヘルスチェックの設定と異常なターゲットの診断。
ターゲットのヘルスチェックを設定する
提供されたサービスを確認し、ALB がアプリケーションの準備状態を調べる方法を設定します。
用意された作業ディレクトリに移動し、ネットワーク変数を読み込みます。
cd /home/labex/project
source launch.env
提供されたロードバランサーとグループを名前で検索します。後続コマンド用に ARN を、HTTP リクエスト用に DNS 名を保存します。
LB_ARN=$(aws elbv2 \
describe-load-balancers \
--names application-alb \
--query 'LoadBalancers[0].LoadBalancerArn' \
--output text)
TG_ARN=$(aws elbv2 \
describe-target-groups \
--names application-targets \
--query 'TargetGroups[0].TargetGroupArn' \
--output text)
LB_DNS=$(aws elbv2 \
describe-load-balancers \
--load-balancer-arns "$LB_ARN" \
--query 'LoadBalancers[0].DNSName' \
--output text)
ヘルスチェックはクライアントのリクエストとは独立して各ターゲットを調べます。パスはアプリケーションがトラフィックを処理できるかを示す必要があります。現在の設定を確認します。
aws elbv2 \
describe-target-groups \
--target-group-arns "$TG_ARN" \
--query 'TargetGroups[].{Path:HealthCheckPath,Interval:HealthCheckIntervalSeconds,Timeout:HealthCheckTimeoutSeconds,Healthy:HealthyThresholdCount,Unhealthy:UnhealthyThresholdCount,Matcher:Matcher}'
提供グループは 30 秒ごとに /health をチェックします。この小さな演習では間隔を 5 秒、タイムアウトを 2 秒に設定します。連続 2 回の失敗で除外し、連続 2 回の成功で再参加させます。マッチャーは HTTP 200 を成功と判定します。
aws elbv2 \
modify-target-group \
--target-group-arn "$TG_ARN" \
--health-check-protocol HTTP \
--health-check-path /health \
--health-check-interval-seconds 5 \
--health-check-timeout-seconds 2 \
--healthy-threshold-count 2 \
--unhealthy-threshold-count 2 \
--matcher HttpCode=200 \
--query 'TargetGroups[].{Path:HealthCheckPath,Interval:HealthCheckIntervalSeconds,Healthy:HealthyThresholdCount,Unhealthy:UnhealthyThresholdCount}'
間隔は頻度、タイムアウトは各チェックの待ち時間を決めます。しきい値は一時的な失敗への過剰な反応を防ぎます。本番では起動と障害の特性に合わせてください。ここでは観察しやすい短い値を使います。
両方のターゲットが正常になるまで待ち、実際の状態を確認します。
aws elbv2 \
wait target-in-service \
--target-group-arn "$TG_ARN"
aws elbv2 \
describe-target-health \
--target-group-arn "$TG_ARN" \
--query 'TargetHealthDescriptions[].{Instance:Target.Id,Port:Target.Port,Health:TargetHealth.State}' \
--output table
AWS View を開き、2 つの healthy を確認して Send request をクリックします。実際の HTTP 200 とヘルス状態で初期条件を確認できます。
実際のアプリケーション障害を観察する
EC2 インスタンスを稼働させたまま、app-a のヘルスエンドポイントを失敗させます。
提供された名前タグで ID を取得し、SSH 用のアドレスも取得します。
APP_A=$(aws ec2 \
describe-instances \
--filters Name=tag:Name,Values=app-a \
--query 'Reservations[0].Instances[0].InstanceId' \
--output text)
APP_B=$(aws ec2 \
describe-instances \
--filters Name=tag:Name,Values=app-b \
--query 'Reservations[0].Instances[0].InstanceId' \
--output text)
APP_A_IP=$(aws ec2 \
describe-instances \
--instance-ids "$APP_A" \
--query 'Reservations[0].Instances[0].PublicIpAddress' \
--output text)
アプリケーションは毎回 /etc/report-app/config.json を読みます。healthy により /health が 200 または 503 を返します。提供された鍵と設定で SSH 接続します。jq はこのフィールドだけを変更し、一時ファイルは読み取り中の上書きを防ぎ、install は読み取り可能な権限で置き換えます。
ssh -F ssh_config "ubuntu@$APP_A_IP" \
'sudo jq ".healthy = false" /etc/report-app/config.json > /tmp/report-config.json && sudo install -m 644 /tmp/report-config.json /etc/report-app/config.json'
サーバー内部から直接確認します。-o /dev/null は本文を破棄し、-w は HTTP ステータスを表示します。
ssh -F ssh_config "ubuntu@$APP_A_IP" \
'curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8081/health'
503 が返るはずです。これはアプリケーション障害であり EC2 停止ではありません。2 回のチェックを待って理由を確認します。
sleep 12
aws elbv2 \
describe-target-health \
--target-group-arn "$TG_ARN" \
--query 'TargetHealthDescriptions[].{Instance:Target.Id,Health:TargetHealth.State,Reason:TargetHealth.Reason}' \
--output table
503 は 200 と一致しないため、APP_A は unhealthy、理由は Target.ResponseCodeMismatch となります。APP_B は healthy のままです。チェックは非同期なので、切り替え中なら少し待って再確認します。
EC2 インスタンスが稼働したままであることを確認します。
aws ec2 \
describe-instances \
--instance-ids "$APP_A" "$APP_B" \
--query 'Reservations[].Instances[].{Instance:InstanceId,State:State.Name}' \
--output table
ALB 経由で 6 回の独立したリクエストを送ります。
for request in 1 2 3 4 5 6; do
curl --config client.conf -sS "http://$LB_DNS/health"
echo
done
すべての応答が APP_B を示すはずです。AWS View で異常なターゲットと正常なターゲットを確認します。Send request を何度かクリックし、正常なサーバーが応答することを確認します。正常なターゲットがあれば、ALB は故障ターゲットを除外します。

例では一方が Target.ResponseCodeMismatch を示し、正常なターゲットから実際の HTTP 200 が返っています。あなたの ID は異なるため、自分の正常なターゲットと応答を照合してください。
すべてが異常な場合、ALB は fail open で異常なターゲットにも転送することがあります。app-b を正常に保つことが重要です。全ターゲット異常を、ALB がすべての転送を停止する証拠と考えないでください。
ターゲットを復旧して再参加させる
app-a を復旧し、チェック成功後にリクエスト処理へ戻ることを確認します。
同じ安全なファイル置換で healthy だけを復元します。
ssh -F ssh_config "ubuntu@$APP_A_IP" \
'sudo jq ".healthy = true" /etc/report-app/config.json > /tmp/report-config.json && sudo install -m 644 /tmp/report-config.json /etc/report-app/config.json'
直接アクセスで 200 が返ることを確認します。
ssh -F ssh_config "ubuntu@$APP_A_IP" \
'curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8081/health'
アプリケーションは復旧しましたが、ALB は設定された連続成功を確認する必要があります。正常状態を待って両方を確認します。
aws elbv2 \
wait target-in-service \
--target-group-arn "$TG_ARN"
aws elbv2 \
describe-target-health \
--target-group-arn "$TG_ARN" \
--query 'TargetHealthDescriptions[].{Instance:Target.Id,Health:TargetHealth.State}' \
--output table
両方が healthy になったら、再び 6 回リクエストします。
for request in 1 2 3 4 5 6; do
curl --config client.conf -sS "http://$LB_DNS/health"
echo
done
両方の ID を探します。AWS View の正常な 2 つのカードと Send request の応答を確認します。アプリケーションを修復してチェックを成功させたのであり、インスタンスの置換や登録解除はしていません。
負荷分散リソースを削除する
復旧したサーバーとネットワークを残し、提供された負荷分散設定を削除します。
リスナー ARN を取得し、リスナー、ALB、ターゲットグループの順で削除します。
LISTENER_ARN=$(aws elbv2 \
describe-listeners \
--load-balancer-arn "$LB_ARN" \
--query 'Listeners[0].ListenerArn' \
--output text)
aws elbv2 \
delete-listener \
--listener-arn "$LISTENER_ARN"
aws elbv2 \
delete-load-balancer \
--load-balancer-arn "$LB_ARN"
aws elbv2 \
delete-target-group \
--target-group-arn "$TG_ARN"
両方のリソース一覧が空であることを確認します。
aws elbv2 \
describe-load-balancers \
--query 'LoadBalancers[].LoadBalancerName'
aws elbv2 \
describe-target-groups \
--query 'TargetGroups[].TargetGroupName'
両クエリの [] と AWS View の空の領域を確認します。提供された EC2 とネットワークは残してください。
まとめ
ALB ヘルスチェックを設定し、実際の障害を起こして EC2 停止と区別しました。正常なサーバーへのトラフィックを確認し、復旧後は両方の応答を確認しました。最後に負荷分散リソースを削除し、サーバーとネットワークを残しました。
次のラボでは、既存サーバーを手動修復する代わりに Auto Scaling グループで故障インスタンスを置き換えます。



