エラーの概要
Kubernetes環境で503エラーが発生するのは、クライアントからのリクエストに対応できるPodが存在しない、または全てのPodが利用不可状態にあることを示しています。Service経由でアクセスした際、バックエンドのPodがすべてダウンしていたり、起動途中だったり、リソース不足で応答できない状態で表示されるHTTPステータスコードです。本エラーは一時的な問題である場合が多く、Podの自動復旧により解決することもありますが、根本原因の特定と対処が必要です。
実際のエラーメッセージ例
HTTP/1.1 503 Service Unavailable
Content-Type: text/html; charset=utf-8
Connection: close
<html>
<body><h1>503 Service Unavailable</h1>
No servers are available to handle this request.
</body></html>
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {},
"status": "Failure",
"message": "no endpoints available for service",
"code": 503
}
よくある原因と解決手順
原因1: Podがすべてダウン状態である
DeploymentやStatefulSetで定義したPodが何らかの理由でクラッシュしており、バックエンドサーバーが完全に停止している状態です。CrashLoopBackOff状態やExit Code 1などの異常終了が続いている場合に発生します(Kubernetes の CrashLoopBackOff の記事)。
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: app
image: myapp:latest
env:
- name: DATABASE_URL
value: "invalid-connection-string"
After(修正後):
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: app
image: myapp:latest
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: db-credentials
key: connection-string
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
Podのステータスを確認するコマンド:
kubectl get pods -n <namespace>
kubectl describe pod <pod-name> -n <namespace>
kubectl logs <pod-name> -n <namespace>
原因2: Readiness Probeに失敗している
Readiness Probeが設定されているものの、起動時間が長すぎたり、ヘルスチェックエンドポイントが応答しなかったりして、Podが「Ready」状態に到達していません。この場合、Podプロセスは動作していても、トラフィックがルーティングされません。
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-server
spec:
replicas: 2
selector:
matchLabels:
app: api
template:
metadata:
labels:
app: api
spec:
containers:
- name: api
image: api-service:v1.0
ports:
- containerPort: 3000
readinessProbe:
httpGet:
path: /ready
port: 3000
initialDelaySeconds: 5
periodSeconds: 5
After(修正後):
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-server
spec:
replicas: 2
selector:
matchLabels:
app: api
template:
metadata:
labels:
app: api
spec:
containers:
- name: api
image: api-service:v1.0
ports:
- containerPort: 3000
readinessProbe:
httpGet:
path: /ready
port: 3000
initialDelaySeconds: 15
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3
livenessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 20
periodSeconds: 10
Readiness Probeの状態を確認するコマンド:
kubectl get pods -o wide -n <namespace>
kubectl describe pod <pod-name> -n <namespace> | grep -A 5 "Ready"
原因3: Serviceのエンドポイントが設定されていない
ServiceとPodのラベルセレクタが一致していない場合、Serviceは利用可能なエンドポイントを持たず、トラフィックをルーティングできません。この場合、Serviceオブジェクトは存在していても、バックエンドのPodが見つかりません。
# Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: backend
spec:
replicas: 3
selector:
matchLabels:
app: backend
tier: api
template:
metadata:
labels:
app: backend
spec:
containers:
- name: server
image: backend-app:latest
---
# Service
apiVersion: v1
kind: Service
metadata:
name: backend-service
spec:
selector:
app: backend
tier: web
ports:
- protocol: TCP
port: 80
targetPort: 8080
After(修正後):
# Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: backend
spec:
replicas: 3
selector:
matchLabels:
app: backend
tier: api
template:
metadata:
labels:
app: backend
tier: api
spec:
containers:
- name: server
image: backend-app:latest
ports:
- containerPort: 8080
---
# Service
apiVersion: v1
kind: Service
metadata:
name: backend-service
spec:
selector:
app: backend
tier: api
ports:
- protocol: TCP
port: 80
targetPort: 8080
kubectl get endpoints <service-name> -n <namespace>
kubectl describe service <service-name> -n <namespace>
Kubernetes固有の注意点
RBAC(Role-Based Access Control)による制限
ServiceAccountに対して必要なClusterRole/Roleが割り当てられていない場合、Podが外部リソースへのアクセスに失敗し、起動途中でクラッシュすることがあります。特に、PodがKubernetesAPI、CloudProvider API、その他外部サービスにアクセスする必要がある場合は、RBACの設定を確認してください。
リソースリクエスト・リミットの不足
CPUメモリリクエスト/リミットが不適切に設定されていると、Nodeのリソースが不足し、Podがスケジュールされなかったり、OOMKillerに強制終了されたりします。
spec:
containers:
- name: app
image: heavy-app:latest
# リソース要件が記述されていない
After(修正後):
spec:
containers:
- name: app
image: heavy-app:latest
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
Namespaceの隔離
異なるNamespace上のServiceにアクセスしようとしている場合、ServiceのFQDN(<service-name>.<namespace>.svc.cluster.local)を正確に指定する必要があります。
Ingress設定の不備
IngressコントローラーがServiceを正しく検出できていない場合、Ingressを経由したアクセスで503が発生します。IngressのBackend設定とServiceのPort番号の一致を確認してください。
それでも解決しない場合
ログの確認
# Podのログを確認
kubectl logs <pod-name> -n <namespace> --tail=100
# 前回のクラッシュログを確認
kubectl logs <pod-name> -n <namespace> --previous
# 複数Podのログを同時に確認
kubectl logs -l app=<label-value> -n <namespace> --all-containers=true
Eventの確認
kubectl describe node <node-name>
kubectl get events -n <namespace> --sort-by='.lastTimestamp'
kube-proxyのデバッグ
# kube-proxyのログを確認
kubectl logs -n kube-system -l k8s-app=kube-proxy
# ServiceのEndpointsが正しく作成されているか確認
kubectl get endpoints -A
メトリクスの確認
Podのリソース使用率を確認して、リソース不足が原因でないか調査します。
kubectl top nodes
kubectl top pods -n <namespace>
公式ドキュメント参照
Kubernetes公式ドキュメントの「Debugging Services」セクションと「Troubleshooting」ガイドに、さらに詳細なトラブルシューティング手順が記載されています。また、使用しているKubernetesバージョンに応じた互換性情報も確認してください。
免責事項:本記事の内容は、執筆時点の公開情報をもとに作成したものです。ソフトウェアの仕様は予告なく変更されることがあります。最新の情報は各ツールの公式サポートページをご確認ください。本記事の情報を利用した結果生じたいかなる損害についても、著者および運営者は責任を負いかねます。
この記事でエラーは解決しましたか?