AWS ALB 503 Service Unavailableを修正する:ターゲットグループに正常なターゲットがない

intermediate☁️ AWS2026-03-21| AWS Application Load Balancer (ALB)、EC2、ECS、ターゲットグループ — 全リージョン対応

Error Message

503 Service Temporarily Unavailable - No healthy upstream
#alb#ec2#ヘルスチェック#ロードバランサー#ターゲットグループ

エラーの概要

ALBは起動中。EC2インスタンスも稼働中。しかし、すべてのリクエストが以下のエラーを返します:

503 Service Temporarily Unavailable - No healthy upstream

ALBのターゲットグループに正常なターゲットが存在しません。すべてのターゲットがヘルスチェックに失敗、ドレイン中、または未登録の状態です。トラフィックの転送先がない状態です。

原因

ALBはヘルスチェック設定に基づき、一定間隔で各ターゲットを確認します。N回連続して失敗すると、そのターゲットは「異常」とマークされ、トラフィックが送られなくなります。主な原因は以下のとおりです:

  • アプリサーバーがクラッシュしているか、起動していない
  • ヘルスチェックパスが2xx以外を返している(/healthで404や500が返される)
  • セキュリティグループがALBからインスタンスへのヘルスチェックポートへのアクセスをブロックしている
  • ターゲットグループのポート設定が誤っている(アプリは8080でリッスンしているのに、TGでは80に設定されている)
  • インスタンスが起動直後で、まだ正常しきい値に達していない
  • ターゲットグループが空で、インスタンスが登録されていない

手順1:ターゲットのヘルス状態を確認する

まずここから始めましょう。AWS CLIを使えば、ALBが各ターゲットをどのように評価しているかを正確に確認できます:

# ターゲットグループのARNに置き換えてください
aws elbv2 describe-target-health \
  --target-group-arn arn:aws:elasticloadbalancing:ap-northeast-1:123456789:targetgroup/my-tg/abc123

出力例:

{
  "TargetHealthDescriptions": [
    {
      "Target": { "Id": "i-0abc123def456", "Port": 80 },
      "TargetHealth": {
        "State": "unhealthy",
        "Reason": "Target.FailedHealthChecks",
        "Description": "Health checks failed with these codes: [502]"
      }
    }
  ]
}

Reasonフィールドが最初の手がかりになります。よくある値は以下のとおりです:

  • Target.FailedHealthChecks — アプリが不正なステータスコードを返している
  • Target.Timeout — タイムアウト時間内にレスポンスがない
  • Target.NotRegistered — インスタンスがターゲットグループに登録されていない
  • Elb.InitialHealthChecking — ウォームアップ中。30〜60秒待ちましょう
  • Target.DeregistrationInProgress — ドレイン処理中。完了を待ちましょう

手順2:セキュリティグループを確認する

これは深夜2時に人を悩ませる原因の一つです。ALBがヘルスチェックポートを通じてインスタンスに到達できるよう、通信経路が確保されている必要があります。セキュリティグループは最もよくある障害要因です。

# インスタンスに紐づくセキュリティグループを取得する
aws ec2 describe-instances --instance-ids i-0abc123def456 \
  --query 'Reservations[].Instances[].SecurityGroups'

# そのセキュリティグループのインバウンドルールを確認する
aws ec2 describe-security-groups --group-ids sg-0123456789 \
  --query 'SecurityGroups[].IpPermissions'

インスタンスのセキュリティグループは、ヘルスチェックポート(TCP 80、443、またはアプリが使用するポート)においてALBのセキュリティグループからのインバウンドトラフィックを許可する必要があります0.0.0.0/0のルールしかない場合や、ALBのSGを参照するルールがない場合は、そこが原因です。

CLIで修正する場合:

aws ec2 authorize-security-group-ingress \
  --group-id sg-INSTANCE_SG \
  --protocol tcp \
  --port 80 \
  --source-group sg-ALB_SG

コンソールから設定する場合:EC2 → セキュリティグループ → インスタンスのSG → インバウンドルール → ルールを追加 → カスタムTCP、ポート80、送信元 = ALBのセキュリティグループID。

手順3:ヘルスチェックエンドポイントを直接テストする

SSHでインスタンスに接続し、ALBが確認しているURLをcurlで直接叩いてみましょう:

ssh ec2-user@your-instance-ip

# ヘルスチェックエンドポイントをテストする
curl -v http://localhost:80/health

# アプリが別のポートで動いている場合
curl -v http://localhost:8080/health

レスポンスはHTTP 200、またはターゲットグループで設定した成功コードを返す必要があります。404が返る場合はパスが間違っています。500が返る場合はアプリに問題があります。リクエストがハングする場合は、アプリがそのポートでリッスンしていません。

実際にリッスンしているポートを確認する:

ss -tlnp | grep LISTEN
# または
netstat -tlnp

手順4:ターゲットグループのヘルスチェック設定を見直す

ヘルスチェックの設定ミスは気づきにくい原因の一つです。特に、アプリを更新せずにTGの設定だけ変更した場合に起こりがちです。CLIで確認しましょう:

aws elbv2 describe-target-groups \
  --target-group-arns arn:aws:elasticloadbalancing:...

以下の項目を実際のアプリの動作と照合してください:

  • Protocol:HTTPまたはHTTPS — アプリが提供するプロトコルと一致している必要があります
  • Port:アプリがリッスンしているポートと一致している必要があります
  • Path:例 /health/ping — 2xxを返す必要があります
  • Healthy threshold:正常と判定されるために必要な連続成功回数(デフォルト:5)
  • Unhealthy threshold:異常とマークされるまでの連続失敗回数(デフォルト:2)
  • Timeout:ALBがレスポンスを待つ秒数(デフォルト:5秒)
  • Interval:確認の実施間隔(デフォルト:30秒)

負荷がかかっている状態では、アプリがヘルスチェックに6〜8秒かかることがあります。タイムアウトが5秒に設定されていると、すべてのプローブがタイムアウトしてターゲットが異常のままになります。タイムアウトを延ばしましょう。復旧を早めるには、インターバルを10〜15秒に、正常しきい値を2に下げることを検討してください。

aws elbv2 modify-target-group \
  --target-group-arn arn:aws:elasticloadbalancing:... \
  --health-check-path /health \
  --health-check-interval-seconds 15 \
  --healthy-threshold-count 2 \
  --unhealthy-threshold-count 3 \
  --health-check-timeout-seconds 10

手順5:登録済みターゲットを確認する

基本的な確認ですが、インスタンスが実際に登録されているか確かめましょう:

aws elbv2 describe-target-health \
  --target-group-arn arn:aws:elasticloadbalancing:... \
  --query 'TargetHealthDescriptions[].Target'

リストが空の場合は、インスタンスを登録してください:

aws elbv2 register-targets \
  --target-group-arn arn:aws:elasticloadbalancing:... \
  --targets Id=i-0abc123def456,Port=80

修正を確認する

変更を加えたら、ターゲットのヘルス状態が切り替わるまでポーリングして確認しましょう:

# 10秒ごとにポーリングする
watch -n 10 'aws elbv2 describe-target-health \
  --target-group-arn arn:aws:elasticloadbalancing:... \
  --query "TargetHealthDescriptions[].TargetHealth"'

少なくとも1つのターゲットで"State": "healthy"が表示されたら、ALBをテストしましょう:

curl -I https://your-alb-dns-name.ap-northeast-1.elb.amazonaws.com/
# 期待されるレスポンス: HTTP/1.1 200 OK

補足Tips

  • ALBアクセスログ:ALBの属性設定から有効化できます。各ログ行にターゲットのレスポンスコードが記録されるため、SSHで確認する前に消えてしまう断続的な503を追跡する際に非常に役立ちます。
  • CloudWatchアラーム:ターゲットグループのメトリクスでHealthyHostCount < 1のアラームを設定しましょう。ユーザーより先に問題を把握できます。
  • Auto Scalingグループ:ASGが正しいターゲットグループに紐づいているか確認してください。また、ウォームアップ期間が終わる前にインスタンスがヘルスチェックを通過しているかも確認しましょう。300秒のウォームアップと30秒のチェック間隔では、トラフィックが流れるまでに10回のプローブが実行されます。
  • ECSサービス:コンテナが正しいポートを公開し、かつECS自身のコンテナヘルスチェックを先に通過している必要があります。ECSが異常とみなしているタスクへは、ALBはトラフィックをルーティングしません。
  • ローリングデプロイ:古いインスタンスが一斉にドレインされると、一時的に503が発生することがあります。デプロイを分散させるか、最小正常割合を100%に設定してこれを防ぎましょう。

Related Error Notes