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: valueis a map;- itemunder 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
defaultor set withkubectl 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
- Save the Pod example above as
demo-pod.yaml. - Run
kubectl apply -f demo-pod.yamlon your lab from Part 1. - Change the image tag, run
kubectl applyagain, and observe that Pod spec fields are largely immutable—Kubernetes may recreate the Pod. - Delete with
kubectl delete -f demo-pod.yaml.