エラーの概要

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 の記事)。

Before(エラーが起きるコード):

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プロセスは動作していても、トラフィックがルーティングされません。

Before(エラーが起きるコード):

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が見つかりません。

Before(エラーが起きるコード):

# 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

Serviceのエンドポイント確認コマンド

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に強制終了されたりします。

Before(エラーが起きるコード):

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バージョンに応じた互換性情報も確認してください。


免責事項:本記事の内容は、執筆時点の公開情報をもとに作成したものです。ソフトウェアの仕様は予告なく変更されることがあります。最新の情報は各ツールの公式サポートページをご確認ください。本記事の情報を利用した結果生じたいかなる損害についても、著者および運営者は責任を負いかねます。