Anatomy of a Kubernetes Manifest (YAML, Line by Line)

Kubernetes is declarative: you hand the API a document that says what should exist. That document is usually YAML. Before you memorize twenty resource types, learn the skeleton every manifest shares—and how to discover fields you have not memorized yet.

In short

Every object has apiVersion, kind, metadata, and spec. Labels identify things; selectors connect controllers to Pods. Use kubectl explain and dry-run to validate before you apply.

YAML rules that save beginners hours

  • Indentation matters. Use spaces, not tabs (two spaces per level is common).
  • Maps vs lists: key: value is a map; - item under a key is a list.
  • Strings: Quote values with special characters. Numbers and booleans are unquoted (replicas: 3, not "3" unless you mean a string).
  • One file can hold multiple documents separated by --- on its own line.

The four top-level fields

Almost every Kubernetes object you create looks like this shape:

apiVersion: v1          # which API group and version
kind: Pod               # what type of object
metadata:               # identity and labels
  name: demo
  namespace: default
  labels:
    app.kubernetes.io/name: demo
spec:                   # desired state — shape depends on kind
  containers:
    - name: app
      image: nginx:1.25-alpine
      ports:
        - containerPort: 80

apiVersion

Tells the API server which schema to validate against. Examples:

  • v1 — core resources: Pod, Service, ConfigMap, Namespace.
  • apps/v1 — Deployment, ReplicaSet, StatefulSet, DaemonSet.
  • batch/v1 — Job, CronJob.

Wrong apiVersion usually fails at apply time with a clear error. Use kubectl api-resources to see kinds and versions your cluster supports.

kind

The resource type: Pod, Deployment, Service, and so on. It must match apiVersion (you cannot put a Deployment in v1).

metadata

  • name — unique within the namespace for most types.
  • namespace — scope; omit to use default or set with kubectl apply -n team-a -f file.yaml.
  • labels — key/value tags for selection, governance, and observability (Part 4).
  • annotations — non-identifying metadata (tooling hints, last-applied URLs); not used in label selectors.

spec

What you want. The API fills in status for you (phase, conditions, Pod IPs). Beginners should read spec in Git and status with kubectl describe when debugging.

Labels and selectors: how objects find each other

A Deployment does not list Pod names. It says: “keep three Pods that match these labels.” A Service routes traffic to Pods with matching labels.

# Fragment — Deployment template labels
spec:
  selector:
    matchLabels:
      app.kubernetes.io/name: demo
  template:
    metadata:
      labels:
        app.kubernetes.io/name: demo

The Deployment’s spec.selector must match spec.template.metadata.labels. If they diverge, the controller cannot adopt Pods—or worse, adopts the wrong ones. This is one of the most common copy-paste mistakes in workshops.

Read the schema instead of guessing

kubectl explain pod
kubectl explain pod.spec.containers
kubectl explain deployment.spec.template

Think of kubectl explain as structured help for YAML authors. Pair it with the official Kubernetes API reference when you need field-level semantics.

Validate before you mutate the cluster

# Client-side dry run — catches many typos
kubectl apply -f demo.yaml --dry-run=client

# Server-side dry run (when enabled) — API validates admission
kubectl apply -f demo.yaml --dry-run=server

Dry-run does not replace review in Git, but it catches “wrong indentation under containers” faster than a crash loop.

Imperative vs declarative (why YAML wins)

You can run kubectl run and kubectl expose for quick experiments. For anything you will repeat, prefer manifests in Git—the same discipline as GitOps, even before you install Flux or Argo CD.

Practice exercise

  1. Save the Pod example above as demo-pod.yaml.
  2. Run kubectl apply -f demo-pod.yaml on your lab from Part 1.
  3. Change the image tag, run kubectl apply again, and observe that Pod spec fields are largely immutable—Kubernetes may recreate the Pod.
  4. Delete with kubectl delete -f demo-pod.yaml.

← Part 1 · Blog index · Part 3 →

Part 1 Part 3