kubectl command reference, core objects, and troubleshooting workflow for Kubernetes.
| Object | What it is | Notes |
|---|---|---|
| Pod | One or more containers sharing a network namespace and storage. | The smallest deployable unit. Never create one directly outside of debugging — it won't be rescheduled if the node dies. |
| ReplicaSet | Keeps N identical Pods running. | You rarely touch these directly; Deployments create and manage them for you. |
| Deployment | Manages ReplicaSets to give you rolling updates and rollback. | The default choice for any stateless workload. |
| StatefulSet | Pods with stable names, stable storage, and ordered startup. | For databases and anything with identity. Pods get -0, -1 suffixes that survive rescheduling. |
| DaemonSet | One Pod per node, automatically. | Log shippers, monitoring agents, CNI plugins. |
| Job / CronJob | Run to completion, once or on a schedule. | Set backoffLimit and history limits, or failed Jobs accumulate indefinitely. |
| Service | A stable virtual IP and DNS name load-balancing to matching Pods. | Selects Pods by label, not by owner. A typo in the selector yields a Service with no endpoints and no error. |
| Ingress | HTTP routing into the cluster, by host and path. | Inert without an ingress controller installed. Increasingly superseded by the Gateway API. |
| ConfigMap | Non-secret configuration as key/value pairs or files. | Changes don't restart Pods automatically — see the Gotchas tab. |
| Secret | Same shape as a ConfigMap, for sensitive values. | Base64 is encoding, not encryption. Enable encryption at rest and RBAC, or use an external secrets store. |
| Namespace | A scope for names, quotas, and policy. | Not a security boundary on its own — pair with NetworkPolicy and RBAC. |
| PV / PVC | A piece of storage, and a claim on it. | Most PVCs are filled dynamically by a StorageClass. Check the reclaim policy before deleting. |
- Services, Deployments, and NetworkPolicies all find Pods by label selector. Labels are the only thing connecting them.
- A Service whose selector matches nothing returns no error — it just has zero endpoints.
kubectl get endpoints <svc>is the check. - Use the standard keys:
app.kubernetes.io/name,/instance,/component,/part-of. - A Deployment's
selector.matchLabelsis immutable. Changing it means deleting and recreating the Deployment. - Annotations are for metadata and tooling; labels are for selection. Don't put large values in labels — they're indexed.
| Group | Command | Does |
|---|---|---|
| Context | kubectl config get-contexts | List every cluster you can reach. |
| Context | kubectl config use-context NAME | Switch clusters. Check this before every destructive command. |
| Context | kubectl config set-context --current --namespace=NS | Stop typing -n on every command. |
| Inspect | kubectl get pods -o wide | Adds node and IP columns — usually what you actually wanted. |
| Inspect | kubectl get all -n NS | Common objects in a namespace. Note it omits ConfigMaps, Secrets, and Ingresses. |
| Inspect | kubectl describe pod NAME | Full state plus the Events list at the bottom — the first place to look when something won't start. |
| Inspect | kubectl get events --sort-by=.lastTimestamp | Cluster-wide events in time order. Unsorted output is near-useless. |
| Inspect | kubectl get po -o yaml | The full object as stored, including defaults the API server filled in. |
| Inspect | kubectl explain deployment.spec.strategy | Built-in schema docs for any field path. Faster than the website. |
| Logs | kubectl logs -f POD -c CONTAINER | Follow logs from a specific container in a multi-container Pod. |
| Logs | kubectl logs POD --previous | Logs from the crashed instance. Essential for CrashLoopBackOff. |
| Logs | kubectl logs -l app=api --tail=100 | Aggregate logs across every Pod matching a label. |
| Exec | kubectl exec -it POD -- sh | Shell into a container. Use sh — many images have no bash. |
| Exec | kubectl debug POD -it --image=busybox --target=NAME | Attach an ephemeral debug container to a running Pod — works on distroless images with no shell. |
| Exec | kubectl port-forward svc/NAME 8080:80 | Tunnel a Service to localhost without exposing it. |
| Exec | kubectl cp POD:/path ./local | Copy files out of a container. Requires tar in the image. |
| Deploy | kubectl apply -f dir/ --dry-run=server | Validate against the real API, including admission webhooks, without applying. |
| Deploy | kubectl diff -f manifest.yaml | Shows exactly what would change. Run this before every apply. |
| Deploy | kubectl rollout status deploy/NAME | Blocks until the rollout finishes or fails — the right CI gate. |
| Deploy | kubectl rollout undo deploy/NAME | Roll back to the previous ReplicaSet. Add --to-revision=N to pick one. |
| Deploy | kubectl rollout restart deploy/NAME | Rolling restart with no manifest change — how you pick up a changed ConfigMap or Secret. |
| Scale | kubectl scale deploy/NAME --replicas=3 | Immediate scale. Reverted on next apply if your manifest says otherwise. |
| Nodes | kubectl top nodes / kubectl top pods | Live CPU and memory. Needs metrics-server installed. |
| Nodes | kubectl drain NODE --ignore-daemonsets | Evict Pods before maintenance. Respects PodDisruptionBudgets. |
| Nodes | kubectl cordon NODE / uncordon | Stop or resume new scheduling on a node. |
| RBAC | kubectl auth can-i create pods -n NS | Test your own permissions. Add --as=user to test someone else's. |
- Requests are what the scheduler reserves. Limits are the hard ceiling.
- Always set a memory limit. Exceeding it means the container is OOMKilled instantly — no grace, no signal.
- Consider omitting CPU limits. CPU is compressible: hitting the limit throttles rather than kills, and aggressive limits cause latency that looks like an application bug. Setting requests without limits is a defensible, common choice.
- Requests equal to limits gives a Pod Guaranteed QoS — evicted last under node pressure.
- No requests at all gives BestEffort — evicted first. Fine for batch, wrong for anything serving traffic.
- readiness — should traffic reach this Pod? Failing removes it from the Service, no restart.
- liveness — is this container wedged? Failing restarts it. Too aggressive and you get restart loops under load.
- startup — for slow starters. Suspends the other two until it passes; better than a huge
initialDelaySeconds. - Don't point liveness at a check that touches the database. A slow dependency then restarts every Pod at once.
- No readiness probe means traffic hits the Pod the instant the container starts, before it can serve.
| Pod status | Means | Check |
|---|---|---|
| Pending | Not scheduled to a node. | describe events — usually insufficient CPU/memory, an unsatisfiable nodeSelector, or an unbound PVC. |
| ImagePullBackOff | Can't fetch the image. | Typo in the tag, private registry with no imagePullSecrets, or wrong architecture. |
| CrashLoopBackOff | Container starts then exits repeatedly. | kubectl logs POD --previous. Usually a config error, a missing env var, or a failing liveness probe. |
| OOMKilled | Exceeded its memory limit. | Raise the limit or fix the leak. Exit code 137. Visible in describe under Last State. |
| CreateContainerConfigError | A referenced ConfigMap or Secret doesn't exist. | Check the name and the namespace — they must be in the same namespace as the Pod. |
| Init:0/1 | Stuck in an init container. | kubectl logs POD -c INIT_NAME. Often waiting on a dependency that never arrives. |
| Terminating (stuck) | Won't finish deleting. | Usually a finalizer. Inspect metadata.finalizers — force-deleting a StatefulSet Pod risks split-brain. |
| Running but not Ready | Readiness probe failing. | The container is up but the app isn't serving. Check the probe path and port. |
Does the Service have endpoints?
Empty means the selector matches no ready Pods. That is the answer 80% of the time — either the labels don't match, or the Pods aren't passing readiness.
Compare the selector against actual Pod labels
Check the ports
targetPort must match the container's actual listening port, not the Service's port. Mixing these up is extremely common.
Test from inside the cluster
This separates a DNS problem from a routing problem from an application problem.
Check for a NetworkPolicy
If any NetworkPolicy selects the Pod, traffic is default-deny except what's explicitly allowed. A policy added elsewhere can silently break your Service.
Gotchas
- Updating a ConfigMap does not restart Pods. Values mounted as env vars keep the old value until the Pod restarts.
- Volume-mounted ConfigMaps do update in place, but only after a sync delay — and only if the app re-reads the file.
- Fix:
kubectl rollout restart deploy/NAME, or hash the config into a Pod annotation so a change triggers a rollout automatically.
- Base64 is encoding, not encryption. Anyone with read access to Secrets in the namespace has the plaintext.
- Enable encryption at rest on etcd — it is not on by default in every distribution.
- Lock down RBAC:
get secretsis effectively credential access. - For anything serious use External Secrets Operator, Vault, or your cloud's secret manager.
- Never commit a Secret manifest to git. Use Sealed Secrets or SOPS if it must live in a repo.
:latestis a trap. WithimagePullPolicy: Alwaysyour Pods drift between nodes; without it, they never update. Pin a digest or an immutable tag.kubectl delete podon a managed Pod does nothing lasting — the controller recreates it. Scale the Deployment instead.- No PodDisruptionBudget means a node drain can take your whole service down at once.
- Namespaces don't isolate network traffic. Any Pod can reach any other Pod unless a NetworkPolicy says otherwise, and many CNI plugins ignore them entirely.
kubectl applyon a resource created withcreatecan conflict over ownership. Stay consistent.- An unset
terminationGracePeriodSecondsdefaults to 30s — long-draining apps get SIGKILLed mid-request. - StatefulSet PVCs are not deleted when the StatefulSet is. That's deliberate, and it surprises people at bill time.
Tips
kubectl diff before every applyShows precisely what would change against the live cluster. The single cheapest habit for avoiding accidental production changes.
alias k=kubectl plus source <(kubectl completion bash) and complete -o default -F __start_kubectl k. Add kubectx/kubens for fast context and namespace switching.
kubectl explainSchema docs for any field path, straight from your cluster's actual API version — so it's never out of date the way a web page can be. Add --recursive for the whole tree.
kubectl run tmp --rm -it --image=nicolaka/netshoot -- bash gives you dig, curl, tcpdump, and iproute2 inside the cluster network.
--dry-run=serverValidates against the real API including admission webhooks and defaulting, catching things client-side validation misses entirely.
kubectl create deploy api --image=x --dry-run=client -o yaml scaffolds valid YAML you then edit — much faster than remembering the nesting.
Resources
kubectl debug.
kubernetes.io
kubectx & kubens
Fast context and namespace switching. The first thing to install on a new machine.
github.com
netshoot
A container image packed with network debugging tools, built for exactly this.
github.com
Kustomize
Environment overlays without templating. Built into kubectl as -k.
github.com
Docker
The images Kubernetes runs — build them well and half these problems disappear.
build.ty1er.com
Terraform
How the cluster itself usually gets provisioned.
build.ty1er.com