kubectl Essentials
Summary
kubectlis the primary CLI for the Kubernetes API server, and a handful of verbs cover the vast majority of daily work.- Insight:
getanddescribeare for reading state,logsandexecare for debugging, andapply/deleteare for changing desired state. - Key Concepts: contexts and namespaces, output formats (
-o wide/yaml/json/jsonpath), label selectors, and resource shortnames. - When to Use: every interaction with a cluster, from inspection to deploys, though production changes should go through
applyand GitOps. - Limitations: kubectl talks to one cluster/context at a time and will happily mutate prod if your context is wrong.
- Master these six verbs before reaching for dashboards or wrappers.
Recipe
Point at the right cluster and namespace, then use the core verbs.
kubectl config get-contexts
kubectl config use-context staging
kubectl config set-context --current --namespace=web- Read state with
getanddescribe. - Debug with
logsandexec. - Change desired state with
applyanddelete.
Always confirm your context before any change. Most incidents start with a command run against the wrong cluster.
Working Example
A realistic end-to-end loop: apply a manifest, inspect it, debug it, then clean up.
# Change desired state
kubectl apply -f web.yaml
# Read: list and widen output
kubectl get deploy,pods -l app=web -o wide
# Read: full detail + events for one Pod
kubectl describe pod -l app=web
# Debug: stream logs from the Deployment's Pods
kubectl logs deploy/web -f --tail=100
# Debug: get a shell inside a running container
kubectl exec -it deploy/web -- sh
# Watch a rollout finish
kubectl rollout status deploy/web
# Clean up by the same file
kubectl delete -f web.yamlNotice that deploy/web and -l app=web both target Pods without you typing Pod names. Pod names are generated and change on every rollout, so select by label or controller instead.
Deep Dive
get: list and read
get lists objects and is your default read command.
kubectl get pods # current namespace
kubectl get pods -A # all namespaces
kubectl get pod web-abc -o yaml # full object as stored
kubectl get pods -o jsonpath='{.items[*].status.podIP}'Add -o wide for node and IP columns, and --watch to stream changes. Shortnames save typing: po, deploy, svc, ns, cm.
describe: human-readable state plus events
describe merges an object with its recent events, which is where scheduling failures, image pull errors, and probe failures show up.
kubectl describe pod web-abcWhen a Pod is Pending or CrashLoopBackOff, describe almost always tells you why in the Events section at the bottom.
logs: what the container printed
logs streams a container's stdout/stderr.
kubectl logs deploy/web -f # follow
kubectl logs web-abc --previous # last crashed container
kubectl logs web-abc -c sidecar # a specific container--previous is essential for crash loops because it shows the logs from the instance that just died, not the fresh one.
exec: run a command inside a container
exec runs a process in a live container, typically a shell for interactive debugging.
kubectl exec -it deploy/web -- sh
kubectl exec web-abc -- envHardened, distroless images may not have a shell. Use kubectl debug to attach an ephemeral debug container in that case.
apply and delete: change desired state
apply creates or updates objects from files and is idempotent, so re-running it is safe.
kubectl apply -f ./manifests/ # a whole directory
kubectl diff -f web.yaml # preview the change first
kubectl delete -f web.yaml # remove exactly what you appliedkubectl diff shows what apply would change before you commit to it, which is a good habit for anything touching a shared cluster.
Gotchas
Wrong-context changes are the classic outage. Show your context in your shell prompt (kube-ps1) or run kubectl config current-context before writing.
Forgetting -n/--namespace makes objects "disappear" - you are looking at the wrong namespace. Set a default namespace per context.
kubectl delete pod on a Deployment-managed Pod does not remove the workload; the controller recreates it. Delete the Deployment or scale to zero instead.
--force --grace-period=0 can leave StatefulSet or storage state inconsistent. Avoid it unless you understand the consequences.
kubectl edit changes the live object and drifts from your files. Prefer editing the manifest and running apply.
Streaming logs -f on a busy Deployment interleaves Pods confusingly. Target one Pod, or use a log aggregator for real analysis.
Alternatives
k9s is a terminal UI over the same API, great for fast navigation and live views without typing every command. Use it for interactive exploration.
GitOps (Argo CD / Flux) replaces manual apply in production. You commit manifests and a controller applies them, giving you audit and rollback. Use kubectl for reads and debugging, GitOps for changes.
Helm wraps templated manifests behind helm install/upgrade for packaged apps. It still applies through the API server underneath.
Cloud consoles (EKS/GKE/AKS dashboards) are handy for a visual overview but are read-mostly and provider-specific; kubectl is portable across all of them.
FAQs
How do I target a Pod without its generated name?
Use a label selector (-l app=web) or a controller reference (deploy/web). Names change every rollout.
Why are my objects missing from get?
You are likely in a different namespace. Add -n <ns> or -A for all namespaces.
How do I see logs from a crashed container?
kubectl logs <pod> --previous shows the previous instance's output, which is what you need for CrashLoopBackOff.
How can I preview a change before applying?
kubectl diff -f file.yaml shows the server-side diff without applying it.
My image has no shell, how do I debug it?
Use kubectl debug to attach an ephemeral container with your tools into the Pod's namespace.
How do I extract a single field for scripting?
Use -o jsonpath='{...}' or -o custom-columns to pull exactly the fields you need.
Related
- Kubernetes Basics
- Declarative vs Imperative
- Labels & Selectors
- API Objects & Reconciliation
- Kubernetes Fundamentals Best Practices
Stack versions: This page was written for Kubernetes 1.36.2, Docker Engine 29.6.1 (BuildKit default), containerd (CRI runtime on nodes), Helm 3, Compose v2, Argo CD (latest - verify at build), and Gateway API (GA - verify controller support at build).