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.
| Verb | Does |
|---|---|
get | Lists or reads current state |
describe | Reads state plus recent events, human formatted |
create | Makes a new object imperatively, errors if it exists |
apply | Creates or updates from a file, declarative |
delete | Removes an object |
edit | Opens the live object in your editor |
logs | Reads container stdout/stderr |
exec | Runs a command inside a container |
rollout | Manages Deployment history |
port-forward | Tunnels a local port to a Pod or Service |

Drive Your First Cluster with kubectl Verbs | CloudLearn
Practice kubectl get, describe, and explain on a pre-built kind cluster before touching any YAML.
🔌 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.
| Command | What It Does |
|---|---|
kubectl config get-contexts | Lists every context in your kubeconfig |
kubectl config current-context | Shows 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 --minify | Shows only the active context's config, not the whole file |
🔍 Get vs Describe
Two different questions. get answers "what exists and what state is it in." describe answers "what happened to it recently."
| Command | What It Does |
|---|---|
kubectl get pods | Lists Pods in the current namespace |
kubectl get pods -A | Lists Pods across every namespace |
kubectl get pods -o wide | Adds node, IP, and readiness columns |
kubectl get pods -w | Watches for changes live |
kubectl get pod <name> -o yaml | Full object definition as YAML |
kubectl describe pod <name> | State plus the Events section at the bottom, which is where most answers live |
🐛 Debugging
| Command | What It Does |
|---|---|
kubectl logs <pod> | Current container's stdout/stderr |
kubectl logs <pod> -f | Streams logs live |
kubectl logs <pod> -c <container> | Picks a container in a multi-container Pod |
kubectl logs <pod> --previous | Logs from the container's last run, before it crashed |
kubectl get events --sort-by=.lastTimestamp | Cluster-wide event stream, newest last |
kubectl top pod / kubectl top node | Live CPU and memory, needs metrics-server |
kubectl debug <pod> -it --image=busybox --target=<container> | Attaches an ephemeral debug container to a running Pod |

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.
🏗️ Imperative vs Declarative
Two ways to create things, and they don't mix cleanly.
| Command | What It Does |
|---|---|
kubectl run nginx --image=nginx | Imperative: creates one Pod right now |
kubectl create deployment nginx --image=nginx | Imperative: creates a Deployment right now |
kubectl apply -f deployment.yaml | Declarative: makes the cluster match the file, creating or updating as needed |
kubectl delete -f deployment.yaml | Removes everything defined in that file |
📝 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.
| Command | What It Does |
|---|---|
kubectl create deployment nginx --image=nginx --dry-run=client -o yaml | Prints the YAML, creates nothing |
kubectl run nginx --image=nginx --dry-run=client -o yaml > pod.yaml | Same idea, saved to a file |
kubectl create service clusterip my-svc --tcp=80:8080 --dry-run=client -o yaml | Generates a Service definition |
kubectl expose deployment nginx --port=80 --dry-run=client -o yaml | Generates a Service from an existing Deployment's labels |
🔄 Rollouts and Rollback
Deployments keep a revision history. This is how you use it.
| Command | What 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=3 | Rolls 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 |
🔗 Port Forward
Talk to something inside the cluster without exposing it.
| Command | What It Does |
|---|---|
kubectl port-forward pod/<name> 8080:80 | Local port 8080 to that Pod's port 80 |
kubectl port-forward svc/<name> 8080:80 | Same, but through a Service, so it survives the Pod restarting |
kubectl port-forward deployment/<name> 8080:80 | Picks one Pod from the Deployment automatically |
📦 Namespaces and Cleanup
| Command | What 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=Failed | Cleans up only failed Pods |
kubectl delete pods --all -n <namespace> | Deletes every Pod in a namespace, Deployments will recreate theirs |
🔎 JSONPath and Custom Columns
For when -o wide isn't the column you need.
| Command | What 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.phase | A 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 |
🔐 Permissions: auth can-i
Before assuming an error is a bug, check whether it's RBAC.
| Command | What It Does |
|---|---|
kubectl auth can-i create pods | Can you, right now, create Pods in this namespace |
kubectl auth can-i list secrets -n kube-system | Checks a specific namespace |
kubectl auth can-i create pods --as=system:serviceaccount:default:my-sa | Checks what a ServiceAccount can do, not you |
kubectl auth can-i '*' '*' | Are you effectively cluster-admin |
⚠️ Five Traps
| Trap | What Actually Happens |
|---|---|
| Deleting a Pod that belongs to a Deployment | The 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 manages | The 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 image | No 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 start | get shows the status word. describe's Events section shows the reason. Always check both. |
| Assuming a context switch also switches namespace | It 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
Use Helm as a package manager - add a repo, install a sample app chart, override values, upgrade, roll back, and uninstall.