エラーの概要
Kubernetes APIサーバーへのリクエストが不正な形式や内容であることを示すHTTP 400エラーです。マニフェストファイルの構文エラー、API仕様に違反するフィールド値、または不完全なリクエストボディが原因となります。このエラーはクラスタとの通信に成功した後、サーバー側でリクエストの妥当性検証に失敗したときに発生する重要な診断シグナルです。
実際のエラーメッセージ例
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {},
"status": "Failure",
"message": "error validating data: ValidationError(Pod.spec.containers[0].resources.limits): invalid type for io.k8s.api.core.v1.ResourceList: got \"string\", expected \"object\"",
"reason": "BadRequest",
"code": 400
}
error: error validating "deployment.yaml": error validating data:
[ValidationError(Deployment.spec.template.spec.containers[0].ports[0].containerPort):
invalid type for io.k8s.api.core.v1.ContainerPort: got "string", expected "integer",
ValidationError(Deployment.spec.template.spec.containers[0].image): string length must be non-empty]
よくある原因と解決手順
原因1: YAML構文エラーまたはフィールド型の不一致
なぜ発生するか: Kubernetesマニフェストファイルで、数値型フィールドを文字列で指定したり、オブジェクト型フィールドにスカラー値を渡したりするときに発生します。特にポート番号やリソース制限でこの問題が頻発します。
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: "8080" # 文字列型で指定
resources:
limits:
memory: 512Mi # オブジェクト型だが不正
cpu: "1" # 数値型だが文字列
After(修正後):
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 8080 # 整数型で指定
resources:
limits:
memory: 512Mi
cpu: "1" # CPU値は文字列でも有効
requests:
memory: 256Mi
cpu: "500m"
原因2: 必須フィールドの欠落
なぜ発生するか: Kubernetesリソースの必須フィールド(例:metadata.name、コンテナのimage)が定義されていない場合に発生します。APIサーバーは最小限のリソース定義すら受け付けません。
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: web-container
# imageフィールドが欠落
ports:
- containerPort: 80
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: web-container
image: nginx:1.21 # 必須フィールドを追加
ports:
- containerPort: 80
原因3: APIバージョンまたはリソース種別の不一致
なぜ発生するか: 廃止されたAPIバージョンを使用したり、クラスタにインストールされていないカスタムリソース定義(CRD)にアクセスしたりするときに発生します。Kubernetes 1.16以降でv1beta1 extensionsが廃止されるなど、バージョン間での互換性問題が頻繁に起きます。
kubectl apply -f - <<EOF
apiVersion: extensions/v1beta1 # Kubernetes 1.16+で廃止
kind: Deployment
metadata:
name: old-deployment
spec:
replicas: 2
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: myapp:1.0
EOF
After(修正後):
kubectl apply -f - <<EOF
apiVersion: apps/v1 # 現在サポートされているバージョン
kind: Deployment
metadata:
name: old-deployment
spec:
replicas: 2
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: myapp:1.0
EOF
原因4: セレクタラベルの不一致
なぜ発生するか: Deployment、Service、StatefulSetなどで定義したselectorのラベルが、Pod テンプレートのlabelsと一致していない場合に発生します。これにより、リソースが自身が管理すべきポッドを識別できず、検証エラーが発生します。
apiVersion: apps/v1
kind: Deployment
metadata:
name: app-deploy
spec:
selector:
matchLabels:
app: myapp
environment: production
template:
metadata:
labels:
app: myapp
# environmentラベルが欠落
version: v1
After(修正後):
apiVersion: apps/v1
kind: Deployment
metadata:
name: app-deploy
spec:
selector:
matchLabels:
app: myapp
environment: production
template:
metadata:
labels:
app: myapp
environment: production # セレクタと一致させる
version: v1
Kubernetes固有の注意点
ServiceAccountとRBAC設定
400エラーは認可エラー(403)ではなく検証エラーですが、ServiceAccountが適切に設定されていない場合、リソース作成時に引き続き400が発生することがあります。kubectl auth can-iコマンドで権限確認を併せて実施してください。
kubectl auth can-i create deployments --as=system:serviceaccount:default:my-sa -n default
Namespace指定の欠落
リソース定義でmetadata.namespaceを明示しない場合、デフォルトNamespaceに作成されます。別のNamespaceに配置する場合は、明示的に指定するか、-nフラグを使用してください。
kubectl apply -f deployment.yaml -n production
CRD(CustomResourceDefinition)のバージョン不一致
インストール済みのCRDのバージョンと、マニフェストファイルのAPIバージョンが一致していない場合、400エラーが発生します。kubectl api-resourcesで確認可能です。
kubectl api-resources | grep customresource
環境変数置換の不完全性
テンプレート化されたマニフェストファイルで、プレースホルダーが置換されないまま送信された場合、不正なYAML値として認識されます。envsubstやkustomizeを使用する際は、置換前のファイルをバイパスしないよう注意してください。
それでも解決しない場合
ログ確認とデバッグコマンド
APIサーバーのログを直接確認して、より詳細なエラーメッセージを取得してください。
# クラスタログの確認(マネージドKubernetesの場合はプロバイダーのコンソール使用)
kubectl logs -n kube-system deployment/kube-apiserver --tail=100
# リクエストの詳細を確認
kubectl apply -f deployment.yaml -v=8 # 最高レベルのverbosity
# マニフェストの検証(サーバーに送信前にドライラン)
kubectl apply -f deployment.yaml --dry-run=client -o yaml
公式ドキュメントへの参照
- Kubernetes API仕様 - https://kubernetes.io/docs/reference/kubernetes-api/ で各リソースのスキーマ定義を確認
- APIサーバーの検証ルール - https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#validation
- 廃止APIバージョンのマイグレーション - https://kubernetes.io/docs/reference/using-api/deprecation-guide/
コミュニティリソース
問題が解決しない場合は、以下で検索してください。
- Kubernetes GitHub Issues - https://github.com/kubernetes/kubernetes/issues (APIバージョンやバリデーション関連のバグ報告)
- Stack Overflow -
[kubernetes] 400タグでの質問検索 - CNCF Slack - #kubernetes-users チャネルでの相談
免責事項:本記事の内容は、執筆時点の公開情報をもとに作成したものです。ソフトウェアの仕様は予告なく変更されることがあります。最新の情報は各ツールの公式サポートページをご確認ください。本記事の情報を利用した結果生じたいかなる損害についても、著者および運営者は責任を負いかねます。
この記事でエラーは解決しましたか?