Manifests
Everything in Kubernetes is defined as a manifest — a YAML (or JSON) file that describes the desired state of a resource. You apply manifests with kubectl apply -f <file>.
The Four Top-Level Fields
Section titled “The Four Top-Level Fields”Every manifest has these fields:
apiVersion: apps/v1 # API group and versionkind: Deployment # object typemetadata: # identity and labels name: my-app namespace: default labels: app: my-appspec: # desired state (varies by kind) replicas: 3 selector: matchLabels: app: my-app template: metadata: labels: app: my-app spec: containers: - name: app image: nginx:1.25apiVersion
Section titled “apiVersion”Which API group and version to use. Common values:
| apiVersion | Used For |
|---|---|
v1 | Pod, Service, ConfigMap, Secret, Namespace, PVC |
apps/v1 | Deployment, StatefulSet, DaemonSet, ReplicaSet |
batch/v1 | Job, CronJob |
networking.k8s.io/v1 | Ingress, NetworkPolicy |
autoscaling/v2 | HorizontalPodAutoscaler |
policy/v1 | PodDisruptionBudget |
The type of object: Pod, Deployment, Service, Ingress, ConfigMap, Secret, etc. Must match the apiVersion (e.g. Deployment requires apps/v1).
metadata
Section titled “metadata”Identity and organizational fields:
name— Required. Unique within the namespace for that kind.namespace— Optional (defaults todefault). Not all resources are namespaced (e.g. Nodes, PersistentVolumes are cluster-scoped).labels— Key-value pairs for grouping and selecting (e.g.app: my-app,env: production). Used by Services, Deployments, andkubectl -l.annotations— Key-value pairs for non-identifying metadata (e.g. build info, tool config, descriptions). Not used for selection; purely informational or for tooling.
metadata: name: my-app namespace: staging labels: app: my-app env: staging annotations: description: "Frontend web server" managed-by: "helm"The desired state — what you want Kubernetes to do. Structure varies by kind:
- For a Deployment: replicas, selector, pod template.
- For a Service: selector, ports, type.
- For a PVC: access modes, storage size, storage class.
spec vs status
Section titled “spec vs status”When you apply a manifest, Kubernetes stores two things:
spec— What you declared (your desired state). You write this.status— What actually exists (current state). Kubernetes writes this.
Controllers continuously reconcile: if status doesn’t match spec, they take action (create pods, restart containers, etc.).
You can see both with:
kubectl get deployment my-app -o yamlThe status section shows current replicas, conditions, and observed generation. You never write status in your manifests.
Multi-Resource Files
Section titled “Multi-Resource Files”You can put multiple resources in one file, separated by ---:
apiVersion: v1kind: Servicemetadata: name: my-appspec: selector: app: my-app ports: - port: 80 targetPort: 8080---apiVersion: apps/v1kind: Deploymentmetadata: name: my-appspec: replicas: 2 selector: matchLabels: app: my-app template: metadata: labels: app: my-app spec: containers: - name: app image: my-app:v1You can also apply an entire directory:
kubectl apply -f ./k8s/ # applies all YAML files in the directoryApplying and Managing Manifests
Section titled “Applying and Managing Manifests”kubectl apply -f manifest.yaml # create or updatekubectl apply -f manifest.yaml --dry-run=client # preview without applyingkubectl diff -f manifest.yaml # show what would changekubectl delete -f manifest.yaml # delete resources defined in fileDeclarative vs Imperative
Section titled “Declarative vs Imperative”- Declarative (recommended): Write manifests, run
kubectl apply. Kubernetes converges toward the desired state. Easy to version-control and review. - Imperative: Run
kubectl create,kubectl run,kubectl exposedirectly. Quick for one-offs and debugging, but hard to reproduce.
Generating YAML
Section titled “Generating YAML”You don’t have to write manifests from scratch:
kubectl create deployment my-app --image=nginx --dry-run=client -o yaml > deployment.yamlkubectl create service clusterip my-app --tcp=80:8080 --dry-run=client -o yaml > service.yamlThis generates a valid manifest you can edit and then apply.
Validating Manifests
Section titled “Validating Manifests”kubectl apply -f manifest.yaml --dry-run=server # server-side validationkubectl explain deployment.spec.template # docs for any fieldkubectl explain pod.spec.containers # nested fieldskubectl explain is useful for looking up fields without leaving the terminal.
Key Takeaways
Section titled “Key Takeaways”- Every manifest has four fields: apiVersion, kind, metadata, spec.
- Labels are for selection and grouping; annotations are for metadata and tooling.
- spec = what you want; status = what exists. Controllers reconcile the gap.
- Use multi-resource files or directories to keep related resources together.
- Prefer declarative (
kubectl apply -f) over imperative commands for anything you want to reproduce. - Use
--dry-run=client -o yamlto generate manifests;kubectl explainto look up fields.