Containers & orchestration 34 entries 27 run in the sandbox

kubectl cheat sheet

Inspect, debug, roll out and roll back workloads on a cluster. Each entry has a worked example and the flags worth knowing, and where one is easy to get wrong, the gotcha.

Context & access

kubectl config get-contexts

List the clusters and users in your kubeconfig and mark the one you are pointed at.

CURRENT   NAME         CLUSTER      AUTHINFO     NAMESPACE
*         staging      staging      alice        shop
          production   production   alice-prod   shop
use-context NAME
Switch the default context.
current-context
Print only the active context.
--context NAME
Per-command override; safer than switching globally.

Gotcha Most 'I deleted it in prod' stories start with the wrong current context. Put the context in your shell prompt.

kubectl -n <namespace> ...

Target a namespace for one command, or set a default namespace for the current context.

kubectl config set-context --current --namespace=shop
-n NS
Namespace for this command.
-A
All namespaces (read commands).
get ns
List namespaces.

kubectl auth can-i <verb> <resource>

Check RBAC before you try, or verify what a service account may do.

kubectl auth can-i delete pods -n shop --as system:serviceaccount:shop:deployer
no
--as USER
Impersonate a user or service account.
--list
Everything the subject may do in the namespace.

Inspect workloads

kubectl get pods

List pods with readiness, status, restarts and age. Add -o wide for the pod IP and the node it runs on.

NAME                   READY   STATUS             RESTARTS      AGE
api-7d9c6b5f4d-2xkqp   0/1     CrashLoopBackOff   6 (41s ago)   9m
api-7d9c6b5f4d-9mzt4   1/1     Running            0             9m
-o wide
Add IP, node and nominated node.
-l app=api
Filter by label selector.
-w
Watch for changes.
--show-labels
Print every label.

Gotcha READY 0/1 with STATUS Running means the readiness probe fails: the pod runs but gets no traffic.

kubectl get pods -A --field-selector=status.phase!=Running

Find every pod across the cluster that is not in the Running phase.

--field-selector
Server-side filter on fields such as status.phase or spec.nodeName.
-A
All namespaces.

Gotcha CrashLoopBackOff pods are usually in phase Running between restarts, so this filter misses them. Also sort by restarts.

kubectl describe pod <pod>

Human-readable detail plus recent events: scheduling, image pulls, probe failures, OOM kills.

kubectl describe pod -l app=worker
Last State:     Terminated
      Reason:       Error
      Exit Code:    1
    Restart Count:  13
Events:
  Warning  BackOff  4m15s (x13 over 44m)  kubelet  Back-off restarting failed container worker
Last State
Why the previous container instance died.
Events
The last hour of what the scheduler and kubelet did.
describe node NAME
Allocated requests, pressure conditions and taints.

kubectl get events --sort-by=.lastTimestamp

Namespace events in time order: the cluster's own incident timeline.

kubectl get events -n shop --sort-by=.lastTimestamp
--sort-by
Events are unsorted by default.
--field-selector type=Warning
Only warnings.
-w
Stream new events.

Gotcha Events expire after about an hour by default. Capture them early in an incident.

kubectl logs <pod>

Read a container's stdout and stderr.

kubectl logs deploy/worker --previous
--previous / -p
Logs of the crashed previous instance: where the real error is.
-c NAME
Pick a container in a multi-container pod.
-f --since=10m
Follow recent output.
-l app=api --prefix
Logs from every pod matching a label.
deploy/api
Logs from one pod of a deployment.

Gotcha In a crash loop the current container is brand new and its log is nearly empty. Use --previous.

kubectl top pod

Current CPU and memory use per pod or node, from metrics-server.

kubectl top pod -n shop --sort-by=memory
top node
Per-node usage.
--containers
Break down by container.
--sort-by=cpu|memory
Sort the output.

kubectl get <kind> <name> -o yaml

The live object as the API server stores it, including status and defaults you never wrote.

kubectl get deploy api -o yaml
-o yaml / json
Full object.
-o jsonpath='{...}'
Extract one field.
-o custom-columns=
Build your own table.

kubectl get ... -o jsonpath='<expr>'

Pull exact values out of objects for scripts and quick answers.

kubectl get pods -l app=api -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.containerStatuses[0].restartCount}{"\n"}{end}'
{.a.b}
Field path.
{range .items[*]}...{end}
Loop over a list.
[?(@.type=="Ready")]
Filter array elements.

kubectl explain <kind>.<field>

Built-in API documentation for any field, matching your cluster's version.

kubectl explain deployment.spec.strategy.rollingUpdate
--recursive
Show every nested field name.

Debug

What the pod status means

Map a STATUS column value to where to look next.

kubectl get pods, then kubectl describe pod <name> and read Events and Last State.

Pending
Not scheduled: insufficient CPU or memory requests, taints, node selectors, or an unbound PVC.
ImagePullBackOff
Wrong image name or tag, a private registry without imagePullSecrets, or rate limiting.
CreateContainerConfigError
A referenced ConfigMap or Secret or key does not exist.
CrashLoopBackOff
The container starts and exits repeatedly; read logs --previous.
OOMKilled (137)
Exceeded its memory limit.
Running, READY 0/1
Readiness probe failing; check the probe path, port and timing.
Evicted
Node pressure (usually disk or memory); check describe node.

kubectl exec -it <pod> -- sh

Open a shell or run a command inside a running container.

kubectl exec deploy/api -- env
--
Everything after it is the command to run in the container.
-c NAME
Target container.
deploy/api
Exec into one pod of a deployment.

kubectl exec <pod> -- wget -qO- -T 2 <service>

Ask from inside a pod whether another pod or a Service answers: the test for a NetworkPolicy, a selector or a port.

kubectl -n shop exec frontend -- wget -qO- -T 2 api
-T 2
Give up after two seconds instead of waiting for a dropped packet.
nslookup NAME
Only the name lookup, to tell a DNS problem from a blocked port.
http://POD_IP:PORT
Past the Service, straight to one pod.

Gotcha The error says which part failed: "download timed out" is a packet a NetworkPolicy dropped, "bad address" a name that could not be looked up (often DNS closed by an egress policy), and "Connection refused" a pod that got the packet and has nothing listening on that port.

kubectl debug -it <pod> --image=<img> --target=<ctr>

Attach an ephemeral debug container to a running pod, even when its image has no shell.

kubectl debug -it api-7d9c6b5f4d-9mzt4 --image=nicolaka/netshoot --target=api
--image
Image with your tools.
--target
Share the process namespace of this container.
node/NAME
Debug a node with its filesystem at /host.

kubectl run tmp --rm -it --image=<img> -- sh

Start a throwaway pod inside the cluster to test DNS and connectivity from the pod network.

kubectl run tmp --rm -it --restart=Never --image=busybox:1.36 -- nslookup api.shop.svc.cluster.local
--rm
Delete the pod when you exit.
--restart=Never
Create a bare pod, not a deployment.

kubectl port-forward <target> <local>:<remote>

Tunnel a local port to a pod or service to test it without exposing it.

kubectl port-forward svc/api 8081:80
svc/NAME
Picks one pod behind the service.
--address 0.0.0.0
Listen on all interfaces, not just localhost.

Gotcha port-forward goes to a single pod and skips the service's load balancing, so it can hide a problem with only some replicas.

kubectl get endpoints <svc>

Which pod IPs a service currently routes to. Empty means the selector matches nothing ready.

kubectl get endpoints api
NAME   ENDPOINTS                         AGE
api    10.42.2.33:8080,10.42.3.12:8080   12d
get endpointslices
The newer API, with per-endpoint readiness.
describe svc
Shows the selector and target port to compare against pod labels.

Gotcha No endpoints? Compare the service selector with the pod labels character by character, and check targetPort against the container port.

kubectl describe resourcequota

What a namespace may use and what it has used. Look here when a Deployment has fewer pods than replicas and nothing is Pending.

kubectl -n team-a describe resourcequota
Name:         team-quota
Namespace:    team-a
Resource      Used  Hard
--------      ----  ----
pods          3     10
requests.cpu  900m  1
get events --field-selector type=Warning
The refusal itself: FailedCreate on the ReplicaSet, with requested, used and limited.
describe rs <name>
The same event, and the condition ReplicaFailure.
describe limitrange
Defaults, minimum, maximum and limit-to-request ratio per container.

Gotcha A pod a quota refuses is never created, so there is no Pending pod to describe. "must specify limits.cpu" means the quota limits a value the container does not set; "exceeded quota" means the namespace is full.

CrashLoopBackOff triage

A repeatable order of operations for a container that keeps restarting.

1. kubectl logs <pod> --previous: the error from the last run. 2. kubectl describe pod <pod>: Last State reason and exit code (137 OOMKilled, 1 app error). 3. Did the image, config or secret change? kubectl rollout history deploy/<name>. 4. Missing config? Check env vars, mounted ConfigMaps and Secrets exist with the expected keys. 5. Liveness probe too aggressive? Probe failures restart healthy but slow-starting apps; add a startupProbe. 6. Mitigate first: kubectl rollout undo deploy/<name>, then debug the bad version.

exit 137
OOMKilled or killed by a failing liveness probe.
exit 1 / 2
Application or usage error; logs show it.

Deploy, roll back & scale

kubectl apply -f <file>

Create or update resources declaratively from manifests.

kubectl apply -f k8s/
-f DIR|FILE|URL
Manifests to apply.
-k DIR
Apply a kustomization.
--server-side
Server-side apply with field ownership.
--dry-run=server
Validate against the API server without persisting.

kubectl diff -f <file>

Show what apply would change on the live cluster before you apply it.

kubectl diff -f k8s/api.yaml
exit 1
There are differences (not an error).

kubectl rollout status deploy/<name>

Wait for a rollout to finish, failing if it does not progress.

kubectl rollout status deploy/api --timeout=120s
--timeout
Give up and exit non-zero after this long.
-w=false
Print the current status without waiting.

kubectl rollout history deploy/<name>

List previous revisions of a deployment to pick one to roll back to.

kubectl rollout history deploy/api
--revision=N
Show the pod template of revision N.
kubernetes.io/change-cause
Annotation shown in the CHANGE-CAUSE column.

kubectl rollout undo deploy/<name>

Roll back to the previous revision. Usually the fastest mitigation when a deploy breaks things.

kubectl rollout undo deploy/api
--to-revision=N
Roll back to a specific revision.

Gotcha If a GitOps tool such as Argo CD or Flux manages the deployment, it will re-apply the bad version. Revert in Git or pause sync.

kubectl rollout restart deploy/<name>

Replace every pod with a rolling restart, for example to pick up a changed Secret mounted as env vars.

kubectl rollout restart deploy/api

Gotcha Environment variables from Secrets and ConfigMaps are read at container start only. Changing the Secret does nothing until pods restart.

kubectl scale deploy/<name> --replicas=<n>

Change the replica count right now.

kubectl scale deploy/api --replicas=6
--replicas=N
Desired count; 0 stops the workload.
get hpa
An autoscaler will override manual scaling.

kubectl set image deploy/<name> <ctr>=<image>

Change a container image imperatively, which starts a rollout.

kubectl set image deploy/api api=ghcr.io/acme/api:1.4.3
CONTAINER=IMAGE
The container name in the pod spec, not the deployment name.

Gotcha Imperative changes drift from Git. Make the same change in your manifests, or the next apply reverts it.

kubectl delete pod <pod>

Remove one pod; its controller creates a replacement.

kubectl delete pod -l app=worker
--grace-period=N
Seconds for graceful termination.
--wait=false
Return immediately.

Gotcha Deleting a crash-looping pod only resets the backoff timer. It does not fix anything.

kubectl drain <node> --ignore-daemonsets

Cordon a node and evict its pods, respecting PodDisruptionBudgets, before maintenance.

kubectl drain fixops-lab-m02 --ignore-daemonsets --delete-emptydir-data
cordon / uncordon
Mark unschedulable, or schedulable again.
--ignore-daemonsets
DaemonSet pods cannot be evicted; skip them.
--delete-emptydir-data
Allow evicting pods that use emptyDir (data is lost).

Config & secrets

kubectl create secret generic <name> --dry-run=client -o yaml

Generate a Secret manifest from literals or files without applying it.

kubectl create secret generic api-db --from-literal=DB_PASSWORD=changeme --dry-run=client -o yaml
--from-literal=K=V
One key from a value.
--from-file=K=path
One key from a file.
--dry-run=client -o yaml
Print the manifest instead of creating it.

Gotcha Secret data is base64-encoded, not encrypted. Anyone with get secrets can read it; enable encryption at rest and tight RBAC.

kubectl get secret <name> -o jsonpath='{.data.<key>}' | base64 -d

Decode one key of a Secret to confirm what the pod actually receives.

kubectl get secret api-db -o jsonpath='{.data.DB_PASSWORD}' | base64 -d
.data.KEY
The base64 value of one key.

Deployment with probes & resources

A production-shaped Deployment: resource requests and limits, readiness and liveness probes, config from a Secret.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: api
spec:
  replicas: 3
  selector:
    matchLabels:
      app: api
  template:
    metadata:
      labels:
        app: api
    spec:
      containers:
        - name: api
          image: ghcr.io/acme/api:1.4.2
          ports:
            - containerPort: 8080
          envFrom:
            - secretRef:
                name: api-db
          resources:
            requests:
              cpu: 250m
              memory: 256Mi
            limits:
              memory: 512Mi
          readinessProbe:
            httpGet:
              path: /ready
              port: 8080
            periodSeconds: 5
          livenessProbe:
            httpGet:
              path: /healthz
              port: 8080
            initialDelaySeconds: 15
            periodSeconds: 10
selector = template labels
They must match, and the selector is immutable after creation.
requests
What the scheduler reserves; drives placement.
limits.memory
Exceeding it gets the container OOMKilled.
readinessProbe
Failing removes the pod from Service endpoints.
livenessProbe
Failing restarts the container; keep it cheap and dependency-free.

Gotcha A liveness probe that checks the database restarts every replica when the database blips. Check dependencies in readiness, not liveness.

Your pager is ready.

Free, instant, and it works on your phone. No signup: start as a guest and save your progress later.