Logo
CloudWithSingh
Back to all field notes
Cheatsheet
Kubernetes
Intermediate

kubectl Field Notes

kubectl organized by what you're doing, not alphabetically. Context, debugging, imperative vs declarative, rollouts, and the traps that waste an afternoon.

Parveen Singh
September 9, 2026
10 min read
61 commands
Prerequisites:A running cluster (local or cloud) and kubectl pointed at itBasic terminal comfortWhat a Pod is, roughly
TLDR

kubectl talks to the Kubernetes API, not to your cluster directly. Every command follows kubectl VERB TYPE NAME, and most of what trips people up (wrong context, a deleted Pod that comes right back, logs that show nothing) comes from not knowing what's actually managing what. This reference is organized by task, not alphabetically: context, reading resources, debugging, creating things the right way, rollouts, and the five traps that waste an afternoon.

🧭 The kubectl Grammar

Almost every command is the same shape.

kubectl verb type name flags

kubectl get pod my-app -o wide is verb get, type pod, name my-app, flag -o wide. Once this clicks, you stop memorizing commands and start assembling them.

VerbDoes
getLists or reads current state
describeReads state plus recent events, human formatted
createMakes a new object imperatively, errors if it exists
applyCreates or updates from a file, declarative
deleteRemoves an object
editOpens the live object in your editor
logsReads container stdout/stderr
execRuns a command inside a container
rolloutManages Deployment history
port-forwardTunnels a local port to a Pod or Service
When to Use

When you forget a command, don't reach for a search engine. Say the sentence out loud: "I want to VERB a TYPE named NAME." It's usually already valid kubectl.

Drive Your First Cluster with kubectl Verbs | CloudLearn
Hands-on LabCloudlearn.io

Drive Your First Cluster with kubectl Verbs | CloudLearn

Practice kubectl get, describe, and explain on a pre-built kind cluster before touching any YAML.

labs.cloudlearn.ioPractice This

🔌 Context and Cluster Access

kubeconfig can hold several clusters at once. Context decides which one you're talking to, and namespace decides which slice of it.

CommandWhat It Does
kubectl config get-contextsLists every context in your kubeconfig
kubectl config current-contextShows which one is active right now
kubectl config use-context <name>Switches clusters
kubectl config set-context --current --namespace=<ns>Pins the default namespace for the current context
kubectl config view --minifyShows only the active context's config, not the whole file
Gotcha

use-context switches the cluster. It does not switch the namespace. You can be pointed at the right cluster and the wrong namespace and every get will look empty or wrong, with no error telling you why.

🔍 Get vs Describe

Two different questions. get answers "what exists and what state is it in." describe answers "what happened to it recently."

CommandWhat It Does
kubectl get podsLists Pods in the current namespace
kubectl get pods -ALists Pods across every namespace
kubectl get pods -o wideAdds node, IP, and readiness columns
kubectl get pods -wWatches for changes live
kubectl get pod <name> -o yamlFull object definition as YAML
kubectl describe pod <name>State plus the Events section at the bottom, which is where most answers live
Pro Tip

Read describe's Events section before anything else when a Pod misbehaves. That's where ImagePullBackOff, failed scheduling, and readiness probe failures actually show up. get will just say Pending or CrashLoopBackOff with no reason attached.

🐛 Debugging

CommandWhat It Does
kubectl logs <pod>Current container's stdout/stderr
kubectl logs <pod> -fStreams logs live
kubectl logs <pod> -c <container>Picks a container in a multi-container Pod
kubectl logs <pod> --previousLogs from the container's last run, before it crashed
kubectl get events --sort-by=.lastTimestampCluster-wide event stream, newest last
kubectl top pod / kubectl top nodeLive CPU and memory, needs metrics-server
kubectl debug <pod> -it --image=busybox --target=<container>Attaches an ephemeral debug container to a running Pod
Warning

--previous only works while the crashed container's record still exists. Once the Pod restarts again or gets rescheduled, that log is gone. Grab it on the first crash, not the third.

Gotcha

kubectl exec -it <pod> -- sh fails with "executable file not found" on distroless or scratch images, because there's no shell to exec into. That's not a permissions problem. kubectl debug with an ephemeral container is the only way in.

Inspect, Create, and Debug Your First Pod with kubectl | CloudLearn
Hands-on LabCloudlearn.io

Inspect, Create, and Debug Your First Pod with kubectl | CloudLearn

Author a Pod, watch its lifecycle, debug an ImagePullBackOff with describe, then prove a multi-container Pod shares localhost networking and an emptyDir volume.

labs.cloudlearn.ioPractice This

🏗️ Imperative vs Declarative

Two ways to create things, and they don't mix cleanly.

CommandWhat It Does
kubectl run nginx --image=nginxImperative: creates one Pod right now
kubectl create deployment nginx --image=nginxImperative: creates a Deployment right now
kubectl apply -f deployment.yamlDeclarative: makes the cluster match the file, creating or updating as needed
kubectl delete -f deployment.yamlRemoves everything defined in that file
Gotcha

apply tracks what it last applied in an annotation, so it can compute a clean diff next time. An imperative edit, whether that's kubectl edit, kubectl scale, or kubectl set image, changes the live object without updating that annotation. The next apply from the original file can silently revert your imperative change, because as far as apply knows, nothing changed on its end. Pick one method per object and stay there.

📝 Generating YAML Without Writing It

The fastest way to get a correct starting YAML file is to have kubectl generate one and edit from there.

CommandWhat It Does
kubectl create deployment nginx --image=nginx --dry-run=client -o yamlPrints the YAML, creates nothing
kubectl run nginx --image=nginx --dry-run=client -o yaml > pod.yamlSame idea, saved to a file
kubectl create service clusterip my-svc --tcp=80:8080 --dry-run=client -o yamlGenerates a Service definition
kubectl expose deployment nginx --port=80 --dry-run=client -o yamlGenerates a Service from an existing Deployment's labels
Pro Tip

--dry-run=client never touches the cluster. --dry-run=server sends the request to the API server for validation and admission checks, then discards it, which catches errors the client-side check can't see, at the cost of one real API round trip.

🔄 Rollouts and Rollback

Deployments keep a revision history. This is how you use it.

CommandWhat It Does
kubectl rollout status deployment/<name>Watches a rollout until it finishes or stalls
kubectl rollout history deployment/<name>Lists past revisions
kubectl rollout undo deployment/<name>Rolls back to the previous revision
kubectl rollout undo deployment/<name> --to-revision=3Rolls back to a specific one
kubectl rollout restart deployment/<name>Forces new Pods without changing the image, useful after a ConfigMap or Secret update
kubectl set image deployment/<name> <container>=<image>Updates the image and triggers a rollout
When to Use

rollout restart is the fix when Pods need to pick up a changed ConfigMap or Secret, since those don't trigger a rollout on their own unless the Pod spec references them by hash or you're using a tool that does.

🔗 Port Forward

Talk to something inside the cluster without exposing it.

CommandWhat It Does
kubectl port-forward pod/<name> 8080:80Local port 8080 to that Pod's port 80
kubectl port-forward svc/<name> 8080:80Same, but through a Service, so it survives the Pod restarting
kubectl port-forward deployment/<name> 8080:80Picks one Pod from the Deployment automatically
Pro Tip

Forward to the Service, not the Pod, for anything you'll run for more than a minute. A Pod-level forward dies the instant that specific Pod is replaced.

📦 Namespaces and Cleanup

CommandWhat It Does
kubectl create namespace <name>Makes a new namespace
kubectl get all -n <namespace>Lists the common object types in one namespace
kubectl delete namespace <name>Deletes the namespace and everything in it
kubectl delete pods --field-selector=status.phase=FailedCleans up only failed Pods
kubectl delete pods --all -n <namespace>Deletes every Pod in a namespace, Deployments will recreate theirs
Warning

kubectl delete namespace is not reversible and does not ask twice. Everything in it, including PersistentVolumeClaims, goes with it.

🔎 JSONPath and Custom Columns

For when -o wide isn't the column you need.

CommandWhat It Does
kubectl get pods -o jsonpath='{.items[*].metadata.name}'Just the Pod names, space separated
kubectl get pods -o custom-columns=NAME:.metadata.name,STATUS:.status.phaseA table with exactly the columns you asked for
kubectl get nodes -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.capacity.cpu}{"\n"}{end}'Node name and CPU capacity, one per line
When to Use

Scripting, or feeding kubectl output into another command. For a human reading the terminal, -o wide or describe is almost always faster to parse.

🔐 Permissions: auth can-i

Before assuming an error is a bug, check whether it's RBAC.

CommandWhat It Does
kubectl auth can-i create podsCan you, right now, create Pods in this namespace
kubectl auth can-i list secrets -n kube-systemChecks a specific namespace
kubectl auth can-i create pods --as=system:serviceaccount:default:my-saChecks what a ServiceAccount can do, not you
kubectl auth can-i '*' '*'Are you effectively cluster-admin
Pro Tip

--as is the fastest way to debug "works for me, fails in the Pod." Run the same check as the ServiceAccount the Pod actually uses, instead of guessing at its RoleBindings.

⚠️ Five Traps

TrapWhat Actually Happens
Deleting a Pod that belongs to a DeploymentThe Pod comes right back. You deleted an instance, not the thing managing it. Delete the Deployment, or scale it to 0, if that's the actual goal.
Editing an object that apply also managesThe next apply can silently undo your edit, because apply's diff is against its own last-applied record, not against what's currently live.
exec-ing into a distroless imageNo shell exists to exec into. Looks like a permissions error, isn't one. Use kubectl debug instead.
Trusting get alone when a Pod won't startget shows the status word. describe's Events section shows the reason. Always check both.
Assuming a context switch also switches namespaceIt doesn't. You can run a command against the right cluster, wrong namespace, and get a plausible-looking empty result instead of an error.

⚡ Ten to Actually Remember

kubectl get pods -A
kubectl describe pod <name>
kubectl logs <pod> -f --previous
kubectl exec -it <pod> -- sh
kubectl apply -f .
kubectl rollout status deployment/<name>
kubectl rollout undo deployment/<name>
kubectl port-forward svc/<name> 8080:80
kubectl config use-context <name>
kubectl auth can-i <verb> <resource>

📦 Past kubectl: Helm

Once raw manifests start repeating across environments, the next tool most teams reach for is Helm, Kubernetes' package manager. It packages a set of manifests into one versioned, reusable chart you install, upgrade, and roll back as a unit instead of hand-maintaining YAML per environment.

Install Your First Helm Chart on Kubernetes | CloudLearn
Hands-on LabCloudlearn.io

Install Your First Helm Chart on Kubernetes | CloudLearn

Use Helm as a package manager - add a repo, install a sample app chart, override values, upgrade, roll back, and uninstall.

labs.cloudlearn.ioStart Learning

What's Next

Bookmark this page

Save it for your next project sprint

Start a project

Apply what you just learned hands-on

Follow on Instagram

Daily cloud tips & behind-the-scenes

Try hands-on labs

Practice in a real cloud environment

Parveen Singh

Parveen Singh

Microsoft Certified Trainer & Cloud Solutions Consultant

Related Field Notes

Found this useful?

Stay in the loop

Weekly cloud insights, no spam

Subscribe

Explore CloudLearn

Hands-on labs & projects

Start Learning

Book Training

Custom cloud training for your team

Get in Touch

On this page

Subscribe