Skip to main content

The kubectl Cheat Sheet for Running and Debugging Kubernetes Workloads

A practical kubectl cheat sheet for running and debugging Kubernetes workloads: get, describe, logs, exec, apply, scale, rollout, and context switching.

Published By Li Lei
#kubectl #kubernetes #devops #cheatsheet #sre

The kubectl Cheat Sheet for Running and Debugging Kubernetes Workloads

Most kubectl reference pages read like a man page someone reformatted: every flag, no judgment about which ten commands you actually type at 2am. This post is the opposite. It collects the kubectl commands I reach for to run, inspect, and unstick real workloads, in the rough order you hit them during an incident. If you want the searchable version with copy buttons and inline pitfalls, keep the kubectl cheat sheet open in a second tab while you read.

Looking at what is running: get, describe, logs, exec

Four commands carry the first ten minutes of any investigation.

kubectl get pods -n payments -o wide
kubectl describe pod checkout-7d9f-abc -n payments
kubectl logs -f deploy/checkout -n payments
kubectl exec -it checkout-7d9f-abc -n payments -- sh

get pods -o wide adds the node and IP columns, which matters the moment you suspect one node is sick. describe is the command people skip and shouldn't — the Events block at the bottom is where Kubernetes tells you, in plain English, why a pod won't schedule or won't pull. logs -f streams; add --previous and it shows the prior container, which is the only way to read a crash after a restart. For exec, always put -- before your command so the flags go to the container and not to kubectl, and reach for sh over bash — alpine and distroless images often ship sh only, and -- bash returns a confusing exit 127.

Shipping changes: apply, scale, rollout

Once you know what's wrong, you change it. The declarative path is apply, and the dash means standard input, which is the trick that lets you pipe a rendered template straight in without writing a temp file:

kubectl apply -f deploy.yaml -n payments
helm template release ./chart | kubectl apply -f -
kubectl scale deploy/checkout --replicas=4 -n payments
kubectl rollout restart deploy/checkout -n payments
kubectl rollout status deploy/checkout -n payments
kubectl rollout undo deploy/checkout -n payments

The one to internalize is rollout restart. When a teammate wants to "restart the service," the instinct is kubectl delete pod. Don't. On a single-replica deployment, delete briefly drops you to zero, and you get no rollout history. rollout restart bumps a template annotation so the controller performs a proper rolling update honoring maxUnavailable and maxSurge, keeps you at full capacity, and leaves rollout undo available if the new pods misbehave. StatefulSets and DaemonSets support it too. rollout status blocks until the update settles or fails, which makes it the natural last line of a deploy script.

Moving between clusters and namespaces

Half the "it works on my cluster" confusion is just being pointed at the wrong context. Check before you change anything:

kubectl config get-contexts
kubectl config current-context
kubectl config use-context prod-eu
kubectl get pods -n kube-system
kubectl config set-context --current --namespace=payments

That last line pins a default namespace to the current context so you stop typing -n payments on every command. If you switch contexts constantly, kubectx and kubens wrap these into a single keystroke — but it's worth knowing the raw config commands first, because they're what runs on a locked-down jump host where you can't install extras.

A worked example: a pod stuck in CrashLoopBackOff

Here's the scenario that sends people to this page. A pod shows CrashLoopBackOff and the dashboard is unhelpful. Walk it in order.

First, separate the two failure families. ImagePullBackOff is a registry problem — the container never started. CrashLoopBackOff means it did start and then exited, so this is an application problem.

kubectl get pods -n payments
# checkout-7d9f-abc   0/1   CrashLoopBackOff   6 (40s ago)   8m

kubectl logs checkout-7d9f-abc -n payments --previous
kubectl describe pod checkout-7d9f-abc -n payments

logs --previous is the load-bearing flag. A plain kubectl logs on a crash-looping pod shows the freshly started container, which usually hasn't failed yet — you read empty or half-startup output and conclude nothing. --previous shows the run that actually died, and that output is your real error.

Then read the Exit Code in describe. The numbers map to specific causes: 137 is OOMKilled (the kernel killed it for exceeding the memory limit), 143 is a clean SIGTERM, 1 is your application raising an unhandled error, and 0 is the sneaky one — your container's command ran to completion and exited, which means you packaged a one-shot script as a long-running server. A 137 tells you to raise the memory limit or fix a leak; a 0 tells you your entrypoint is wrong. The exponential backoff also means the pod can sit idle-looking for a minute between restarts; that delay is normal, not a second bug.

My on-call shortcut

The first time I owned a pager rotation, I lost twenty minutes to a CrashLoopBackOff because I kept running kubectl logs and seeing nothing useful — I didn't know about --previous yet. Now my muscle memory is a fixed three-step: logs --previous to read the death, describe to read the exit code, then either rollout restart if it was transient or an apply with a fixed limit if it was OOM. I keep the searchable sheet pinned precisely so I don't have to remember which signal maps to 143 versus 137 under pressure — I type 137 into the search box and the OOMKilled row jumps to the top with the fix already written next to it.

Quick reference

| Goal | Command | | --- | --- | | List pods with node + IP | kubectl get pods -o wide | | Read why a pod won't start | kubectl describe pod <name> | | Stream logs | kubectl logs -f <pod> | | Read the crash | kubectl logs <pod> --previous | | Shell into a container | kubectl exec -it <pod> -- sh | | Forward a port locally | kubectl port-forward svc/<name> 8080:80 | | Apply manifest / stdin | kubectl apply -f - | | Restart safely | kubectl rollout restart deploy/<name> | | Watch a rollout | kubectl rollout status deploy/<name> | | Switch context | kubectl config use-context <ctx> |

A few honest caveats. kubectl top pods needs metrics-server installed and healthy, or it returns a 503 that looks like a permissions error but isn't. Force-deleting a Terminating pod with --grace-period=0 --force clears the symptom but leaves dangling endpoints — fix the stuck finalizer or volume instead. And for distroless images with no shell at all, exec is a dead end; use kubectl debug to attach an ephemeral container with real tooling.

That's the working set. If you live in the terminal across more than Kubernetes, the same searchable-with-pitfalls format covers the rest of the toolbelt: the Docker cheat sheet for the layer below your pods, the Bash cheat sheet for the glue scripts, and the Git cheat sheet for the manifests you keep in version control. Run kubectl long enough and the commands above become reflex — until then, keep the sheet open.


Made by Toolora · Updated 2026-06-13