The Docker CLI day to day: inspect, filter, format and clean up
The commands you use every day for images, containers, volumes and networks, how to filter and format their output for scripts, and how to win back disk space safely with docker system df and prune.
By the end of this lesson you'll be able to
0 of 5 completeOne pattern
Every Docker command is docker <object> <verb>. Learn the verbs once and they work everywhere:
| Object | ls | inspect | rm | prune |
|---|---|---|---|---|
image | docker image ls (docker images) | docker image inspect | docker image rm (rmi) | docker image prune |
container | docker container ls (docker ps) | docker container inspect | docker container rm (rm) | docker container prune |
volume | docker volume ls | docker volume inspect | docker volume rm | docker volume prune |
network | docker network ls | docker network inspect | docker network rm | docker network prune |
docker <object> --help lists the rest.
Images
$ docker image ls --filter reference='price-api*' --format '{{.Repository}}:{{.Tag}} {{.Size}}' price-api:multi 14.6MB price-api:dev 14.6MB price-api:single 508MB $ docker image history price-api:multi # layers and their sizes (lesson 7) $ docker image inspect price-api:multi --format '{{.Config.User}} {{json .Config.Entrypoint}}' nonroot ["/price-api"] $ docker image rm price-api:single # removes the tag; layers go when nothing uses them $ docker pull --platform linux/arm64 alpine:3.22 # a specific architecture
docker image ls --filter reference='price-api*' --format '{{.Repository}}:{{.Tag}} {{.Size}}'dockerbuild and run containersimagemanage imageslslist them--filter reference='price-api*'show only matching items--format '{{.Repository}}:{{.Tag}} {{.Size}}'print only these fields (Go template)
docker image inspect price-api:multi --format '{{.Config.User}} {{json .Config.Entrypoint}}'inspectshow details as JSON--format '{{.Config.User}} {{json .Config.Entrypoint}}'print only these fields (Go template)
docker image rm price-api:singlermdelete one
docker pull --platform linux/arm64 alpine:3.22pulldownload an image--platform linux/arm64which CPU architecturealpine:3.22the image
Containers
$ docker ps -a --filter status=exited --format 'table {{.Names}}\t{{.Status}}' $ docker inspect web --format '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' $ docker logs --since 10m --tail 50 web $ docker exec -it web sh $ docker cp web:/etc/nginx/nginx.conf ./nginx.conf # copy out of a container $ docker cp ./index.html web:/usr/share/nginx/html/ # and into it $ docker stats --no-stream # CPU, memory, network, against limits $ docker top web # processes, as the host sees them $ docker container rm -f $(docker ps -aq --filter label=env=test) # remove a whole group
docker ps -a --filter status=exited --format 'table {{.Names}}\t{{.Status}}'dockerbuild and run containerspslist running containers-ainclude stopped ones too--filter status=exitedshow only matching items--format 'table {{.Names}}\t{{.Status}}'print only these fields (Go template)
docker inspect web --format '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}'inspectshow every detail as JSONwebthe container or image--format '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}'print only these fields (Go template)
docker logs --since 10m --tail 50 weblogsshow a container’s output--since 10monly output newer than this--tail 50only the last N lineswebthe container
docker exec -it web shexecrun a command in a running container-itinteractive, with a terminalshthe command to run inside it
docker cp web:/etc/nginx/nginx.conf ./nginx.confcpcopy files between a container and the host
docker stats --no-streamstatslive CPU and memory use--no-streamprint once instead of updating
docker top webtopprocesses in a container
docker container rm -f $(docker ps -aq --filter label=env=test)containermanage containersrmdelete one-fdon’t ask to confirm$(docker ps -aq --filter label=env=test)the output of another command
--filter narrows lists (by status, name, label, ancestor, network…). --format takes a Go
template: {{.Names}}, {{json .Config}}, table for aligned columns. docker inspect returns everything
Docker knows about an object as JSON, and is the first place to look when something behaves oddly: the
mounts, environment, restart count, health log and exit code are all there.
Volumes and networks
$ docker volume ls --filter dangling=true # volumes no container uses $ docker volume inspect shop_pgdata --format '{{.Mountpoint}}' $ docker network ls $ docker network inspect appnet --format '{{range .Containers}}{{.Name}} {{.IPv4Address}}{{"\n"}}{{end}}'
docker volume ls --filter dangling=truedockerbuild and run containersvolumemanage volumeslslist them--filter dangling=trueshow only matching items
docker volume inspect shop_pgdata --format '{{.Mountpoint}}'inspectshow details as JSON--format '{{.Mountpoint}}'print only these fields (Go template)
docker network lsnetworkmanage networks
docker network inspect appnet --format '{{range .Containers}}{{.Name}} {{.IPv4Address}}{{"\n"}}{{end}}'--format '{{range .Containers}}{{.Name}} {{.IPv4Address}}{{"\n"}}{{end}}'print only these fields (Go template)
Cleanup
Docker never deletes anything on its own. Images from old builds, stopped containers, anonymous volumes and the build cache pile up until the disk is full, often on a CI runner at 2 a.m. See where the space goes:
$ docker system df TYPE TOTAL ACTIVE SIZE RECLAIMABLE Images 21 0 5.446GB 479MB (8%) Containers 0 0 0B 0B Local Volumes 14 0 510.6MB 510.6MB (100%) Build Cache 74 0 1.226GB 447.7MB
docker system dfdockerbuild and run containerssystemdisk use and cleanupdfdisk use by type
That's this machine after the course so far: 14 volumes nobody uses (mostly anonymous Postgres volumes from lesson 6) and half a gigabyte of build cache. Clean each kind on purpose:
$ docker volume prune -f Total reclaimed space: 510.6MB $ docker builder prune -f Total: 404.6MB $ docker system df TYPE TOTAL ACTIVE SIZE RECLAIMABLE Images 21 0 5.045GB 77.44MB (1%) Containers 0 0 0B 0B Local Volumes 1 0 0B 0B Build Cache 37 0 820.9MB 43.11MB
docker volume prune -fdockerbuild and run containersvolumemanage volumesprunedelete the unused ones-fdon’t ask to confirm
docker builder prune -fbuildermanage the build cache
docker system dfsystemdisk use and cleanupdfdisk use by type
| Command | Removes |
|---|---|
docker container prune | stopped containers |
docker image prune | dangling images (untagged leftovers); -a: every image no container uses |
docker volume prune | unused anonymous volumes; --all: unused named volumes too |
docker network prune | networks no container uses |
docker builder prune | build cache; --filter until=168h keeps the last week |
docker system prune | containers, networks, dangling images and build cache; add --volumes or -a to go further |
Measure before you prune
docker system df maps image, container and volume usage; prune narrowly after checking what is reclaimable.
inspect --format gives stable fields for scripts, and docker context show confirms which daemon a command will
affect. These are operational safeguards, not backups.
$ docker system df $ docker ps --format '{{.Names}} {{.Image}} {{.Status}}' $ docker inspect api --format '{{.Name}} {{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' $ docker context show $ docker container prune --filter until=24h
docker system dfdockerbuild and run containerssystemdisk use and cleanupdfdisk use by type
docker ps --format '{{.Names}} {{.Image}} {{.Status}}'pslist running containers--format '{{.Names}} {{.Image}} {{.Status}}'print only these fields (Go template)
docker inspect api --format '{{.Name}} {{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}'inspectshow every detail as JSONapithe container or image--format '{{.Name}} {{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}'print only these fields (Go template)
docker context showcontextchoose which daemon to talk to
docker container prune --filter until=24hcontainermanage containersprunedelete the unused ones--filter until=24hshow only matching items
Find and reclaim wasted space
Measure Docker's disk use, create some junk on purpose (exited containers, anonymous volumes, a dangling image), find each kind with filters, and remove it with the matching prune without touching a named volume you want to keep.
docker system df before and after, with the keep-me volume still presentReveal one safe solution
$ docker system df $ docker volume create keep-me $ for i in 1 2 3; do docker run -v /data alpine:3.22 true; done # 3 exited containers, 3 anonymous volumes $ docker ps -a --filter status=exited --filter ancestor=alpine:3.22 --format '{{.Names}} {{.Status}}' $ docker container prune -f $ docker volume ls --filter dangling=true # now unused: the 3 anonymous ones, and keep-me $ docker volume prune -f $ docker volume ls --filter name=keep-me DRIVER VOLUME NAME local keep-me $ docker system df && docker volume rm keep-me
docker system dfdockerbuild and run containerssystemdisk use and cleanupdfdisk use by type
docker volume create keep-mevolumemanage volumescreatecreate one
for i in 1 2 3; do docker run -v /data alpine:3.22 true; doneforloop over a listdostart of what the loop runs each timerunstart a new container-v /datamount a volume or folder, source:path-insidealpine:3.22the image to starttrue;the command run inside, instead of the image’s defaultdoneend of the loop
docker ps -a --filter status=exited --filter ancestor=alpine:3.22 --format '{{.Names}} {{.Status}}'pslist running containers-ainclude stopped ones too--filter status=exitedshow only matching items--filter ancestor=alpine:3.22show only matching items--format '{{.Names}} {{.Status}}'print only these fields (Go template)
docker container prune -fcontainermanage containersprunedelete the unused ones-fdon’t ask to confirm
docker volume ls --filter dangling=truelslist them--filter dangling=trueshow only matching items
docker volume ls --filter name=keep-me--filter name=keep-meshow only matching items
docker system df && docker volume rm keep-me&&run the next command only if this one workedrmdelete one
volume prune removed the anonymous volumes but kept keep-me, because named volumes need --all. Order
matters too: volumes still attached to a stopped container aren't unused, so containers go first.
Try it yourself
0 of 6 steps doneRun each task in your own account or terminal, then tick it off.
Quick check
docker system df shows Local Volumes at 510MB, 100% reclaimable. What does that mean?
Official reading for this lesson
Or get every quiz answer right and it completes itself.