Manifests and kubectl
Scope: the grammar of every Kubernetes object —
four fields that never change — and kubectl, the
one tool you drive it all with.
Every object has the same four fields
A manifest is a YAML document describing one object. Whatever the object, the top level is:
apiVersion: apps/v1 # which API, which version
kind: Deployment # what kind of object this is
metadata: # identity: name, labels
name: hello-web
spec: # the desired state — the part that differs per kind
...
apiVersion+kindtogether say what this is:v1+Pod,apps/v1+Deployment,v1+Service. The API server rejects a pairing it doesn't know.metadatais identity: aname(unique among objects of this kind in the namespace), plus labels — key/value tags (app: hello-web) that other objects use to select this one. Labels look like decoration and are actually the cluster's connective tissue: Services find pods by label, Deployments count pods by label.specis the desired state proper. Everything past this point is kind-specific, and it's the only part you really write.
Namespaces divide one cluster into named
compartments (default is where things land when
you don't say). Objects are usually namespaced;
names only need to be unique within one.
A real manifest, generated by kubectl itself
You don't have to write YAML from memory: kubectl will draft it. This is actual output, produced while writing this guide (client-side, no cluster involved):
$ kubectl create deployment hello-web --image=nginx:alpine \
--replicas=2 --dry-run=client -o yaml
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: hello-web
name: hello-web
spec:
replicas: 2
selector:
matchLabels:
app: hello-web
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: hello-web
spec:
containers:
- image: nginx:alpine
name: nginx
resources: {}
status: {}
Two teaching points hide in it. The template
section is a pod description embedded in the
Deployment — the thing being replicated. And the
creationTimestamp: null / status: {} lines are
dry-run printing artifacts: real objects get real
timestamps, and status is written by the cluster,
never by you. Delete those two lines when you save
a generated draft as your manifest.
The working verbs
(Documented — these need a cluster.) Life with a manifest is a short loop:
kubectl apply -f deployment.yaml # create or update to match the file
kubectl get deployments # what exists, and is it as desired?
kubectl describe deployment hello-web # the object + recent events
kubectl delete -f deployment.yaml # remove what the file declares
apply is the heart of the declarative style: the
file is the truth, and applying it again after an
edit converges the cluster to the file. The opposite
style — imperative commands like kubectl scale or
kubectl set image — changes the live object
without changing any file. Both work; mixing them
carelessly doesn't, because the next apply will
quietly undo whatever the imperative command did
that the file doesn't know about. Pick files as
the source of truth; use imperative commands for
experiments and emergencies.
Check
On any machine with kubectl installed — no cluster
required — the generator above should work as
shown; it's how the draft for this guide's example
Deployment started. To validate a hand-written
file's shape without a cluster, a schema checker
such as kubeconform does it offline; every
manifest shipped in examples/ passed exactly
that check (see the README's note).