Pods: Imperative vs Declarative & YAML
Video: Day 7/40 — Pod In Kubernetes | Imperative VS Declarative | YAML • https://www.youtube.com/watch?v=_f9ql2Y5Xcc • Duration: ~33 min
Key terms
| Term | Meaning |
|---|---|
| Pod | Smallest deployable unit (one or more containers) |
| Imperative | Do-this-now commands (kubectl run/create) |
| Declarative | Apply desired YAML and let Kubernetes converge |
| Manifest | A YAML/JSON object definition |
| apiVersion/kind/metadata/spec | The four required top-level YAML fields |
--dry-run=client | Build YAML without creating anything |
kubectl apply | Declarative create/update from a manifest |
Problem & solution
The pod is the unit you actually deploy, but there are two very different ways to create resources: quick imperative commands versus versionable declarative YAML. Choosing wrong leads to unrepeatable, undocumented infrastructure.
Solution: Define workloads declaratively in YAML and apply them, so the cluster reconciles to your desired state (prefer declarative over imperative one-offs).
The analogy
You can run a dock two ways. You can stand on the pier barking each step at a dockworker, fast for a one-off, but nobody records what you asked or repeats it tomorrow. Or you can file a standing work order describing the end state you want, and the port keeps fulfilling it on its own, restoring it whenever reality drifts. Kubernetes mirrors this: imperative kubectl commands are the shouted steps, while a declarative YAML manifest is the standing order that Kubernetes continuously reconciles toward.
Where this fits in the cluster
The same cluster entities appear in every day's notes; the diagram below shows where this day's topic fits.
Graph legend — each node maps to the nginx pod this day creates:
| Graph node | Maps to | What it does |
|---|---|---|
| api-server / etcd / scheduler / controller-mgr | the control-plane components | Accept, store, schedule, and reconcile the pod |
| Worker node | a node running kubelet, kube-proxy, runtime | Hosts the nginx pod |
| Pod nginx | kind: Pod, metadata.name: nginx | The smallest deployable unit |
| container nginx:1.27 | spec.containers[0].image: nginx:1.27 | The web server process inside the pod |
What is a Pod?
The smallest deployable unit in Kubernetes. A pod wraps one (or more) containers that share network (same IP) and storage.
Graph legend — each node maps to containers sharing one pod's network/storage:
| Graph node | Maps to | What it does |
|---|---|---|
| Pod - shared IP and shared volumes | a single kind: Pod | One network namespace and shared volumes for its containers |
| container nginx:1.27 | the main nginx:1.27 container | Serves the app on the pod IP |
| sidecar - log shipper | an optional second container | Reads nginx logs over the shared volume |
| localhost | the shared pod network | Lets the two containers reach each other on 127.0.0.1 |
- You usually run ONE main container per pod.
- Pods are ephemeral: they get replaced, not repaired.
Two ways to manage objects
Kubernetes accepts both styles: you can fire off imperative commands or hand it a declarative file describing the end state.
IMPERATIVE = tell K8s the exact COMMANDS to run (how)
DECLARATIVE = give K8s a YAML of the desired STATE (what)
| Imperative | Declarative | |
|---|---|---|
| Style | kubectl run/create ... | kubectl apply -f file.yaml |
| Best for | quick tests, exam speed | real/version-controlled infra |
| Repeatable | hard to track | yes (GitOps-friendly) |
| Idempotent | no | yes (re-apply = no-op) |
Imperative examples
Quick one-off commands that create and inspect a pod without writing any YAML.
kubectl run nginx --image=nginx # create a pod fast
kubectl get pods
kubectl get pods -o wide # node + pod IP
kubectl describe pod nginx # events & details
kubectl delete pod nginx
Declarative: a Pod YAML
Here the desired state lives in a file you version-control and apply — the
preferred way for real infrastructure.
pod.yaml:
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: web
spec:
containers:
- name: nginx
image: nginx:1.27
ports:
- containerPort: 80
kubectl apply -f pod.yaml # create or update to match file
kubectl get pod nginx -o yaml # full live spec
kubectl delete -f pod.yaml
The 4 required top-level YAML fields
Every Kubernetes manifest needs these four keys at the top.
apiVersion: which API group/version (e.g. v1, apps/v1)
kind: object type (Pod, Deployment...)
metadata: name, labels, namespace
spec: desired state of the object
Pro tip: generate YAML instead of hand-writing (exam gold)
Let kubectl write the boilerplate for you, then tweak the file instead of typing YAML from scratch.
# --dry-run=client builds the YAML WITHOUT creating anything
kubectl run nginx --image=nginx \
--dry-run=client -o yaml > pod.yaml
Debugging a pod
When a pod misbehaves, these three commands surface events, logs, and a shell inside the container.
kubectl describe pod nginx # see Events at the bottom
kubectl logs nginx # container stdout/stderr
kubectl exec -it nginx -- bash # shell inside
Imperative -> Declarative mental model
A handy workflow: generate a manifest from an imperative command, then manage it declaratively from then on.
Graph legend — each node maps to the generate-then-apply workflow for the nginx pod:
| Graph node | Maps to | What it does |
|---|---|---|
| kubectl run nginx ... --dry-run=client -o yaml | the imperative generate command | Prints a pod manifest without creating anything |
| pod.yaml | the saved manifest | Version-controlled desired state for the nginx pod |
| kubectl apply -f pod.yaml | the declarative apply | Submits the manifest to the cluster |
| cluster state in etcd | the stored object | The reconciled desired state |
End-to-end flow
Imperative and declarative paths both converge on the same reconcile flow that ends in a running pod.
Graph legend — each node maps to the path both styles take to a running nginx pod:
| Graph node | Maps to | What it does |
|---|---|---|
| kubectl run nginx imperative | kubectl run nginx --image=nginx:1.27 | One-off imperative creation |
| kubectl apply -f pod.yaml declarative | kubectl apply | Declarative creation from the manifest |
| API server | kube-apiserver | Validates and admits either request |
| Store in etcd | etcd write | Persists the desired pod |
| Scheduler picks node | kube-scheduler | Binds the pod to a node |
| kubelet on node | the node kubelet | Drives the runtime for the bound pod |
| Runtime pulls nginx:1.27 | containerd/CRI-O | Pulls the image and starts the container |
| Pod nginx Running | the live pod | Final reconciled state |
Key takeaways
- Pod = smallest unit; containers in it share IP + storage.
- Use imperative for speed, declarative for real infra.
--dry-run=client -o yamlgenerates manifests fast (use it in the exam).
Checklist
- [ ] Created a pod imperatively and declaratively
- [ ] Generated YAML with
--dry-run=client -o yaml - [ ] Used
describe,logs,execto inspect a pod