Kubernetes Cheat Sheet: The Object Model Before the Commands
β‘ Quick Answer
A practical Kubernetes cheat sheet β the object model explained as a map, kubectl commands grouped by task, probes, resource limits, and how to debug a crashing pod.
Get more content like this on Telegram!
Daily AI tips, notes & resources β free
Advertisement
Kubernetes Cheat Sheet
Kubernetes is not hard because the commands are complicated. It is hard because the commands operate on an object model most people never learn properly.
kubectl has maybe fifteen verbs you use daily. The confusion comes from not knowing what a Pod is versus a Deployment, or why a Service exists at all.
So this sheet does the map first, then the commands.
Updated for 2026. Kubernetes 1.30+ and kubectl.
The Object Model
Think of a Kubernetes cluster as an office building.
| Object | What it is | Building analogy |
|---|---|---|
| Pod | One or more containers sharing a network and storage | A desk with one worker at it |
| ReplicaSet | Keeps N identical Pods alive | A supervisor who refills empty desks |
| Deployment | Manages ReplicaSets to enable safe rollouts | The manager who swaps in a new team gradually |
| Service | A stable internal address for a set of Pods | The department phone extension |
| Ingress | Routes external HTTP traffic to Services | The reception desk with a directory |
| ConfigMap | Non-secret configuration data | The staff handbook |
| Secret | Credentials, base64-encoded at rest | The locked drawer |
| PersistentVolumeClaim | A request for durable storage | A filing cabinet that survives staff changes |
| Namespace | A logical partition of the cluster | A floor of the building |
The chain that matters: you write a Deployment, it creates a ReplicaSet, which creates Pods, and a Service gives those Pods one address that does not change when they do.
That last clause is the whole reason Services exist. Pods get a new IP every time they are recreated, and they are recreated constantly. Nothing can hard-code a Pod IP. The Service is the stable name in front of a moving target.
What people get wrong: treating a Pod as a long-lived machine. A Pod is cattle, not a pet. It is designed to be deleted and replaced, and any state you keep inside its container filesystem dies with it.
Daily Commands
kubectl get pods # in the current namespace
kubectl get pods -A # every namespace
kubectl get pods -o wide # adds node and pod IP
kubectl get deploy,svc,ingress # several kinds at once
kubectl describe pod <name> # config + EVENTS (the useful bit)
kubectl logs <pod> # stdout/stderr of the container
kubectl logs -f --tail=100 <pod> # follow
kubectl logs <pod> -c <container> # multi-container pods
kubectl logs <pod> --previous # the run that just crashed
kubectl exec -it <pod> -- sh # shell inside a RUNNING pod
kubectl port-forward svc/api 8080:80 # tunnel a service to localhost--previous is the command most people never learn, and it is the one that solves CrashLoopBackOff. The current container may have started two seconds ago and logged nothing; the useful stack trace belongs to the run before it.
kubectl apply -f manifest.yaml # create or update, declaratively
kubectl delete -f manifest.yaml
kubectl diff -f manifest.yaml # what would change if I applied thisUse apply, not create. apply is idempotent β running it twice does nothing the second time. create errors if the object exists, which makes it useless in a pipeline.
Namespaces and Context
kubectl config get-contexts
kubectl config use-context prod-cluster
kubectl config set-context --current --namespace=staging
kubectl get pods -n kube-systemSet the namespace on your context rather than typing -n on every command. Forgetting -n is how people run kubectl delete deploy api against default when they meant staging β and how they run it against production when they meant staging.
Always check kubectl config current-context before anything destructive.
Debugging a Crashing Pod
This is the section to print.
The order matters more than the commands. Describe before logs.
kubectl get pods # 1. what state is it in?
kubectl describe pod <name> # 2. read the Events at the bottom
kubectl logs <pod> --previous # 3. only if the container actually ranWhy logs are empty when a pod never started: logs capture what a process wrote. If the image could not be pulled, or the pod was never scheduled, or an init container failed, there is no process. Nothing wrote anything. The failure is recorded in Events, not logs.
Reading the status column
| Status | What it means | First thing to check |
|---|---|---|
Pending | Not scheduled onto any node | describe events β usually insufficient CPU/memory, or an unbound PVC |
ImagePullBackOff | Cannot fetch the image | Image name, tag, and registry credentials (imagePullSecrets) |
CrashLoopBackOff | Starts, exits, restarts, repeat | logs --previous |
OOMKilled / exit 137 | Kernel killed it for exceeding memory | Raise limits.memory or fix the leak |
Error | Container exited non-zero | logs --previous |
Terminating (stuck) | Finalizer or long terminationGracePeriodSeconds | describe for finalizers |
Pending is a scheduling problem, never an application problem. The application has not run and will not run. Something about the request cannot be satisfied: no node has enough free CPU or memory to meet your requests, a node selector or taint excludes every node, or a PersistentVolumeClaim has no matching volume.
137 is 128 + 9 β the process received SIGKILL. In a container that nearly always means the memory limit. It is not a bug in your error handling; your process was never given the chance to handle anything.
kubectl get events --sort-by=.lastTimestamp # cluster-wide, newest last
kubectl top pod # actual CPU/memory in use
kubectl debug -it <pod> --image=busybox --target=app # ephemeral debug containerkubectl debug attaches a container with real tools into a running pod's namespaces β the answer to "the image is distroless and has no shell."
The YAML That Matters
A Deployment has many fields. These are the ones that change behaviour.
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
spec:
replicas: 3
selector:
matchLabels:
app: api # MUST match template.metadata.labels
template:
metadata:
labels:
app: api
spec:
containers:
- name: api
image: myrepo/api:1.4.2 # never :latest
ports:
- containerPort: 3000
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: api-secrets
key: database-url
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
memory: 512Mi
readinessProbe:
httpGet: { path: /ready, port: 3000 }
initialDelaySeconds: 5
periodSeconds: 5
livenessProbe:
httpGet: { path: /healthz, port: 3000 }
initialDelaySeconds: 30
periodSeconds: 10selector.matchLabels must match template.metadata.labels. If they do not, the Deployment creates Pods it does not consider its own, then creates more, forever. It is the single most common manifest error and the error message is not obvious.
Never use :latest. A tag that moves means two Pods from the same Deployment can run different code, and a rollback has nothing distinct to roll back to.
Requests vs Limits
| Requests | Limits | |
|---|---|---|
| Used by | The scheduler, at placement time | The kernel, at runtime |
| Meaning | Reserve at least this much | Never exceed this |
| CPU over-use | β | Throttled (slower, still alive) |
| Memory over-use | β | Killed, exit 137 |
Requests decide where your pod lands. Limits decide what happens when it misbehaves.
Two practical consequences.
A Pending pod with idle-looking nodes means the sum of requests already booked on each node leaves no room for yours β regardless of actual usage. The scheduler does arithmetic on requests, not on kubectl top.
Many teams set a memory limit and no CPU limit deliberately. CPU throttling degrades latency in ways that are hard to diagnose, while memory genuinely must be bounded because it cannot be reclaimed by slowing down. Set requests for both; be more careful before setting a CPU limit.
Readiness vs Liveness
| Probe | Question | On failure |
|---|---|---|
| readinessProbe | Can it serve traffic now? | Removed from Service endpoints; container untouched |
| livenessProbe | Is it still healthy? | Container is killed and restarted |
| startupProbe | Has it finished booting? | Delays the other two until it passes |
Readiness controls routing. Liveness controls restarts. Confusing them is expensive.
The classic failure: an application takes 45 seconds to warm a cache, and the liveness probe starts checking at 10 seconds. Kubernetes kills it at 30, restarts it, kills it again. CrashLoopBackOff on an application with no bug in it.
The fix is a startupProbe with a generous failureThreshold. Liveness only begins once startup has succeeded, so slow boots and genuine hangs are no longer the same signal.
A liveness probe should test liveness, not dependencies. If /healthz also checks the database, one database blip restarts every pod in the fleet simultaneously β turning a degraded service into an outage.
Services and Ingress
apiVersion: v1
kind: Service
metadata:
name: api
spec:
type: ClusterIP
selector:
app: api # matches Pod labels, not Deployment name
ports:
- port: 80 # the Service port
targetPort: 3000 # the container port| Type | Reachable from | Use for |
|---|---|---|
ClusterIP | Inside the cluster only | Default; internal services |
NodePort | A fixed port on every node | Local clusters, debugging |
LoadBalancer | The internet, via a cloud LB | One public entry point per service |
ExternalName | DNS alias to an outside host | Pointing at a managed database |
A Service selects Pods by label, not by Deployment. This is why a Service can return no endpoints while your pods are clearly running: the labels do not match. Check with kubectl get endpoints <service> β an empty list is the whole diagnosis.
Ingress replaces one LoadBalancer per service with one for all of them, routing by hostname and path at layer 7. It needs an ingress controller installed; an Ingress object alone does nothing.
Config and Secrets
kubectl create configmap app-config --from-literal=LOG_LEVEL=debug
kubectl create secret generic api-secrets --from-literal=database-url='postgres://...'
kubectl get secret api-secrets -o jsonpath='{.data.database-url}' | base64 -dSecrets are base64-encoded, not encrypted. Base64 is an encoding, not a cipher β anyone with read access to the Secret has the value. Enable encryption at rest on etcd, restrict RBAC, and never commit a Secret manifest to Git unencrypted.
Changing a ConfigMap does not restart your pods. Values injected as env are read once at container start. Either mount the ConfigMap as a volume, which updates in place after a delay, or roll the Deployment explicitly with kubectl rollout restart deployment/api.
Rollouts and Rollback
kubectl set image deployment/api api=myrepo/api:1.4.3
kubectl rollout status deployment/api # blocks until done or failed
kubectl rollout history deployment/api
kubectl rollout undo deployment/api # back one revision
kubectl rollout undo deployment/api --to-revision=3
kubectl rollout restart deployment/api # recreate pods, same imageA Deployment rolls out by scaling a new ReplicaSet up while scaling the old one down, governed by maxSurge and maxUnavailable.
A "stuck" rollout is usually working correctly. The new pods are failing their readiness probe, so the Deployment refuses to remove the old ones. That is the safety mechanism, not a bug. Run kubectl describe pod on a new pod and fix the real failure rather than forcing anything.
kubectl rollout restart is the clean way to pick up a rotated Secret or a changed ConfigMap β it patches an annotation on the template, which triggers a normal rolling update with zero downtime.
The Five Mistakes
1. Reaching for logs before describe. If the container never started, logs are empty by definition. Events hold the answer.
2. selector.matchLabels not matching template.labels. Pods multiply, nothing works, the error is cryptic.
3. An aggressive liveness probe on a slow-starting app. You get CrashLoopBackOff on perfectly healthy code. Use a startupProbe.
4. Assuming Pending is an app problem. It is a scheduling problem β requests, taints, or an unbound PVC.
5. Treating Secrets as encrypted. Base64 is encoding. Restrict RBAC and encrypt etcd.
Print This Section
DEBUG ORDER get pods β describe pod (READ EVENTS) β logs --previous
STATUS Pending = scheduling (requests / taints / PVC)
ImagePullBackOff = image name, tag, or pull secret
CrashLoopBackOff = logs --previous
137 / OOMKilled = memory limit exceeded
MODEL Deployment β ReplicaSet β Pod ; Service = stable address
Service selects PODS BY LABEL β kubectl get endpoints
RESOURCES requests = scheduling limits = enforcement
CPU over limit = throttled ; memory over limit = killed
PROBES readiness = routing liveness = restart
slow boot? use startupProbe, not a longer liveness delay
ROLLOUT kubectl rollout status / undo / restart deployment/<name>
stuck rollout = new pods failing readiness
SAFETY kubectl config current-context before anything destructiveLearn the object chain once β Deployment to ReplicaSet to Pod, with a Service in front β and most kubectl output stops being noise and starts being a sentence.
π Next in this collection: Docker Cheat Sheet for Developers, or return to The Complete Developer Cheat Sheet Collection.
Advertisement
π¬ DiscussionPowered by GitHub Discussions
Frequently Asked Questions

AI & Software Engineering Editorial Team
The AiTechWorlds editorial team writes and reviews in-depth guides on artificial intelligence, machine learning, prompt engineering, programming, and developer tools. Every article is fact-checked against primary sources and kept up to date for working developers and CS students.
Not sure yet? Ask AI about this article
Get an instant, unbiased AI summary of βKubernetes Cheat Sheet: The Object Model Before the Commandsβ.
Advertisement
Related Articles
Bash Scripting Cheat Sheet (The First Line Every Script Needs)
A practical Bash scripting cheat sheet β variables, conditionals, loops, functions, and the set -euo pipefail line that turns silent failure into loud failure.
15 Coding Interview Patterns That Solve Most Problems
The 15 coding interview patterns that cover most problems β the signal that identifies each one, a minimal code skeleton, and a two-minute recognition table.
CSS and Tailwind Cheat Sheet: Flexbox, Grid and Centering Solved
A practical CSS and Tailwind cheat sheet β Flexbox vs Grid decision rules, every centering method, responsive breakpoints, and the specificity traps.
Data Structures and Big-O Cheat Sheet for Coding Interviews
A practical big O cheat sheet β the complexity ladder with real examples, data structure operation tables, and how to state your complexity in an interview.