Core Resources
.mdVerified against kubectl v1.34.0 (client), flags verified via `kubectl <cmd> --help`, 2026-08-21 · official docs
Getting, describing, creating, and deleting the resources you touch every day — pods, deployments, services — plus applying manifests.
Listing resources#
kubectl get pods
kubectl get pods -o wide # + node, IP, and readiness columns
kubectl get pods -n my-namespace
kubectl get pods --all-namespaces
kubectl get deployments,services # multiple resource types in one call
kubectl get pods -l app=nginx # filter by label selector
kubectl get pods -w # watch for changes liveInspecting a resource in detail#
kubectl describe pod my-pod
kubectl describe deployment my-deployment
kubectl get pod my-pod -o yaml # full resource manifest as YAML
kubectl get pod my-pod -o json # full resource manifest as JSONdescribe includes recent Events for the resource — often the fastest way to see why a pod is stuck (ImagePullBackOff, failed readiness probe, insufficient node resources) without a separate get events call.
Applying and creating resources#
kubectl apply -f deployment.yaml # create or update to match the file (idempotent)
kubectl apply -f ./manifests/ # apply every manifest in a directory
kubectl create -f pod.yaml # create only — fails if it already exists
kubectl create deployment my-app --image=nginx:1.27apply is the standard for anything you'll re-run (it diffs against the last-applied state and only changes what differs); create is a one-shot, fails on a resource that already exists. Prefer apply for anything under version control.
Deleting resources#
kubectl delete pod my-pod
kubectl delete -f deployment.yaml
kubectl delete pods -l app=nginx # delete everything matching a label
kubectl delete pod my-pod --grace-period=0 --force # skip graceful termination (last resort)Logs and exec#
kubectl logs my-pod
kubectl logs my-pod -c my-container # a specific container in a multi-container pod
kubectl logs my-pod -f # stream/follow
kubectl logs deployment/my-deployment --all-pods=true
kubectl exec my-pod -- date # run a one-off command
kubectl exec -it my-pod -- /bin/bash # interactive shell-it (interactive + tty) is what makes exec behave like a real shell session instead of a single non-interactive command — forgetting it against a shell command leaves you unable to type.
Editing and scaling#
kubectl edit deployment my-deployment # opens the live resource in $EDITOR
kubectl scale deployment my-deployment --replicas=5
kubectl set image deployment/my-deployment my-container=myrepo/app:v2 # roll a new image without editing YAMLAutoscaling a workload (HPA)#
kubectl autoscale deployment my-deployment --min=2 --max=10 --cpu-percent=70
kubectl get hpa # list HorizontalPodAutoscalers and their current/target metrics
kubectl describe hpa my-deployment
kubectl delete hpa my-deploymentkubectl autoscale tries the autoscaling/v2 API first (CPU + memory + custom metrics) and falls back to v1 (CPU only) if the cluster doesn't support it — --cpu-percent alone always works, memory-based targets need v2. autoscale also works against a ReplicaSet or ReplicationController, not just a Deployment.
StatefulSets, DaemonSets, Jobs, and CronJobs#
kubectl get statefulsets
kubectl get daemonsets
kubectl scale statefulset my-db --replicas=3 # StatefulSets scale like Deployments...
kubectl rollout status statefulset/my-db # ...and support the same rollout commands
kubectl rollout restart daemonset/my-agent # roll every node's pod without a manifest change
kubectl create job my-job --image=busybox -- date # one-off Job
kubectl create job my-job-from-cj --from=cronjob/my-cronjob # run a CronJob's Job definition immediately, on demand
kubectl create cronjob my-cronjob --image=busybox --schedule="*/5 * * * *" -- date
kubectl get cronjobs
kubectl get jobs --field-selector status.successful=1 # completed Jobs onlyThere's no kubectl create statefulset/kubectl create daemonset shortcut the way there is for deployment/job/cronjob — StatefulSets and DaemonSets are manifest-only resources, created with kubectl apply -f (they need a volumeClaimTemplates/spec.selector shape that doesn't map cleanly onto CLI flags). Once created, though, get/describe/scale/rollout all work on them exactly like Deployments since they're all generic resource kinds.
Kustomize overlays#
kubectl apply -k ./overlays/production/ # build and apply a kustomization directory
kubectl kustomize ./overlays/production/ # render the final manifest to stdout without applying
kubectl diff -k ./overlays/production/ # preview what apply -k would changeapply -k is for a kustomization.yaml-based directory (patches/overlays layered on a base) — it can't be combined with -f or -R in the same call. kubectl kustomize (no apply) is the equivalent of a dry-run render, useful for reviewing the generated manifest in a PR before it ever touches the cluster.
Diffing before you apply#
kubectl diff -f deployment.yaml # unified diff between the live object and what apply would produce
kubectl diff -f ./manifests/kubectl diff shells out to the system diff (or KUBECTL_EXTERNAL_DIFF if set, e.g. colordiff) and exits 1 if there are differences, 0 if none — script it into a CI gate the same way you'd use terraform plan's exit code.
Labels and annotations#
kubectl label pods my-pod tier=frontend # add a label
kubectl label pods my-pod tier=backend --overwrite # change an existing label (fails without --overwrite)
kubectl label pods my-pod tier- # remove a label (trailing "-")
kubectl label pods -l app=nginx --all env=prod # label everything matching a selector
kubectl annotate pods my-pod description="handles checkout" # annotations can hold longer/structured values
kubectl annotate pods my-pod description- # remove an annotation (no --overwrite needed)Labels are for selection (used by selectors on Services, Deployments, -l filters) and are capped at 63 characters; annotations are for arbitrary metadata (build SHAs, owner contacts, tool-specific config) that nothing selects on. Reach for a label only if something will actually query on it.