# kubectl Cheat Sheet 2026: 60 Commands Grouped by Task

URL: https://www.devopsness.com/blog/kubectl-cheatsheet
Author: Kiril Urbonas
Published: 2026-10-31
Updated: 2026-10-31
Categories: DevOps
Tags: Kubectl, Kubernetes, DevOps, Containers, Operations

Summary: The kubectl commands we actually type, grouped by the job in front of you, from switching contexts to rolling back a bad deploy. Copy-paste blocks, real output fields, and the errors that mean you are pointed at the wrong cluster.

---
# kubectl Cheat Sheet 2026: 60 Commands Grouped by Task

You need about sixty kubectl commands for daily Kubernetes work, and they cluster into twelve jobs: context, reading state, logs and exec, debugging, rollouts, scaling, apply and diff, permissions, port-forward, metrics, output shaping and cleanup. The single habit that prevents the most damage is `kubectl config set-context --current --namespace=<ns>`, so every command lands where you think it does.

> [!VERIFIED]
> Kubernetes 1.37, kubectl 1.37, against the kubernetes.io kubectl Quick Reference, the JSONPath support page, and the generated `kubectl auth can-i` and `kubectl wait` references. Checked October 2026.

This page is the whole-job reference. When a specific Pod is misbehaving, our ordered [kubectl debugging commands](/blog/kubectl-debugging-commands) walk through the investigation step by step; this sheet is what you keep open in the other tab.

## Context and namespace: check this before anything else

Most kubectl incidents are not bad commands. They are good commands run against production. Confirm where you are, then pin a namespace to the context.

```
$ kubectl config get-contexts                        # every context, current one starred
$ kubectl config current-context                     # just the name
$ kubectl config use-context staging-eu              # switch clusters
$ kubectl config set-context --current --namespace=payments   # default namespace for this context
$ kubectl config view --minify                       # only the active context's config
$ kubectl auth whoami                                # which identity the API server sees
```

Put the current context in your shell prompt.

## Reading state: get, describe, explain

```
$ kubectl get pods -o wide                           # node and Pod IP columns
$ kubectl get pods -A                                # all namespaces
$ kubectl get pods -l app=checkout -w                # label selector, then watch
$ kubectl get pods --sort-by='.status.containerStatuses[0].restartCount'
$ kubectl get pods --field-selector=status.phase!=Running
$ kubectl get deploy,svc,ingress                     # several kinds at once
$ kubectl describe pod checkout-7d9f8-abcde          # Events block at the bottom
$ kubectl get events --sort-by=.metadata.creationTimestamp
$ kubectl events --types=Warning                     # warnings only
$ kubectl explain deployment.spec.strategy           # field docs from the API server
$ kubectl api-resources                              # every kind, short name and API group
```

`describe` is where the scheduler and kubelet leave their notes. If you only remember one read command, remember that the answer to "why" usually sits in its Events block.

## Logs and exec

```
$ kubectl logs -f checkout-7d9f8-abcde               # stream
$ kubectl logs checkout-7d9f8-abcde --previous       # the container that just died
$ kubectl logs checkout-7d9f8-abcde -c envoy         # one container in a multi-container Pod
$ kubectl logs -f -l app=checkout --all-containers   # every Pod matching a label
$ kubectl exec -it checkout-7d9f8-abcde -- /bin/sh   # interactive shell
$ kubectl exec deploy/checkout -- env                # first Pod of a Deployment
$ kubectl cp checkout-7d9f8-abcde:/tmp/heap.out ./heap.out
```

`--previous` is the flag people forget during a crash loop. The current container may not have logged anything yet; the one before it has the stack trace.

## Debugging Pods and nodes

```
$ kubectl debug checkout-7d9f8-abcde -it --image=busybox:1.28 --target=app   # ephemeral container
$ kubectl debug node/worker-3 -it --image=busybox:1.28                       # shell on a node
```

Both commands come straight from the Quick Reference. For the decision tree that tells you which one to reach for, use the debugging post linked above or the broader [Kubernetes error troubleshooting guide](/blog/kubernetes-error-troubleshooting-guide).

## Rollouts and scaling

```
$ kubectl rollout status -w deployment/checkout      # block until done or failed
$ kubectl rollout history deployment/checkout        # revisions
$ kubectl rollout undo deployment/checkout           # back one revision
$ kubectl rollout undo deployment/checkout --to-revision=4
$ kubectl rollout restart deployment/checkout        # new Pods, same spec
$ kubectl rollout pause deployment/checkout          # batch several edits
$ kubectl rollout resume deployment/checkout
$ kubectl set image deployment/checkout app=registry.example.com/checkout:2.14.1
$ kubectl scale --replicas=6 deployment/checkout
$ kubectl scale --current-replicas=6 --replicas=8 deployment/checkout   # only if it is 6 now
$ kubectl wait --for=condition=Ready pod -l app=checkout --timeout=120s
```

`kubectl wait` gives up after 30 seconds by default, per its reference page, which is shorter than most image pulls. Always pass `--timeout` in CI.

## Apply, diff and safe changes

```
$ kubectl diff -f ./k8s/                             # what would change, before it changes
$ kubectl apply -f ./k8s/                            # every manifest in the directory
$ kubectl apply -f ./k8s/ --dry-run=server           # full admission, nothing persisted
$ kubectl label pods checkout-7d9f8-abcde quarantine=true
$ kubectl annotate deployment/checkout team=payments
```

We run `kubectl diff` before every manual `apply`. It compares the live object with what the cluster would hold after the change, so drift someone introduced by hand shows up before you overwrite it.

## Permissions, access and metrics

```
$ kubectl auth can-i create deployments -n payments
$ kubectl auth can-i --list --namespace=payments
$ kubectl auth can-i list pods --as=system:serviceaccount:ci:deployer -n payments
$ kubectl auth can-i get pods --subresource=log
$ kubectl port-forward svc/checkout 8080:80          # local 8080 to the Service
$ kubectl port-forward deploy/checkout 9090:9090     # a Pod picked from the Deployment
$ kubectl top node
$ kubectl top pod --containers --sort-by=memory
```

`--as` needs impersonation rights, and it is the fastest way to answer "why does the pipeline get Forbidden" without asking anyone for their token.

## Output shaping: jsonpath and custom-columns

```
$ kubectl get pods -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.phase}{"\n"}{end}'
$ kubectl get pods -o custom-columns='NAME:.metadata.name,IMAGE:.spec.containers[*].image'
$ kubectl get nodes -o custom-columns='NODE:.metadata.name,READY:.status.conditions[?(@.type=="Ready")].status'
$ kubectl get secret db-creds -o jsonpath='{.data.password}' | base64 -d
$ kubectl get pods -o json | jq -r '.items[] | select(.metadata.name | test("checkout-")).metadata.name'
```

kubectl's JSONPath does not support regular expressions; the docs say to pipe JSON into `jq` instead, which is the last line above.

## Cleanup and node maintenance

```
$ kubectl delete pods,services -l app=old-checkout
$ kubectl delete pods --field-selector=status.phase=Failed -n payments
$ kubectl cordon worker-3                            # stop new scheduling
$ kubectl drain worker-3 --ignore-daemonsets         # evict, respecting PDBs
$ kubectl uncordon worker-3
```

Add `--dry-run=client -o name` to any delete first. It prints what the selector matches, and a selector that matches more than you expected is how namespaces get emptied.

## The errors that mean you are pointed at the wrong thing

| Error string | What it usually means | First check |
|---|---|---|
| `The connection to the server localhost:8080 was refused - did you specify the right host or port?` | No kubeconfig loaded | `echo $KUBECONFIG`, `kubectl config view` |
| `error: You must be logged in to the server (Unauthorized)` | Expired token or cloud credentials | Re-run your provider's login |
| `Error from server (Forbidden): pods is forbidden: User "..." cannot list resource "pods"` | RBAC, or the wrong namespace | `kubectl auth can-i list pods -n <ns>` |
| `error: Metrics API not available` | metrics-server not installed or not ready | `kubectl get apiservices \| grep metrics` |
| `exec: "tar": executable file not found in $PATH` | `kubectl cp` needs `tar` in the image | Use `kubectl debug` or `exec ... cat` |

## Where this breaks

This sheet assumes kubectl within one minor version of your cluster and RBAC that lets you read most things. Managed platforms add their own wrappers (`oc`, cloud CLIs for auth), and locked-down clusters will reject `debug node/` and `--as` outright. On GitOps-managed namespaces, `scale`, `set image` and `annotate` are temporary: the controller reverts them on its next sync, so change Git instead.

## Questions people ask

### How do I switch namespace in kubectl permanently?

Run `kubectl config set-context --current --namespace=<name>`. It writes the namespace into your current context in kubeconfig, so every later command without `-n` uses it until you change it again. It is per context, so switching clusters with `kubectl config use-context` brings back whatever namespace that context had. Tools like kubens wrap the same call.

### How do I see logs from a pod that crashed?

Use `kubectl logs <pod> --previous`, adding `-c <container>` for multi-container Pods. The flag returns output from the previous instance of the container, which is the one that crashed, while plain `kubectl logs` shows the fresh instance that may not have logged anything yet. Pair it with `kubectl describe pod` to see the exit code and reason.

### What is the difference between kubectl apply and kubectl create?

`kubectl create` makes a resource and fails if it already exists. `kubectl apply` is declarative: it creates the resource when missing and patches it toward your manifest when present, recording what you last applied so later removals are detected. Use `apply` for anything you keep in Git, and run `kubectl diff` first so you see the change before it lands.

## The call we'd make

Memorize the context block and the rollout block; look up the rest here. Pin a namespace per context, show the context in your prompt, and run `kubectl diff` before any manual `apply`. If you find yourself running `scale` or `set image` in production more than once a month, that change belongs in Git and a pipeline, not in your shell history.

## Sources

- [Kubernetes docs: kubectl Quick Reference](https://kubernetes.io/docs/reference/kubectl/quick-reference/)
- [Kubernetes docs: JSONPath support](https://kubernetes.io/docs/reference/kubectl/jsonpath/)
- [Kubernetes docs: kubectl auth can-i](https://kubernetes.io/docs/reference/kubectl/generated/kubectl_auth/kubectl_auth_can-i/)
- [Kubernetes docs: kubectl wait](https://kubernetes.io/docs/reference/kubectl/generated/kubectl_wait/)

