503エラーの解読
アプリケーションのURLにアクセスした際、ダッシュボードの代わりに 503 Service Temporarily Unavailable という冷ややかな画面が表示されることがあります。NGINX Ingressを使用している場合、コントローラーのログには通常、次のような原因が記録されています。
[error] 197#197: *3586884 Service "default/my-service" does not have any active endpoints
このメッセージは非常に役立ちます。IngressはServiceを見つけられたものの、そのServiceがリクエストを処理するための正常なPodを見つけられなかったことを示しているからです。
根本原因
Kubernetesのルーティングは連鎖のように機能します。IngressがServiceを指し、そのServiceがPodのセットを指します。これが機能するために、ServiceはEndpointsリスト、つまり正常なPodのIPアドレスのリアルタイムなディレクトリを保持しています。
503エラーは、そのディレクトリが空のときに発生します。通常、ラベルの不一致、ヘルスチェックの失敗、または単純なポート番号の入力ミスが原因でこの断絶が起こります。
ステップバイステップのトラブルシューティング
1. Endpointsリソースの確認
まずは、ServiceとPodの間の架け橋が壊れていないか確認しましょう。次のコマンドを実行します。
kubectl get endpoints my-service -n <your-namespace>
ENDPOINTS 列を確認してください。もし <none> と表示されていれば、トラフィックの送り先がない状態です。これにより、問題はIngress自体ではなく、Pod側、あるいはServiceによるPodの選択方法にあることが確認できます。
2. ラベルの不一致を探す
ラベルはKubernetesにおける「接着剤」です。Serviceが app: payment-api を探しているのに、DeploymentがPodに app: payment-gateway というラベルを付けている場合、Serviceはそれらを見つけることができません。これはよくあるコピー&ペーストのミスです。
Serviceが何を探しているか確認します。
kubectl describe svc my-service -n <your-namespace> | grep Selector
次に、Podに付いている実際のラベルを一覧表示します。
kubectl get pods -n <your-namespace> --show-labels
Podは、Serviceセレクターに記載されているすべてのラベルを持っている必要があります。Serviceが3つのラベルを指定しているのに、Podが2つしか持っていない場合、トラフィックは受信されません。
3. Readiness Probeの失敗を診断する
Podは「Running(実行中)」であっても「Ready(準備完了)」ではない場合があります。Readiness Probe(起動準備状態チェック)が失敗すると、Kubernetesは壊れたコンテナにトラフィックを送信しないよう、EndpointsリストからそのIPを削除します。
Podの READY 列を確認します。
kubectl get pods -n <your-namespace>
もし 0/1 と表示されていれば、Podは生きていますがヘルスチェックに失敗しています。詳細を確認するには、 kubectl describe pod <pod-name> を実行し、下部の「Events」セクションを確認してください。 Readiness probe failed: HTTP probe failed with statuscode: 500 のようなエラーが表示されているかもしれません。これは、アプリケーション(Java Spring Bootサービスなど)の起動に45秒かかるのに、プローブがわずか5秒後からチェックを開始する場合によく発生します。
4. ポートマッピングの検証
ポート番号の入力ミスは「サイレントキラー」です。アプリケーションコンテナがポート 8080 で待機しているのに、Serviceが targetPort: 80 にトラフィックを送信している場合、接続はタイムアウトします。
Serviceの targetPort が、Deployment의 containerPort と一致していることを確認してください。
# Service (サービス)
ports:
- port: 80
targetPort: 8080 # 下記と一致させる必要があります
# Deployment (デプロイメント)
containers:
- name: my-app
ports:
- containerPort: 8080 # 上記と一致させる必要があります
修正の確認
ラベルやプローブを更新した後、再度Endpointsリストを確認してください。 10.244.1.45:8080 のような内部IPアドレスのリストが表示されるはずです。100%確実にするために、クラスター内から簡単な接続テストを実行しましょう。
kubectl run curl-test --image=curlimages/curl -i --tty --rm -- curl http://my-service:80
200 OK というレスポンスが返ってくれば、503エラーは正式に解決されたことになります。
ベストプラクティス
- ラベルの標準化: チーム間でセレクターの一貫性を保つために、
app.kubernetes.io/nameなどの標準ラベルを使用しましょう。 - 適切なプローブ遅延の設定:
initialDelaySecondsを、アプリの実際の起動時間に合わせて設定してください。起動の遅いアプリに30秒ほどの猶予を与えることで、不要な503エラーを防ぐことができます。 - アラートの自動化: Prometheusなどのツールを使用して、
kube_endpoint_address_availableがゼロになったときに通知されるようにしましょう。

