Overview¶
kubectl is both the control-plane interface and the primary diagnostic tool for a cluster. This guide covers the commands used to read cluster state — listing, filtering, and drilling into resources — as opposed to commands that change it (apply, create, delete, scale, etc.). For working across multiple clusters while inspecting them, see Merge Multiple kubectl Config Files. For attaching a debug container to a running or crashed pod, see Debugging containers with kubectl debug.
kubectl get — listing and filtering resources¶
The workhorse command for viewing resources.
kubectl get pods
kubectl get pods -n kube-system
kubectl get pods -A # all namespaces (shorthand for --all-namespaces)
Output formats¶
kubectl get pod mypod -o wide # adds node, IP, readiness gates
kubectl get pod mypod -o yaml # full manifest as stored in etcd
kubectl get pod mypod -o json
-o wide is the fastest way to see which node a pod landed on and its pod IP without a full describe. -o yaml/-o json show the resource exactly as the API server holds it, including status fields and server-populated defaults — useful for diffing against what you applied.
Narrowing output with jsonpath and custom-columns¶
kubectl get pods -o jsonpath='{.items[*].metadata.name}'
kubectl get pods -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.phase}{"\n"}{end}'
kubectl get pods -o custom-columns='NAME:.metadata.name,STATUS:.status.phase,NODE:.spec.nodeName'
jsonpath is precise but fiddly to write by hand; custom-columns is usually faster to reach for when you just want a different table shape than the default.
Selecting by label or field¶
kubectl get pods -l app=nginx
kubectl get pods -l 'environment in (staging,production)'
kubectl get pods --field-selector=status.phase=Running
kubectl get pods --field-selector=spec.nodeName=worker-3
Label selectors (-l) filter on arbitrary key/value metadata you or a controller applied; field selectors (--field-selector) filter on a fixed, resource-specific set of spec/status fields — the set of usable fields is much smaller than for labels and varies by resource kind.
Watching for changes¶
kubectl get pods --watch
kubectl get pods -w --output-watch-events # show ADDED/MODIFIED/DELETED events explicitly
--watch streams changes as they happen rather than polling — useful while a rollout or scale-up is in progress, but it's a long-running foreground command, not a snapshot.
Showing labels and sorting¶
kubectl get pods --show-labels
kubectl get pods --sort-by=.metadata.creationTimestamp
kubectl get pods --sort-by=.status.startTime
kubectl describe — human-readable detail and recent events¶
kubectl describe pod mypod
kubectl describe node worker-3
kubectl describe deployment myapp
describe is not just a prettier get -o yaml: it also pulls in the Events associated with the object (scheduling decisions, image pulls, restarts, probe failures) from the API server's event stream, which get does not show. When a pod is stuck Pending or crash-looping, describe pod is usually the first command to run — the Events: section at the bottom explains why far more often than the spec itself does.
For nodes, describe node also surfaces Allocatable vs Capacity, taints, and conditions (MemoryPressure, DiskPressure, PIDPressure, Ready) that get nodes collapses into a single STATUS column.
kubectl logs — container output¶
kubectl logs mypod
kubectl logs mypod -c sidecar-container # multi-container pod: name the container
kubectl logs mypod --all-containers
kubectl logs -f mypod # follow (stream)
kubectl logs --previous mypod # logs from the container's last (crashed) run
kubectl logs mypod --since=1h
kubectl logs mypod --since-time=2026-09-21T10:00:00Z
kubectl logs mypod --tail=200
kubectl logs -l app=nginx --all-containers=true --prefix # logs across every pod matching a label
--previous is the one people forget under pressure: for a pod that's currently crash-looping, plain kubectl logs shows the new container's (often empty) output, while --previous shows what the container printed right before it died. -l with --prefix fans a single log stream out across every pod matching a selector, prefixing each line with the source pod/container — handy for a Deployment with several replicas without reaching for a log aggregator.
For anything beyond a single follow session — tailing several pods long-term, filtering, or aggregating across a whole Deployment continuously — a dedicated tool such as stern or kubetail is usually a better fit than scripting kubectl logs in a loop.
kubectl top — live resource usage¶
kubectl top nodes
kubectl top pods
kubectl top pods -n mynamespace --containers
kubectl top pods --sort-by=cpu
kubectl top pods --sort-by=memory
top requires the metrics-server add-on to be running in the cluster; without it, every top command fails with a "metrics not available" error rather than falling back to anything else. It reports current usage only — there's no historical view here, so for trends over time you still need Prometheus/Grafana or similar, not kubectl top.
kubectl get events — the cluster-wide event feed¶
kubectl get events
kubectl get events -n mynamespace
kubectl get events --sort-by='.lastTimestamp'
kubectl get events --field-selector involvedObject.name=mypod
kubectl get events --watch
describe shows events scoped to one object; kubectl get events shows the raw event stream for a namespace (or, with -A, the cluster), which is useful when you don't yet know which object is misbehaving — e.g. hunting for FailedScheduling or BackOff events across an entire namespace after a bad rollout. Events are ephemeral (the API server garbage-collects them, typically after about an hour by default), so they're for real-time triage, not an audit log.
kubectl explain — inline API documentation¶
kubectl explain pod.spec
kubectl explain pod.spec.containers
kubectl explain deployment.spec.strategy.rollingUpdate --recursive
Pulls field documentation straight from the API server's OpenAPI schema for the exact API version the cluster is running — more reliable than searching the web when the cluster is on an older or newer Kubernetes version than what a search result assumes.
Discovering what's available: api-resources and api-versions¶
kubectl api-resources
kubectl api-resources --namespaced=true
kubectl api-resources -o wide # includes verbs each resource supports
kubectl api-versions
api-resources is the fastest way to find a resource's short name (kubectl get po vs pods), whether it's namespaced, and which API group it belongs to — especially useful after installing a CRD-based operator, to confirm its custom resources actually registered.
kubectl rollout — deployment history and status¶
kubectl rollout status deployment/myapp
kubectl rollout history deployment/myapp
kubectl rollout history deployment/myapp --revision=3
rollout status blocks and reports progress until a rollout finishes (or times out) — useful in scripts/CI as a readiness gate after kubectl apply. rollout history shows prior ReplicaSet revisions, which is the first place to look when deciding whether to kubectl rollout undo.
Interactive inspection: exec and port-forward¶
kubectl exec -it mypod -- /bin/sh
kubectl exec -it mypod -c sidecar-container -- /bin/bash
kubectl exec mypod -- cat /etc/resolv.conf # one-off command, no TTY needed
kubectl port-forward pod/mypod 8080:80
kubectl port-forward svc/myapp 8080:80
kubectl port-forward deployment/myapp 8080:80
exec only works if the target container actually has a shell in its image — distroless/scratch-based images will fail with "executable file not found," which is exactly the case kubectl debug (ephemeral containers) exists for; see Debugging containers with kubectl debug. port-forward is a quick way to reach a ClusterIP service or a specific pod from a workstation without exposing it via Ingress/NodePort — it's a foreground process bound to the local terminal, not a persistent tunnel.
A practical triage order¶
For a pod that isn't behaving, working through these in order covers most cases before reaching for anything heavier:
kubectl get pod mypod -o wide— is itRunning,Pending,CrashLoopBackOff,ImagePullBackOff? Which node?kubectl describe pod mypod— read theEvents:section for the actual reason (scheduling failure, failed probe, OOMKilled, image pull error).kubectl logs mypod(and--previousif it has restarted) — application-level errors.kubectl top pod mypod --containers— is it hitting a CPU/memory limit (consistent with anOOMKilledevent)?kubectl exec -it mypod -- shorkubectl debug— inspect the filesystem/network from inside if the above hasn't explained it.kubectl get events --sort-by='.lastTimestamp' -n <namespace>— check for cluster-level noise (node pressure, eviction) affecting more than just this pod.