80+ kubectl commands with flags, real-world use cases, and gotchas. Searchable and filterable. Verified against official Kubernetes docs.
Everything runs in your browser. No commands or data are sent to any server.
5 essential commands to get you started. The full reference is right below.
kubectl get pods The most basic health check, showing what pods exist and their current status in a namespace.
kubectl describe pod <pod-name> The number one debugging command, showing the Events section that explains why something failed, not just its current status.
kubectl logs <pod-name> -f --previous --since=1h --tail=100 -c <container> Read what an application actually printed before or during a failure. It's the single most-used debugging command after describe.
kubectl apply -f deployment.yaml The standard way to create or update any resource declaratively from a YAML manifest, ideal for GitOps and CI pipelines.
kubectl rollout restart deployment/<name> Restart all pods to pick up a changed ConfigMap or Secret, since those changes do not automatically trigger a redeploy on their own.
kubectl cluster-info ↓ Click command to explain
When to use this
First command to run against a new cluster context to confirm kubectl can actually reach the API server before doing anything else.
Gotcha
This only shows the control plane URL, not overall cluster health. A clean cluster-info output does not mean every node or workload in the cluster is healthy.
kubectl version ↓ Click command to explain
--client Show only the local kubectl client version without contacting the cluster When to use this
Confirm client and server version skew before applying manifests that depend on a specific API version or feature gate.
Gotcha
Kubernetes only officially supports a client within one minor version of the server. A big skew can cause apply errors that look unrelated to versioning.
kubectl get nodes ↓ Click command to explain
-o wide Add internal/external IP, OS image, kernel version and container runtime columns When to use this
Quick health check of every node in the cluster before digging into a scheduling or capacity issue.
Gotcha
Node STATUS of Ready only reflects a recent kubelet heartbeat, not whether the node actually has spare CPU or memory capacity for more pods.
kubectl get namespaces ↓ Click command to explain
When to use this
See every namespace in the cluster when you are not sure where a workload was deployed.
kubectl create namespace <namespace-name> ↓ Click command to explain
When to use this
Set up an isolated namespace for a new team, environment, or application before deploying anything into it.
Gotcha
Namespaces do not provide network isolation by default. Pods in different namespaces can still talk to each other unless a NetworkPolicy explicitly blocks it.
kubectl delete namespace <namespace-name> ↓ Click command to explain
When to use this
Tear down an entire environment, such as a temporary review-app or staging namespace, in one command.
Gotcha
This deletes EVERY resource inside the namespace with no recovery option. This is the most dangerous command on this entire cheat sheet. Double check kubectl config current-context first.
kubectl config get-contexts ↓ Click command to explain
When to use this
See every cluster/user/namespace combination saved in your kubeconfig before switching between clusters.
Gotcha
The asterisk in the first column marks your CURRENT context. Always check this before running any destructive command. It is the single fastest sanity check that exists.
kubectl config use-context <context-name> ↓ Click command to explain
When to use this
Switch kubectl to point at a different cluster, such as moving from staging to production.
Gotcha
This is the number one cause of accidentally deleting or modifying something in the wrong cluster. Always confirm with kubectl config current-context after switching.
kubectl config current-context ↓ Click command to explain
When to use this
A sanity check before running any risky command, to confirm you are actually pointed at the cluster you think you are.
kubectl config set-context --current --namespace=<namespace> ↓ Click command to explain
When to use this
Avoid typing -n <namespace> on every single command when you are working in one namespace for an extended session.
Gotcha
This changes the default namespace stored in your kubeconfig, not just for the current terminal session. It persists until you change it again.
kubectl config view ↓ Click command to explain
--raw Include actual embedded credentials (certificates and tokens) instead of redacted placeholders When to use this
Inspect which clusters, users and contexts are merged into your active kubeconfig, especially after merging multiple config files.
Gotcha
The --raw flag includes actual credentials in plaintext. Never paste --raw output into a public chat, ticket, or AI chat tool.
kubectl cordon <node-name> ↓ Click command to explain
When to use this
Mark a node unschedulable before performing maintenance, so no new pods land on it while you investigate or patch it.
Gotcha
Cordon alone does NOT evict existing pods already running on the node. It only blocks new ones from being scheduled there. Pair it with drain to actually empty the node.
kubectl drain <node-name> --ignore-daemonsets --delete-emptydir-data ↓ Click command to explain
--ignore-daemonsets Required, otherwise drain refuses to proceed because DaemonSet-managed pods cannot be safely evicted --delete-emptydir-data Required if any pod uses an emptyDir volume, since that data cannot survive eviction anyway When to use this
Safely evict all pods from a node before decommissioning it or performing disruptive maintenance like a kernel upgrade.
Gotcha
Drain can hang indefinitely waiting for a PodDisruptionBudget to allow eviction. If it seems stuck, check kubectl get pdb -A for a budget blocking the last available replica.
kubectl uncordon <node-name> ↓ Click command to explain
When to use this
Mark a node schedulable again after maintenance is complete so the scheduler starts placing pods on it once more.
kubectl taint nodes <node-name> key=value:NoSchedule ↓ Click command to explain
When to use this
Reserve a node for specific workloads, such as GPU jobs or a dedicated tenant, by repelling everything else.
Gotcha
A taint repels pods without a matching toleration but does NOT attract pods to that node. To actually steer specific workloads onto it, combine the taint with nodeAffinity in the pod spec.
kubectl get componentstatuses ↓ Click command to explain
When to use this
Historically used to check whether the scheduler, controller-manager, and etcd were reporting healthy.
Gotcha
Deprecated since v1.19 and unreliable on managed clusters like EKS, GKE, and AKS, where it often just returns Unknown for every component. Use cloud-provider-specific health dashboards instead.
kubectl get pods ↓ Click command to explain
-A List pods across all namespaces instead of just the current one -o wide Add node, pod IP, and QoS class columns When to use this
The most basic health check, showing what pods exist and their current status in a namespace.
Gotcha
Running this with no flags only shows the default namespace. Use -A if your pod seems to have disappeared. It is almost always sitting in a different namespace.
kubectl get all ↓ Click command to explain
When to use this
Get a quick overview of pods, services, deployments, and replicasets in the current namespace at once.
Gotcha
Despite the name, get all does NOT return ConfigMaps, Secrets, Ingress objects, or custom resources. This trips up nearly every beginner who assumes 'all' really means all.
kubectl run tmp --image=busybox -it --rm -- sh ↓ Click command to explain
When to use this
Spin up a throwaway debug pod to test DNS resolution or network connectivity from inside the cluster, then have it clean itself up automatically.
Gotcha
Since Kubernetes v1.18, kubectl run only creates a plain Pod, not a Deployment. Older tutorials that assume it creates a Deployment are out of date.
kubectl label pod <pod-name> environment=production ↓ Click command to explain
--overwrite Required if the label key already exists on the resource, otherwise the command errors out When to use this
Tag pods so they can be selected by a Service, NetworkPolicy, or filtered with kubectl get pods -l.
kubectl annotate pod <pod-name> owner-team=platform ↓ Click command to explain
When to use this
Attach non-identifying metadata, like a build hash or deploy timestamp, that a CI tool or dashboard reads later.
Gotcha
Labels are for selection and filtering, annotations are for arbitrary metadata that tooling reads. Mixing them up, like trying to select on an annotation, is a common conceptual error.
kubectl delete pod <pod-name> ↓ Click command to explain
When to use this
Force a single unhealthy pod to restart when you suspect it is stuck in a bad state, such as a hung connection pool.
Gotcha
If the pod is managed by a Deployment or ReplicaSet it will be recreated within seconds. Deleting the pod does not delete the underlying workload that owns it.
kubectl cp ./local-file.txt <namespace>/<pod-name>:/path/in/container ↓ Click command to explain
When to use this
Push a config file, certificate, or patched binary into a running container without rebuilding the image.
Gotcha
Requires tar to be installed inside the target container. It silently fails or hangs on minimal or distroless images that do not have tar available.
kubectl cp <namespace>/<pod-name>:/path/in/container ./local-file.txt ↓ Click command to explain
When to use this
Pull a log file, heap dump, or generated report off a container for local inspection.
Gotcha
Same tar dependency as copying into a pod. This also requires tar inside the source container or it will fail with an unclear error.
kubectl get deployments ↓ Click command to explain
When to use this
Check replica counts and rollout status for every deployment in the current namespace at a glance.
kubectl apply -f deployment.yaml ↓ Click command to explain
When to use this
The standard way to create or update any resource declaratively from a YAML manifest, ideal for GitOps and CI pipelines.
Gotcha
Apply computes a diff against the last-applied-configuration annotation. If someone hand-edited the resource with kubectl edit, this can produce confusing three-way merge conflicts.
kubectl create -f deployment.yaml ↓ Click command to explain
When to use this
Create a brand-new resource once, in a one-off script where you specifically want it to fail if the resource already exists.
Gotcha
Unlike apply, create errors out with AlreadyExists if the resource already exists. It has no built-in update behaviour.
kubectl scale deployment <name> --replicas=5 ↓ Click command to explain
When to use this
Quickly add or remove replicas to handle a traffic spike or scheduled maintenance window.
Gotcha
If a HorizontalPodAutoscaler is managing this deployment, it can override your manual scale within seconds as it reconciles back to its target.
kubectl autoscale deployment <name> --min=2 --max=10 --cpu-percent=80 ↓ Click command to explain
When to use this
Automatically scale replica count between a floor and ceiling based on observed CPU utilization.
Gotcha
Requires metrics-server to be installed in the cluster. Without it, the HPA shows unknown targets in kubectl get hpa and never scales anything.
kubectl set image deployment/<name> <container>=<image>:<tag> ↓ Click command to explain
When to use this
Deploy a new image tag from a CI pipeline without re-applying the whole manifest.
kubectl patch deployment <name> -p '{"spec":{"replicas":3}}' ↓ Click command to explain
When to use this
Modify a single field on a live resource, such as replica count or an annotation, without touching the rest of the spec.
Gotcha
Quoting JSON correctly in a patch is a frequent source of shell-escaping errors, especially on Windows where quote characters behave differently between cmd, PowerShell, and Git Bash.
kubectl edit deployment <name> ↓ Click command to explain
When to use this
Make a quick emergency change directly against the live object when there is no time to update a manifest and re-apply.
Gotcha
Changes apply immediately on save with no confirmation step. Edits made this way are not tracked in version control and will be silently overwritten the next time kubectl apply runs.
kubectl replace -f deployment.yaml ↓ Click command to explain
When to use this
Force a full replacement of a resource's spec when apply's three-way merge is producing unwanted results.
Gotcha
Requires the full current spec or it fails outright. Most engineers should use apply instead. Replace is a niche escape hatch, not a default.
kubectl delete deployment <name> ↓ Click command to explain
When to use this
Remove a deployment and all of its managed ReplicaSets and Pods, such as decommissioning an old service.
Gotcha
This is a hard delete with no confirmation prompt and no built-in undo. Make sure the manifest is still in version control before running it.
kubectl rollout status deployment/<name> ↓ Click command to explain
When to use this
Block a CI/CD pipeline until a rolling update has fully finished, so the next pipeline step only runs against healthy pods.
Gotcha
Hangs indefinitely if the rollout is stuck, unless you set --timeout. This can silently freeze a CI job for hours until it hits an external timeout.
kubectl rollout history deployment/<name> ↓ Click command to explain
When to use this
See every revision of a deployment to decide which one to roll back to.
Gotcha
Without --record having been set on earlier apply commands, the CHANGE-CAUSE column is blank, making the history much less useful for figuring out what changed.
kubectl rollout undo deployment/<name> ↓ Click command to explain
When to use this
The fastest way back to a known-good state after a bad deploy causes a production incident.
Gotcha
Only works if the ReplicaSet history for that revision still exists. Kubernetes keeps 10 revisions by default via revisionHistoryLimit.
kubectl rollout pause deployment/<name> ↓ Click command to explain
When to use this
Stop a rolling update mid-flight to make multiple manifest changes that should be applied together as one rollout.
Gotcha
A paused deployment will NOT respond to kubectl rollout undo. You must resume it first before any rollout command takes effect.
kubectl rollout resume deployment/<name> ↓ Click command to explain
When to use this
Continue a rollout after finishing a batch of changes made while it was paused.
kubectl rollout restart deployment/<name> ↓ Click command to explain
When to use this
Restart all pods to pick up a changed ConfigMap or Secret, since those changes do not automatically trigger a redeploy on their own.
kubectl get services ↓ Click command to explain
When to use this
See what ClusterIP, NodePort, or LoadBalancer services exist and which ports they expose.
Gotcha
kubectl get svc is the common shorthand nearly every engineer uses day to day instead of typing the full word.
kubectl get ingress ↓ Click command to explain
When to use this
Check which hostnames and paths are routed to which backend services.
Gotcha
An Ingress object alone does nothing without an Ingress controller installed in the cluster. This is the most common source of 'why is my Ingress not working' confusion.
kubectl expose deployment <name> --port=80 --target-port=8080 ↓ Click command to explain
When to use this
Quickly create a Service in front of a deployment so other pods in the cluster can reach it by a stable name.
Gotcha
Forgetting --target-port when the container listens on a different port than the Service causes silent traffic failures. Connections just time out with no obvious error.
kubectl port-forward pod/<pod-name> 8080:80 ↓ Click command to explain
When to use this
Access a database or internal service running in the cluster from your local machine for debugging, without exposing it publicly.
Gotcha
The forward only lasts as long as the terminal session stays open, and it only proxies to that single pod. It does not load-balance across replicas.
kubectl get networkpolicies ↓ Click command to explain
When to use this
Audit which pods have traffic restrictions applied when investigating an unexpected connection failure or a security review.
Gotcha
A namespace with zero NetworkPolicies allows all traffic by default. Isolation only kicks in once at least one policy selects a pod, so half-configured policies can be more dangerous than none.
kubectl get configmaps ↓ Click command to explain
When to use this
See what non-sensitive configuration objects exist in a namespace before checking what a specific pod is actually using.
kubectl create configmap <name> --from-literal=key=value ↓ Click command to explain
--from-literal Add a single key=value pair directly on the command line --from-file Load one or more keys from the contents of a file, using the filename as the key --from-env-file Bulk-load every KEY=VALUE line from an env-style file as separate keys When to use this
Store application configuration, feature flags, or non-sensitive settings separately from the container image.
Gotcha
Imperatively created ConfigMaps are not in version control. Use --dry-run=client -o yaml to generate a manifest you can commit instead of creating it directly.
kubectl get secrets ↓ Click command to explain
When to use this
See what Secret objects exist in a namespace, such as database credentials or TLS certificates.
Gotcha
Values are base64-encoded and hidden in the list output. Use kubectl get secret <name> -o jsonpath to decode a specific value instead of guessing from the list view.
kubectl create secret generic <name> --from-literal=password=supersecret ↓ Click command to explain
When to use this
Store a database password, API key, or token for a pod to consume as an environment variable or mounted file.
Gotcha
Secrets are only base64-encoded, not encrypted, by default. Anyone with kubectl get/describe access on the Secret can decode the value instantly, so treat RBAC on Secrets as your real protection.
kubectl create secret tls <name> --cert=path/to/tls.crt --key=path/to/tls.key ↓ Click command to explain
When to use this
Load a certificate and private key pair for an Ingress controller to terminate HTTPS traffic.
kubectl create secret docker-registry <name> --docker-server=<registry> --docker-username=<user> --docker-password=<pass> --docker-email=<email> ↓ Click command to explain
When to use this
Authenticate the kubelet against a private container registry so it can pull images that require a login.
Gotcha
Creating the Secret is only half the fix. It does nothing until it's referenced by name in the pod spec's imagePullSecrets field.
kubectl get pv ↓ Click command to explain
When to use this
Check which cluster-wide storage volumes exist and whether they're Bound, Available, or Released.
Gotcha
PersistentVolumes are cluster-scoped, not namespaced. Never pass -n to this command. It will simply be ignored since PVs don't belong to any namespace.
kubectl get pvc ↓ Click command to explain
When to use this
Check whether a pod's storage request has been successfully bound to a volume before assuming a database pod's storage issue is elsewhere.
Gotcha
A PVC stuck in Pending almost always means no StorageClass can satisfy the requested size or access mode. Check the storageClassName and requested capacity.
kubectl describe pvc <name> ↓ Click command to explain
When to use this
Read the Events section to find the exact provisioning failure reason when a PVC is stuck Pending.
kubectl get storageclass ↓ Click command to explain
When to use this
Check which StorageClass is marked as default before creating a PVC that doesn't explicitly specify one.
Gotcha
Having zero or multiple default StorageClasses both cause confusing provisioning failures. With multiple defaults the behaviour depends on your cloud provider's admission controller.
kubectl get roles,rolebindings -n <namespace> ↓ Click command to explain
When to use this
Audit exactly what permissions exist within a single namespace during a security review or access debugging session.
kubectl create role <name> --verb=get,list,watch --resource=pods ↓ Click command to explain
When to use this
Define a set of permissions, like read-only access to pods, scoped to a single namespace.
Gotcha
A Role only grants access within its own namespace no matter how it is bound. It can never grant cluster-wide access.
kubectl create rolebinding <name> --role=<role-name> --user=<user> ↓ Click command to explain
When to use this
Actually grant the permissions defined in a Role to a specific user, group, or ServiceAccount.
Gotcha
A Role by itself grants nothing until it is bound to a subject via a RoleBinding. Creating the Role alone is a no-op.
kubectl create clusterrole <name> --verb=get,list,watch --resource=pods ↓ Click command to explain
When to use this
Define permissions that apply across every namespace, or to cluster-scoped resources like nodes and PersistentVolumes.
kubectl create clusterrolebinding <name> --clusterrole=cluster-admin --serviceaccount=<namespace>:<serviceaccount> ↓ Click command to explain
When to use this
Grant a ServiceAccount or user permissions across the entire cluster, such as for a cluster-wide monitoring agent.
Gotcha
This is the broadest grant available in RBAC. A common security review finding is cluster-admin granted to a ServiceAccount that only ever needed read access to one namespace.
kubectl create serviceaccount <name> ↓ Click command to explain
When to use this
Give a workload its own identity so RBAC permissions can be scoped precisely to what that workload needs, instead of relying on defaults.
Gotcha
Every namespace has a default ServiceAccount that pods use automatically if none is specified. Relying on it for anything with real permissions is a security smell.
kubectl auth can-i create pods --namespace=<namespace> ↓ Click command to explain
--as Check what a different user or ServiceAccount is permitted to do, instead of yourself When to use this
The fastest way to debug a 403 Forbidden error before hunting through Role and RoleBinding YAML by hand.
kubectl describe pod <pod-name> ↓ Click command to explain
When to use this
The number one debugging command, showing the Events section that explains why something failed, not just its current status.
Gotcha
New users see CrashLoopBackOff in kubectl get pod and stop there. describe is where the actual reason lives, so always run it next.
kubectl logs <pod-name> -f --previous --since=1h --tail=100 -c <container> ↓ Click command to explain
-f Stream logs continuously instead of printing a static snapshot --previous Show logs from the last terminated instance of the container, not the current one --since Only show logs newer than a relative duration, e.g. 1h --tail Limit output to the last N lines -c Specify which container's logs to show in a multi-container pod When to use this
Read what an application actually printed before or during a failure. It's the single most-used debugging command after describe.
Gotcha
If the pod already restarted, plain kubectl logs shows the new container's empty logs. Use --previous to see why the last one crashed. This is the flag people forget at 2am.
kubectl get events --sort-by=.metadata.creationTimestamp ↓ Click command to explain
--sort-by=.metadata.creationTimestamp Order events chronologically instead of the default, mostly-useless ordering When to use this
See scheduling failures, probe failures, and image pull errors across a namespace in one chronological timeline.
Gotcha
Events expire after about an hour by default, so check this early during an incident, because by the time you circle back the evidence may already be gone.
kubectl exec -it <pod-name> -- sh ↓ Click command to explain
When to use this
Poke around inside a running container to check environment variables, test DNS, or inspect a mounted file directly.
Gotcha
Minimal and distroless images often have no shell at all. exec failing with 'executable file not found' usually means no shell exists, not that something is broken.
kubectl debug <pod-name> -it --image=busybox --target=<container> ↓ Click command to explain
--copy-to Debug a disposable copy of the pod instead, if ephemeral containers aren't supported by the cluster When to use this
Debug minimal or distroless images by attaching a separate debug container with tools like curl and busybox, without restarting the original workload.
Gotcha
Requires cluster support for ephemeral containers. If your cluster doesn't support it, use --copy-to to debug a disposable copy of the pod instead.
kubectl top pods --containers ↓ Click command to explain
--containers Break usage down per container instead of aggregating per pod When to use this
Check live CPU and memory usage when investigating an OOMKilled pod or deciding whether to raise resource limits.
Gotcha
Silently fails with 'metrics not available' unless metrics-server is installed in the cluster, which is not part of Kubernetes core.
kubectl top nodes ↓ Click command to explain
When to use this
Check overall cluster capacity pressure before assuming a scheduling failure is caused by something else.
Gotcha
Same metrics-server dependency as kubectl top pods. This fails the same way if metrics-server isn't installed.
kubectl wait --for=condition=Ready pod/<pod-name> --timeout=60s ↓ Click command to explain
When to use this
In CI pipelines that need to block until a pod is Ready, instead of polling kubectl get in a loop.
Gotcha
Always set --timeout or this hangs indefinitely if the condition never becomes true, which can silently freeze a pipeline job.
kubectl delete all --all -n <namespace> ↓ Click command to explain
When to use this
Clean up a temporary test namespace by removing pods, services, deployments and replicasets in one shot.
Gotcha
Same as kubectl get all. This only targets common resource types and will NOT delete ConfigMaps, Secrets, PVCs, or CRDs left behind.
kubectl get pods -o jsonpath='{.items[*].metadata.name}' ↓ Click command to explain
When to use this
Pull just the pod names, or any specific nested field, out of a large kubectl get output for use in a shell script.
Gotcha
Quoting JSONPath correctly differs between bash, zsh, and PowerShell. A mismatched quote is the most common reason these one-liners fail when copy-pasted between environments.
kubectl get pods -o custom-columns=NAME:.metadata.name,STATUS:.status.phase ↓ Click command to explain
When to use this
Build a readable table with exactly the fields you care about, for a status report or quick audit.
kubectl get pods --watch ↓ Click command to explain
When to use this
Watch pods come up in real time during a rollout or scale-up, without repeatedly re-running kubectl get.
Gotcha
This command never exits on its own. You have to Ctrl-C out of it, which trips up scripts that call it expecting it to return.
kubectl apply -f deployment.yaml --dry-run=client ↓ Click command to explain
--dry-run=client Validate locally against the schema only, without contacting the cluster --dry-run=server Send the request to the API server for full validation, including admission webhooks, without persisting it When to use this
Sanity check a manifest for syntax and schema errors before actually applying it to a shared cluster.
Gotcha
Client-side dry-run only validates locally and will not catch errors that require cluster state, like an admission webhook rejecting the resource.
kubectl diff -f deployment.yaml ↓ Click command to explain
When to use this
See exactly what an apply would change before running it, useful in a CI gate that reviews infrastructure diffs.
Gotcha
Exits with a non-zero status code whenever there IS a difference, which can look like an error in scripts that don't account for it.
kubectl apply -k ./overlays/production ↓ Click command to explain
When to use this
Apply an environment-specific overlay of a base manifest, such as patching replica counts and image tags for production.
Gotcha
Kustomize support is built into kubectl since v1.14 with no separate install needed, which surprises people looking for a separate kustomize binary.
kubectl explain pod.spec.containers ↓ Click command to explain
When to use this
Look up what a specific manifest field does and what values it accepts, without leaving the terminal to check the docs.
The exact sequence engineers reach for first when something breaks in production. Run these in order before doing anything else.
kubectl get pods -A Get a cluster-wide view first before assuming the pod is in the namespace you expect. The most common beginner confusion is a pod that deployed to the wrong namespace. -A removes that guesswork immediately.
kubectl describe pod <pod-name> -n <namespace> Read the Events section at the bottom. This is where Kubernetes tells you the actual reason something failed. kubectl get pods only shows a status label. describe shows whether it is OOMKilled, ImagePullBackOff, a failed probe, or a scheduling failure.
kubectl logs <pod-name> -n <namespace> --previous If the pod already restarted, plain kubectl logs shows the new container's empty logs. --previous shows what the crashed instance printed right before it died. This is the flag people forget at 2am.
kubectl get events -n <namespace> --sort-by=.metadata.creationTimestamp Cluster events expire after about an hour so check this early. Sorting by timestamp puts them in chronological order. Without sorting the default output order is almost useless for incident diagnosis.
kubectl rollout undo deployment/<name> -n <namespace> If a recent deploy caused the incident this is the fastest path back to a known-good state. Faster than finding and re-applying the last-good manifest. Only works if the ReplicaSet history has not been garbage collected.
What the STATUS column in kubectl get pods is actually telling you and where to look next.
| Status | What it means | What to run next |
|---|---|---|
| Pending | Pod accepted by the cluster but not yet scheduled to a node. | kubectl describe pod <name> and read the Events section. Look for insufficient CPU or memory, unsatisfied node selectors, or taints without matching tolerations. |
| ImagePullBackOff | The kubelet cannot pull the container image from the registry. | Check the image name and tag for typos. Confirm the registry is reachable. Verify an imagePullSecret is attached to the pod spec if it is a private registry. |
| CrashLoopBackOff | The container starts, crashes immediately, and Kubernetes is backing off between restart attempts. | kubectl logs <name> --previous to see what the crashed instance printed. Then kubectl describe pod <name> for the exit code and Events section. OOMKilled exit code 137 means memory limit hit. |
| OOMKilled | The container exceeded its memory limit and the Linux kernel killed it. | kubectl top pod <name> --containers to see current memory usage. Either raise the memory limit in the pod spec or investigate a memory leak in the application. |
| CreateContainerConfigError | The pod spec references a ConfigMap or Secret key that does not exist in this namespace. | kubectl get configmap and kubectl get secret to confirm the referenced objects and keys actually exist in the correct namespace. |
| Running but not Ready | The container process is running but failing its readiness probe so the pod is not receiving traffic. | kubectl describe pod <name> to see the readiness probe failure reason and threshold counts. The app is alive but cannot serve traffic yet. |
kubectl is the command-line tool that talks to the Kubernetes API server, and for nearly every engineer running workloads on Kubernetes it is the primary interface to the cluster, more so than any dashboard or GUI. Every action a Kubernetes cluster performs, whether deploying an application, checking why a pod crashed, or rotating a secret, ultimately reduces to an HTTP request that kubectl constructs and sends. Learning kubectl well is not a nice-to-have skill for a Kubernetes engineer, it is the equivalent of learning to type for a writer: everything else depends on it being second nature.
The reason kubectl shows up in daily workflows so relentlessly is that Kubernetes itself is declarative and API-driven rather than something you configure once and forget. Deployments roll out gradually, pods get rescheduled when nodes fail, and autoscalers adjust replica counts continuously in the background, which means the state of a cluster is always shifting. Engineers check in on that state constantly: is the rollout finished, did the new pod come up healthy, is the autoscaler doing what it's supposed to. kubectl get, kubectl describe, and kubectl logs together form the read loop that every other action depends on, and most of a working day spent operating Kubernetes is really just cycling through those three commands with different arguments.
The mental model that makes kubectl click is understanding that almost everything in Kubernetes is a resource living inside a namespace, and kubectl is just a lens for viewing and editing those resources. A Pod, a Deployment, a Service, a Secret, a ConfigMap: these are all objects stored in etcd behind the API server, described by YAML or JSON, and namespaces are the folders that group and isolate them logically. Once that clicks, most kubectl commands stop feeling like memorized incantations and start feeling like predictable variations on a theme: get lists resources, describe explains one resource in depth, apply reconciles a manifest against live state, and delete removes it. The verb-resource pattern (kubectl <verb> <resource> <name>) covers the overwhelming majority of daily usage.
Three mistakes trip up nearly every engineer learning kubectl. The first is forgetting namespaces exist at all: running kubectl get pods with no flags only searches the default namespace, so a perfectly healthy pod running in a different namespace looks like it vanished. The second is assuming kubectl get all actually means all. It excludes ConfigMaps, Secrets, Ingress objects and any custom resource, which causes confusing gaps during audits. The third is confusing kubectl delete pod with actually removing a workload: if a Deployment owns that pod, Kubernetes recreates it within seconds, so deleting a pod is really just forcing a restart, not decommissioning anything. Internalizing these three quirks early saves hours of confused debugging later.