Free DevOps tool

Kubernetes YAML Checker

Most manifests that fail in production were syntactically valid when they shipped. This checker looks for the mistakes that pass kubectl apply and page you later: :latest images, missing requests and limits, missing probes, privileged containers, host networking and unset namespaces β€” for every document in the file, including CronJob pod templates. It is honestly a common-mistakes checker, not a full schema validator. No sign-up; nothing leaves your browser.

Everything runs in your browser β€” the manifest never leaves this page. This is a common-mistakes checker, not a full Kubernetes schema validation: it will not catch every invalid field, and a clean result is not a guarantee the API server accepts the file. Pair it with kubectl apply --dry-run=server for the real verdict.

1 documentβœ“ 3 passed⚠ 8 warningsβœ— 1 problems

Document 1 β€” Deployment

apiVersion: apps/v1 Β· kind: Deployment

  • βœ“ kind / apiVersion detected β€” Pass

    apps/v1, Kind=Deployment.

  • ⚠ Namespace set β€” Warning

    metadata.namespace is not set β€” the object lands in whatever namespace is current, which in shared clusters is how test workloads end up in production namespaces.

  • ⚠ Labels present β€” Warning

    metadata.labels is not set β€” nothing can select this object by label, and cost/monitoring tools group by labels.

  • βœ— Image tags pinned (no :latest) β€” Problem

    Unpinned: web (nginx:latest). A :latest (or untagged) image means every restart can silently run different code, and rollbacks stop being deterministic.

  • ⚠ CPU/memory requests set β€” Warning

    no requests at all: web. Without requests the scheduler guesses, nodes overcommit, and the noisy-neighbour pod gets OOM-killed first β€” usually yours.

  • ⚠ CPU/memory limits set β€” Warning

    no limits at all: web. Without a memory limit one leaking container can consume the node and take its neighbours down with it.

  • ⚠ Liveness probes β€” Warning

    No livenessProbe on: web. A deadlocked container looks "Running" forever β€” Kubernetes can only restart what it can detect.

  • ⚠ Readiness probes β€” Warning

    No readinessProbe on: web. The pod receives Service traffic the moment it starts, before the app is actually ready to serve.

  • βœ“ Not privileged β€” Pass

    No container sets privileged: true.

  • βœ“ Host namespaces not shared β€” Pass

    hostNetwork, hostPID and hostIPC are not enabled.

  • ⚠ runAsNonRoot set β€” Warning

    runAsNonRoot is not set at pod or container level. That does not prove the container runs as root β€” the image may define a non-root USER β€” but nothing in this manifest guarantees it.

  • ⚠ Container securityContext present β€” Warning

    securityContext is not set on: web. Defaults then apply (image's USER, default capabilities) unless a Pod Security Standard or policy sets them.

The four mistakes behind most 3 a.m. pages

:latest makes rollbacks a lie

With a moving tag, "the version that worked yesterday" no longer names anything. Nodes pull whatever the tag points to at start time, two pods of the same Deployment run different code, and the incident review starts with nobody able to say what was actually deployed.

No requests, blind scheduler

The scheduler places pods by requests. Skip them and it packs nodes by optimism; the first memory spike OOM-kills whatever is biggest, not whatever is guilty. Limits are the other half: without one, a leaking container consumes the node and evicts its neighbours.

No probes, invisible failures

Without a readiness probe, a pod takes production traffic before the app can serve it. Without a liveness probe, a deadlocked process reports Running forever. Kubernetes can only heal what it can observe, and probes are the observation.

Privilege is a blast-radius setting

privileged: true, hostNetwork and runAsUser: 0 each dissolve a boundary between one container and the whole node. They are sometimes right for system daemons β€” and almost never right for application workloads, which is why this checker flags them as problems, not warnings.

Related guides

Frequently asked questions

Is this a full Kubernetes YAML validator?

No β€” and it says so on purpose. This checker parses your YAML (and reports syntax problems with line numbers), detects each document's kind and apiVersion, and runs production-readiness checks on Pod, Deployment, Job and CronJob pod specs. It does not validate against the full Kubernetes OpenAPI schema, so it cannot catch every misspelled or misplaced field. The authoritative check is kubectl apply --dry-run=server, which asks the API server itself.

Why is an untagged image treated the same as :latest?

Because Kubernetes does. An image reference with no tag resolves to :latest, and a Deployment using it also defaults imagePullPolicy to Always β€” so every pod restart can pull different code than the one you tested, and kubectl rollout undo stops restoring a known state.

What is the difference between requests and limits?

Requests are the scheduler's contract: a pod is only placed on a node with at least that much unallocated CPU/memory, and requests drive bin-packing and autoscaling math. Limits are the cgroup ceiling: exceed the memory limit and the container is OOM-killed; exceed CPU and it is throttled. Missing requests break placement; missing limits let one container starve its neighbours.

Does a missing runAsNonRoot mean my container runs as root?

Not necessarily. runAsNonRoot not being set means the manifest does not guarantee anything β€” the container runs as whatever USER the image defines, which is root in many popular images but not all. Setting runAsNonRoot: true makes the kubelet refuse to start the container as root, turning a hope into an enforced fact.

Why does the checker ask for a namespace?

Because kubectl applies to whichever namespace is current in your kubeconfig when metadata.namespace is absent. In shared clusters that is how a test Deployment ends up in the production namespace. Pinning the namespace in the manifest makes the file self-describing and review-able in Git.

Is my YAML sent anywhere?

No. The checker runs entirely in your browser with client-side JavaScript β€” the manifest is never uploaded, logged or stored, which is why it is safe to paste real (non-secret) manifests. Do not paste live Secret values into any online tool, including this one; redacted examples check exactly the same way.