Essential Docker Commands

Chapter 3 — Essential Docker Commands

This is your practical reference chapter. You've already seen several Docker commands in action — now we cover each one properly, with all the useful flags, real annotated output, and the patterns you'll reach for every single day. Keep this chapter handy while you work through the rest of the course.

We'll cover commands in logical groups: running containers, monitoring them, getting inside them, moving files, and cleaning up. At the end there's a condensed cheat sheet you can refer back to at a glance.

1. docker run — Create and Start a Container

docker run is the command you'll use most. It creates a new container from an image and starts it. Every flag you attach shapes how the container behaves for its entire lifetime.

docker run [flags] IMAGE [COMMAND] Create and start a new container
FlagWhat it doesExample
-d Detached — run in background, return container ID docker run -d nginx
-it Interactive terminal — keep STDIN open and allocate a TTY. Almost always used together docker run -it ubuntu bash
-p HOST:CONT Map a host port to a container port -p 8080:80
--name NAME Give the container a memorable name instead of a random one --name my-site
-e KEY=VALUE Set an environment variable inside the container -e MYSQL_ROOT_PASSWORD=secret
-v HOST:CONT Mount a volume or host directory into the container -v /my/data:/var/lib/mysql
--rm Automatically remove the container when it exits — great for one-off tasks docker run --rm alpine echo hi
--restart POLICY Restart policy: no (default), always, unless-stopped, on-failure --restart unless-stopped
--network NAME Connect to a specific Docker network --network my-net
-w DIR Set the working directory inside the container -w /app
--memory 512m Limit RAM the container can use --memory 256m
Terminal — common docker run patterns
# Background web server, port 8080, auto-restart on reboot $ docker run -d -p 8080:80 --name site --restart unless-stopped nginx:alpine # One-off task — container removed automatically when done $ docker run --rm alpine echo "Hello from Alpine" Hello from Alpine # Interactive Python session in a container $ docker run -it --rm python:3.12-slim python >>> print("Running inside Docker!") Running inside Docker! >>> exit() # Pass environment variable (e.g. database password) $ docker run -d --name mydb \ -e MYSQL_ROOT_PASSWORD=mysecret \ -e MYSQL_DATABASE=myapp \ mysql:8.0
--rm is your best friend for experimentation. Any time you want to try something — run a quick Python script, test a CLI tool, check a config — add --rm and the container vanishes the moment it finishes. No cleanup needed.

2. docker ps — List Containers

docker ps [flags] List containers (running only by default)
FlagWhat it does
-aShow all containers, including stopped ones
-qQuiet — only output container IDs (useful in scripts)
--filter status=exitedFilter by status: created, running, paused, exited, dead
--formatCustom output format using Go templates
Terminal
$ docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS NAMES a91b3c2d4e5f nginx:alpine "nginx..." 5 minutes ago Up 5 minutes site b82c4d3e5f6a ubuntu "bash" 2 hours ago Exited (0) 2 hours ago loving_einstein c73d5e4f6a7b hello-world "/hello" 1 day ago Exited (0) 1 day ago hopeful_morse # Stop ALL running containers in one go $ docker stop $(docker ps -q) # Clean up ALL stopped containers $ docker container prune WARNING! This will remove all stopped containers. Are you sure you want to continue? [y/N] y Deleted Containers: b82c4d3e5f6a c73d5e4f6a7b Total reclaimed space: 24B

3. docker logs — View Container Output

docker logs [flags] CONTAINER Fetch the logs (stdout/stderr) of a container
FlagWhat it doesExample
-f Follow — stream new log lines in real time (like tail -f). Press Ctrl+C to stop following without stopping the container docker logs -f site
--tail N Only show the last N lines docker logs --tail 50 site
--since TIME Show logs since a timestamp or relative time docker logs --since 5m site
-t Add timestamps to each log line docker logs -t site
Terminal
# Watch live access log as requests come in $ docker logs -f site 172.17.0.1 - - [16/Jun/2024:10:45:22 +0000] "GET / HTTP/1.1" 200 615 172.17.0.1 - - [16/Jun/2024:10:45:25 +0000] "GET /favicon.ico HTTP/1.1" 404 555 ^C # Last 10 lines with timestamps — useful for diagnosing a crash $ docker logs --tail 10 -t site 2024-06-16T10:44:01.234567890Z 2024/06/16 10:44:01 [notice] nginx started 2024-06-16T10:45:22.123456789Z 172.17.0.1 - GET / 200
Where do logs come from? Docker captures whatever the container's main process writes to stdout and stderr. Well-behaved applications write their logs there by default (nginx, Apache, MySQL all do). If you're building your own image and logs aren't appearing, make sure your app logs to stdout rather than to a file.

4. docker exec — Run Commands Inside a Running Container

docker exec [flags] CONTAINER COMMAND Execute a command in a running container
FlagWhat it does
-itInteractive terminal — needed when opening a shell
-dDetached — run the command in background
-e KEY=VALUESet environment variable for this command only
-u USERRun as a specific user (e.g. -u root)
-w DIRSet working directory for this command
Terminal
# Open an interactive shell inside a running container $ docker exec -it site sh / # nginx -v nginx version: nginx/1.27.0 / # exit # Run a single command without opening a shell $ docker exec site nginx -t nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful # Reload nginx config without restarting the container $ docker exec site nginx -s reload # Connect to MySQL inside a running database container $ docker exec -it mydb mysql -u root -p Enter password: Welcome to the MySQL monitor...
exec vs run: docker exec runs inside an already running container. docker run creates a brand new container. If you want to poke around inside your nginx container without stopping it, always use exec.

5. docker cp — Copy Files To and From Containers

docker cp SRC DEST Copy files between host and container. Works on running or stopped containers.

Use CONTAINER:PATH syntax to refer to a path inside a container.

DirectionCommand
Host → Container docker cp ./index.html site:/usr/share/nginx/html/
Container → Host docker cp site:/etc/nginx/nginx.conf ./nginx.conf
Copy a directory docker cp ./mysite/ site:/usr/share/nginx/html/
Terminal
# Copy a custom HTML page into a running nginx container $ echo "<h1>Hello from Docker!</h1>" > index.html $ docker cp index.html site:/usr/share/nginx/html/index.html Successfully copied 2.05kB to site:/usr/share/nginx/html/index.html # Now refresh http://localhost:8080 — you'll see "Hello from Docker!" # Extract the default nginx config as a starting point $ docker cp site:/etc/nginx/nginx.conf ./nginx.conf Successfully copied 2.77kB to /home/user/nginx.conf
docker cp vs volumes: docker cp is great for one-off file transfers and extracting config files. For ongoing work — where you want file changes on your host to be immediately visible inside the container — use a volume mount (-v). Chapter 4 covers volumes in detail.

6. docker inspect — Full Container Details

docker inspect returns everything Docker knows about a container or image as a JSON object. It's invaluable for debugging — finding the IP address of a container, checking what volumes are mounted, seeing environment variables, and more.

Terminal
$ docker inspect site [ { "Id": "a91b3c2d4e5f...", "Name": "/site", "State": { "Status": "running", "Running": true, ... }, "NetworkSettings": { "IPAddress": "172.17.0.2", "Ports": { "80/tcp": [{ "HostPort": "8080" }] } }, "Mounts": [], "Config": { "Env": ["PATH=/usr/local/sbin:/usr/local/bin:..."], "Image": "nginx:alpine" } } ]

The output is large. Use --format with Go template syntax to extract just what you need:

# Get just the container's IP address docker inspect --format '{{.NetworkSettings.IPAddress}}' site 172.17.0.2 # Get the restart policy docker inspect --format '{{.HostConfig.RestartPolicy.Name}}' site unless-stopped # Get all environment variables docker inspect --format '{{range .Config.Env}}{{println .}}{{end}}' site # Works on images too — see the exposed ports docker inspect --format '{{.Config.ExposedPorts}}' nginx:alpine map[80/tcp:{}]

7. Stopping, Starting, and Removing Containers

# Graceful stop (sends SIGTERM, waits 10s, then SIGKILL) docker stop site # Immediate kill — no grace period docker kill site # Change the grace period to 30 seconds docker stop --time 30 site # Restart a running or stopped container docker restart site # Remove a stopped container docker rm site # Force remove a running container (stop + rm in one) docker rm -f site # Remove all stopped containers docker container prune # Rename an existing container docker rename old-name new-name

8. Image Commands

# List all local images docker images docker image ls # same thing, newer syntax # Pull without running docker pull nginx:alpine # Remove an image (container must be removed first) docker rmi nginx:alpine docker image rm nginx:alpine # same thing # Remove ALL unused images (not used by any container) docker image prune -a # Show image layers and how they were built docker image history nginx:alpine # Tag an image with a new name docker tag nginx:alpine my-nginx:v1 # Search Docker Hub from the CLI docker search --filter is-official=true python

9. docker system — Disk Usage and Global Cleanup

Terminal
# See how much disk Docker is using $ docker system df TYPE TOTAL ACTIVE SIZE RECLAIMABLE Images 6 2 1.23GB 890MB (72%) Containers 3 1 12.5kB 12.5kB Local Volumes 2 1 145MB 0B Build Cache 18 0 234MB 234MB # Remove everything unused: stopped containers, unused images, # unused networks, build cache. The nuclear option — use with care. $ docker system prune -a WARNING! This will remove: - all stopped containers - all networks not used by at least one container - all images without at least one container associated to them - all build cache Are you sure you want to continue? [y/N]
docker system prune -a removes all images not currently in use by a running container — including images you might want again soon. It's useful for freeing up disk space, but you'll have to re-pull those images next time. Leave out -a to only remove dangling (untagged) images and be a bit more conservative.

10. Quick-Reference Cheat Sheet

Running Containers
docker run -d IMAGEStart in background
docker run -it IMAGE shInteractive shell
docker run --rm IMAGEAuto-remove on exit
docker run -p 8080:80Map host:container port
docker run -e KEY=VALSet env variable
docker run -v /h:/cMount directory
--name NAMEName the container
--restart unless-stoppedAuto-restart on reboot
Monitoring
docker psList running containers
docker ps -aAll containers (inc. stopped)
docker logs NAMEView output
docker logs -f NAMEFollow live output
docker statsLive CPU/RAM usage
docker inspect NAMEFull container details (JSON)
docker top NAMEProcesses inside container
docker system dfDisk usage summary
Container Control
docker stop NAMEGraceful stop
docker start NAMEStart stopped container
docker restart NAMEStop then start
docker rm NAMERemove stopped container
docker rm -f NAMEForce remove (running)
docker exec -it NAME shShell into container
docker cp src NAME:destCopy file in
docker cp NAME:src destCopy file out
Images and Cleanup
docker imagesList local images
docker pull IMAGE:TAGDownload image
docker rmi IMAGERemove image
docker image prune -aRemove unused images
docker container pruneRemove stopped containers
docker system prune -aRemove everything unused
docker search TERMSearch Docker Hub
docker image history IMGShow image layers
Exercises
  1. Run a one-off command with --rm. Use docker run --rm python:3.12-slim python -c "import sys; print(sys.version)" to print the Python version from inside a container, then verify with docker ps -a that no container was left behind.
  2. Use docker cp to serve a custom page. Start an nginx container with docker run -d -p 8080:80 --name site nginx:alpine. Create a simple index.html on your host with any content you like. Copy it into the container using docker cp and verify you can see your page at http://localhost:8080.
  3. Follow the logs. With your nginx container running, open a second terminal and run docker logs -f site. In your browser, visit http://localhost:8080 several times. Watch the access log entries appear in real time in the second terminal.
  4. Use docker inspect to find the IP. Run docker inspect --format '{{.NetworkSettings.IPAddress}}' site to get the container's internal IP address. Then use docker exec -it site sh to open a shell and run ip addr to confirm it matches.
  5. Check disk usage and clean up. Run docker system df to see your current Docker disk usage. Stop and remove the nginx container, then run docker image prune -a to remove any images not in use. Run docker system df again to see how much space you reclaimed.
Next: Chapter 4 — Volumes and Persistent Data
You've seen that containers lose their data when removed. Chapter 4 solves this with volumes — Docker's mechanism for keeping data alive independent of containers. You'll learn the difference between bind mounts (pointing at a folder on your host) and named volumes (managed by Docker), and see how to use each one to persist a database and serve website files that you can edit directly from your machine.