Docker & kubectl
Flags and subcommands you retype daily, each with the gotcha. Docker syntax was checked against Docker 29.4.1 help output; kubectl against the Kubernetes docs and source.
Starting Containers
Flags were checked against docker run --help on Docker 29.4.1. docker run IMAGE = create + start; put options before the image name, the command and its arguments after it.
| Flag | Meaning | Gotcha |
|---|---|---|
-d, --detach | Run in the background | Without it the container is tied to your terminal |
-it | -i keep stdin open, -t allocate a TTY | Needed for shells; do not use -t in scripts piping output |
--rm | Remove the container when it exits | Combine with -it for throw-away shells; it also removes anonymous volumes |
--name web | Fixed container name | Names must be unique, even for stopped containers |
-p 8080:80 | Publish host port 8080 to container port 80 | Format is host:container; 127.0.0.1:8080:80 limits it to localhost; -P publishes all EXPOSEd ports to random ports |
-e KEY=value, --env-file f | Set environment variables | Values passed with -e show in docker inspect and process lists |
-v name:/data | Mount a named volume | A path starting with / or ./ is a bind mount instead |
-v $(pwd):/app, --mount | Bind-mount a host folder; --mount is the explicit form | -v creates a missing host folder; --mount errors instead |
--network net | Attach to a user-defined network | On a user-defined network containers reach each other by name; the default bridge has no name resolution |
--restart unless-stopped | Restart policy | always also restarts after you stopped it when the daemon restarts |
-m 512m, --cpus 1.5 | Memory and CPU limits | Exceeding memory gets the process OOM-killed (exit 137) |
-u 1000:1000 | Run as a non-root user | Mounted files keep host ownership |
--read-only | Read-only root filesystem | Add --tmpfs /tmp or a volume for paths that must be written |
--entrypoint | Override the image entrypoint | The command after the image becomes the arguments |
--pull always | Pull the image before running | Default is to use a local copy if present; latest can be stale |
-w /app | Working directory | Overrides the image WORKDIR |
--platform linux/amd64 | Run an image for another architecture | Emulated on Apple silicon and slow |
--health-cmd, --health-interval | Define a health check at run time | The status shows in docker ps but nothing restarts the container by itself |
Looking Inside Containers
Day-to-day commands for running containers.
| Command | What it does | Gotcha |
|---|---|---|
docker ps -a | List containers; -a includes stopped | -q prints only ids, --filter status=exited narrows, --format templates the output |
docker logs -f --tail 100 c | Follow the last 100 log lines | --since 10m and -t (timestamps) exist; only stdout and stderr are captured |
docker exec -it c sh | Open a shell in a running container | Container must be running; use bash only if the image has it; -u root for a root shell |
docker inspect c | Full JSON for a container, image, volume or network | -f "{{.State.ExitCode}}" extracts one field |
docker stats --no-stream | One snapshot of CPU and memory per container | Without --no-stream it refreshes forever |
docker top c | Processes inside the container | Shows host PIDs |
docker cp c:/path ./dir | Copy files between container and host | Works on stopped containers too |
docker stop / kill / restart | Graceful (SIGTERM, then SIGKILL after a timeout) / immediate / both | If your process ignores SIGTERM, stop takes the full timeout; PID 1 signal handling matters (--init) |
docker rm -f c | Remove a container, stopping it first | -v also removes its anonymous volumes |
docker events | Live stream of daemon events | Useful to see OOM kills and health changes |
| Exit codes | 0 success, 137 killed (SIGKILL or OOM), 143 SIGTERM, 139 segfault | Check docker inspect -f "{{.State.OOMKilled}}" c for 137 |
Building and Shipping
docker build is the BuildKit-based builder (buildx) in current Docker.
| Command | What it does | Gotcha |
|---|---|---|
docker build -t name:tag . | Build from the Dockerfile in the current directory | The . is the build context; everything in it is sent unless .dockerignore excludes it |
-f path/Dockerfile | Use a different Dockerfile | Context is still the last argument |
--build-arg KEY=v | Pass a build-time ARG | Not for secrets: it stays in image history; use --secret |
--target stage | Stop at a named stage of a multi-stage build | Good for a test or debug stage |
--no-cache | Ignore the layer cache | Slow; use only when a cached step is stale (for example a RUN apt-get) |
--platform linux/amd64,linux/arm64 | Build for several platforms | Needs --push or a suitable builder; --load loads a single platform locally |
--push / --load | Shorthand outputs: push to registry / load into the local daemon | Pick one |
--secret id=npm,src=.npmrc | Mount a secret for one build step | Does not end up in a layer when used with RUN --mount=type=secret |
docker tag src dst | Add another name to an image | No copy happens; tags are pointers |
docker push / pull | Upload / download an image | You must docker login and the name must include the registry host |
docker images / docker image ls | List local images | <none> entries are dangling layers |
docker image history img | Show layers and their sizes | Reveals what each RUN added |
docker save -o f.tar img / docker load -i f.tar | Export / import an image as a tar file | For air-gapped moves; export and import are for containers and lose metadata |
docker image prune [-a] | Remove dangling images; -a all unused | Check what is "unused" before -a |
Storage, Networking and Compose
Compose commands are docker compose (a plugin) in current Docker, not docker-compose.
| Command | What it does | Gotcha |
|---|---|---|
docker volume ls / create / inspect / rm | Manage named volumes | Removing a volume deletes its data permanently |
docker volume prune | Remove unused local volumes | -a also removes unused named volumes; without it only anonymous ones |
docker network ls / create / inspect / connect | Manage networks | Create a user-defined network for name-based discovery |
docker system prune | Remove stopped containers, unused networks, dangling images and build cache | -a all unused images, --volumes also anonymous volumes; ask for -f only in scripts |
docker compose up -d | Create and start all services in the background | --build rebuilds images, --force-recreate recreates containers, --wait waits for healthy |
docker compose down | Stop and remove containers and networks | -v also removes named volumes, --remove-orphans removes leftover services |
docker compose logs -f svc | Follow a service log | Omit the service for all of them |
docker compose ps | List the project's containers | Shows state and health |
docker compose exec svc sh | Shell in a running service | run starts a new one-off container instead |
docker compose config | Render the merged, interpolated file | First stop when env variables or overrides misbehave |
docker compose watch | Rebuild or sync on file changes (dev loop) | Needs a develop.watch section in the compose file |
docker context ls / use | Switch between Docker daemons | Easy to run a command against the wrong host |
Reading Cluster State
Commands from the Kubernetes quick reference (kubernetes.io, main branch). -n ns picks a namespace, -A means all namespaces, -o wide|yaml|json|name changes the output.
| Command | What it does | Gotcha |
|---|---|---|
kubectl config get-contexts / current-context | List contexts / show the active one | Check before every destructive command |
kubectl config use-context name | Switch cluster | Applies to every terminal sharing the kubeconfig |
kubectl config set-context --current --namespace=ns | Set the default namespace | Forgetting this is why get pods shows nothing |
kubectl get pods -o wide | Pods with node and IP | -A all namespaces, -w watch, --show-labels, -l app=x label selector |
kubectl get pod p -o yaml | Full object definition and status | Includes server-added fields; strip them before re-applying |
kubectl describe pod p | Human summary plus recent events | Events section answers most "why Pending" questions |
kubectl get events --sort-by=.metadata.creationTimestamp | Events oldest to newest | kubectl events --types=Warning shows only warnings |
kubectl logs p [-c container] | Container log | --previous shows the crashed instance; -f follows; -l app=x by label; --tail, --since, --all-containers |
kubectl logs deploy/name | Log of one pod of a Deployment | Picks a single pod; use -l to see all |
kubectl top pod / top node | CPU and memory usage | Needs metrics-server installed; --containers, --sort-by=cpu |
kubectl explain pod.spec.containers | Built-in field documentation | Works for custom resources too |
kubectl api-resources | List resource kinds, short names and scope | --namespaced=false for cluster-wide kinds |
kubectl get -o jsonpath='{.items[*].metadata.name}' | Extract fields | Quote the expression for your shell |
kubectl get pods --field-selector=status.phase=Running | Filter by field | Only a few fields are supported |
kubectl diff -f file.yaml | Show what apply would change | Run before apply in production |
Changing the Cluster
Declarative (apply) is the default way; imperative commands are for quick fixes and debugging.
| Command | What it does | Gotcha |
|---|---|---|
kubectl apply -f file.yaml | Create or update from a manifest (also -f dir) | --server-side runs apply on the server with field ownership; --force-conflicts takes ownership on conflicts |
kubectl create deployment web --image=nginx | Quick imperative create | --dry-run=client -o yaml prints a manifest you can edit |
kubectl delete -f file.yaml | Delete what a manifest describes | kubectl delete pod p --now skips the grace period |
kubectl scale deploy/web --replicas=3 | Change replica count | A HorizontalPodAutoscaler may scale it back |
kubectl set image deploy/web c=img:v2 | Roll out a new image | Container name before the = must match |
kubectl rollout status deploy/web | Wait for a rollout to finish | Also -w, --timeout; non-zero exit on failure, good for CI |
kubectl rollout history deploy/web | List revisions | --revision=2 shows one |
kubectl rollout undo deploy/web [--to-revision=2] | Roll back | Only works for Deployments with kept history (revisionHistoryLimit) |
kubectl rollout restart deploy/web | Rolling restart | Typical way to pick up a changed ConfigMap or Secret |
kubectl edit deploy/web | Edit the live object in your editor | Changes are not in Git; apply from files instead |
kubectl patch deploy/web -p '{"spec":{"replicas":2}}' | Small change by merge patch | --type=json for precise JSON patch operations |
kubectl label / annotate | Add key=value; remove with key- | --overwrite to change an existing value |
kubectl wait --for=condition=Ready pod/p --timeout=60s | Block until a condition is met | Handy in scripts and CI |
kubectl autoscale deploy/web --min=2 --max=10 | Create a HorizontalPodAutoscaler | Needs metrics and CPU requests on the pods |
Debugging and Maintenance
Interactive access and node care.
| Command | What it does | Gotcha |
|---|---|---|
kubectl exec -it p -- sh | Shell in a pod | -c container when there are several; the -- separates kubectl flags from the command |
kubectl run tmp -it --rm --image=busybox:1.28 -- sh | Throw-away pod for testing from inside the cluster | --rm deletes it on exit |
kubectl debug p -it --image=busybox:1.28 | Add an ephemeral debug container to a pod | Works on images with no shell; kubectl debug node/n -it --image=... debugs a node |
kubectl port-forward svc/web 8080:80 | Local port to a Service or pod (also pod/p, deploy/d) | Forwards to one pod, not load-balanced; stops when the pod restarts |
kubectl cp ns/p:/tmp/f ./f | Copy files to or from a pod | Needs tar in the container |
kubectl auth can-i delete pods -n ns | Check your permissions | --list shows everything you may do; add --as user to test another identity |
kubectl cordon node | Mark a node unschedulable | Existing pods keep running |
kubectl drain node --ignore-daemonsets --delete-emptydir-data | Evict pods for maintenance | Respects PodDisruptionBudgets; the two flags are required for typical nodes; --timeout, --force, --grace-period exist |
kubectl uncordon node | Make the node schedulable again | Forgotten uncordon leaves capacity unused |
kubectl taint nodes n key=value:NoSchedule | Repel pods without a toleration | Remove with key=value:NoSchedule- |
kubectl cluster-info | Control plane and DNS addresses | cluster-info dump for a full state dump |
Pod Status Decoder
The status column is a symptom; the Events section of describe is usually the cause.
| Pod status you see | Usually means | First command |
|---|---|---|
Pending | Not scheduled: no node fits (resources, taints, affinity) or volume not bound | kubectl describe pod p then read Events |
ImagePullBackOff / ErrImagePull | Wrong image name or tag, or missing pull credentials | kubectl describe pod p |
CrashLoopBackOff | Container starts and exits repeatedly | kubectl logs p --previous |
OOMKilled (in last state) | Memory limit exceeded | kubectl describe pod p, raise the limit or fix the leak |
CreateContainerConfigError | Missing ConfigMap or Secret key | kubectl describe pod p |
Running but not Ready | Readiness probe failing | kubectl describe pod p, check probe and logs |
Terminating forever | Finalizer or stuck process | kubectl get pod p -o yaml and look at finalizers |
Docker and kubectl Mistakes
- **Running
kubectl deleteon the wrong context or namespace.** Checkkubectl config current-contextand-n. - **
docker run image command -p 80:80.** Options after the image name become arguments to the command. - **Using the
latesttag.** What you tested may not be what runs; pin a version or digest. - **Secrets in
ENV,--build-argor the image.** They stay in layers and inspect output; use runtime secrets or--secret. - **Expecting
docker stopto be instant.** Without SIGTERM handling it waits the full timeout then kills. - **
docker system prune -a --volumeson a shared host.** Deletes other people's unused images and data. - **
kubectl editon production.** Not reproducible; change the manifest andapply. - **
kubectl logsof a crash-looping pod without--previous.** You see the fresh, empty instance. - **Draining a node without
--ignore-daemonsets.** The drain refuses and stops. - **Treating
port-forwardas a service.** It is a debugging tunnel to a single pod.
Long-form pages and what was checked
| Topic | Page |
|---|---|
| Docker: images, layers, networking, security | Docker |
| Kubernetes objects: Pods, Deployments, Services | Kubernetes Core |
| Probes, autoscaling, upgrades, troubleshooting | Kubernetes Operations |
| Linux and shell basics | Linux & Shell Essentials |
| Rollouts and strategies | Deployment Strategies |
Checked on 2026-10-31: all Docker flags and subcommands in chapters 1 to 4 against --help output of Docker 29.4.1 (client) run locally, including the volume prune -a and system prune --volumes semantics and the compose up and compose down flags; kubectl command shapes against the Kubernetes kubectl quick reference (kubernetes.io, main branch) and flag names of drain, auth can-i, wait, logs, rollout status and apply --server-side against the kubectl source in the Kubernetes repository (master). kubectl was not installed locally, so no kubectl command was executed; Kubernetes version differences are not tracked here (see the Kubernetes docs for your cluster version). Exit-code meanings (137, 143, 139) are standard Linux signal conventions rather than Docker-specific documentation.