Docker Command Reference

Docker has many commands, but most daily work uses a small, predictable set. A command reference matters because Docker objects are connected: images create containers, containers attach to networks and volumes, and registries store image layers behind tags and digests. This lesson organizes the commands by job so you can choose the right tool without memorizing the whole CLI.

Overview: How Docker commands work

The docker command is a client. On Linux it usually talks to the Docker Engine daemon through a Unix socket such as /var/run/docker.sock. On Docker Desktop for macOS and Windows, the client talks to a daemon running inside a small Linux VM. Either way, the commands you type ask the daemon to pull layers, create containers, mount filesystems, attach networks, collect logs, and push manifests to registries.

Docker commands mostly operate on five object types. An image is a read-only template made from stacked filesystem layers plus configuration such as CMD, ENTRYPOINT, ENV, USER, and exposed ports. A container is an instance of an image with a thin writable layer and, when running, a process. A volume is Docker-managed persistent storage. A network connects containers and provides DNS for container names or Compose service names. A registry stores compressed layer blobs and manifests; a tag points to a manifest, while a digest identifies exact image content.

Many commands have a noun-and-verb shape: docker image ls, docker container rm, docker volume inspect. Docker also keeps older shorthand commands such as docker ps, docker images, and docker rmi. Both forms are common. The newer object-oriented form is easier to discover because related operations sit under the same noun.

For multi-container projects, use docker compose, the modern Compose V2 subcommand. It reads a Compose YAML file, creates a project network, starts services, attaches named volumes, and lets services reach each other by service name. The old standalone docker-compose command exists in legacy environments, but new examples should use docker compose.

Syntax

docker [GLOBAL_OPTIONS] COMMAND [ARGUMENTS]
docker OBJECT COMMAND [OPTIONS] [ARGUMENTS]
docker compose [OPTIONS] COMMAND [ARGUMENTS]
Form Purpose
docker --help Lists top-level commands and global options.
docker COMMAND --help Shows options for one command, such as docker run --help.
docker build -t NAME:TAG . Builds an image from the current directory as the build context.
docker run [OPTIONS] IMAGE Creates and starts a new container from an image.
docker ps -a Lists running and stopped containers.
docker logs CONTAINER Prints container stdout and stderr captured by Docker.
docker exec -it CONTAINER COMMAND Runs an extra process inside an existing running container.
docker compose up -d Creates or updates a Compose application in the background.
docker inspect OBJECT Prints detailed JSON metadata for images, containers, volumes, or networks.

Examples

Build and run a small web image

FROM nginx:1.27-alpine
COPY ./site /usr/share/nginx/html
EXPOSE 80

Output:

Dockerfile saved. The image will contain static files from ./site and records port 80 as metadata.

This Dockerfile uses a pinned base image tag instead of nginx or latest, which makes rebuilds more predictable. The EXPOSE line documents that the container listens on port 80, but it does not publish the port to the host. Publishing happens when a container is started with -p or when Compose uses ports:.

docker build -t static-site:1.0 .
docker run --rm --name static-site -p 8080:80 static-site:1.0

Output:

[+] Building 4.1s (7/7) FINISHED
=> naming to docker.io/library/static-site:1.0
Serving content on http://localhost:8080

The build command sends the current directory as the build context, applies the Dockerfile, and tags the result. The run command creates a container from that image and maps host port 8080 to container port 80. The --rm flag removes the container when it exits, but it does not delete the image.

Inspect containers and read logs

docker ps --filter "name=static-site"
docker logs static-site
docker inspect --format '{{.State.Status}} {{.NetworkSettings.Ports}}' static-site

Output:

CONTAINER ID   IMAGE             COMMAND                  STATUS          PORTS                  NAMES
0b7a2d6f8c91   static-site:1.0   "/docker-entrypoint.…"   Up 2 minutes    0.0.0.0:8080->80/tcp   static-site
172.17.0.1 - - "GET / HTTP/1.1" 200 615
running map[80/tcp:[{0.0.0.0 8080}]]

docker ps is the quick view for container state. docker logs reads stdout and stderr captured by Docker; it does not read arbitrary files inside the container. docker inspect exposes the full metadata model, and --format lets you extract only the fields you need in scripts.

Use volumes and networks deliberately

docker network create app-net
docker volume create app-data
docker run -d --name redis-cache --network app-net redis:7.4-alpine
docker run --rm --name app-tools --network app-net -v app-data:/data alpine:3.20 sh -c "echo cached > /data/status.txt && cat /data/status.txt"

Output:

app-net
app-data
cached

The network command creates an isolated bridge network where containers can reach each other by name. The volume command creates Docker-managed storage that survives container removal. The final command mounts the volume at /data and writes a file there. If the container disappears, the named volume remains until you remove it with docker volume rm app-data.

Manage a project with Compose

services:
  web:
    image: nginx:1.27-alpine
    ports:
      - "8080:80"
    volumes:
      - ./site:/usr/share/nginx/html:ro
  cache:
    image: redis:7.4-alpine
volumes: {}

Output:

compose.yml saved. The web service is published on host port 8080, and cache is reachable as hostname cache.

This Compose file runs a small web server and Redis cache. The bind mount maps a specific host directory into the web container as read-only, which is useful for local development. It is different from a named volume: a bind mount points to a host path you choose, while a named volume is managed inside Docker’s storage area.

docker compose up -d
docker compose ps
docker compose logs web
docker compose down

Output:

[+] Running 3/3
 ✔ Network reference_default  Created
 ✔ Container reference-web-1   Started
 ✔ Container reference-cache-1 Started
NAME                IMAGE             STATUS          PORTS
reference-web-1     nginx:1.27-alpine Up              0.0.0.0:8080->80/tcp

Compose groups resources under a project name, creates a default network, and starts services in dependency order when possible. down removes the project containers and network. It does not remove named volumes unless you add --volumes, which is important when data should survive restarts.

How it works step by step

  1. You type a command. The Docker CLI parses flags, reads your Docker context, and sends an API request to the daemon.
  2. The daemon resolves object names. For images, it checks local tags and may contact a registry. For containers, it finds the container ID behind a name.
  3. Images are pulled or built as layers. Docker reuses local layers when possible. During builds, each instruction creates or reuses a cached layer; a changed instruction invalidates that layer and every later layer.
  4. A container gets a writable layer. When docker run creates a container, Docker mounts the image layers read-only and adds a thin writable layer for container changes.
  5. Runtime settings are applied. Docker attaches networks, mounts volumes or bind mounts, sets environment variables, configures port publishing, and starts the configured process.
  6. Output is captured. Stdout and stderr become docker logs. Metadata becomes available through docker inspect.
  7. Cleanup is explicit. Removing a container does not remove its image. Removing an image does not remove containers using it. Volumes also persist until removed.

Common Mistakes

Using a command that creates a new container when you meant to enter the old one

docker run -it static-site:1.0 sh

This creates a brand-new container from the image. It does not open a shell in the already running static-site container. Use docker exec when you need an extra process inside an existing running container.

docker exec -it static-site sh

Assuming EXPOSE publishes a port

FROM nginx:1.27-alpine
EXPOSE 80

This is only image metadata. It helps humans and tooling understand the intended port, but the host still cannot reach the container unless you publish the port with docker run -p 8080:80 nginx:1.27-alpine or Compose ports:.

Removing the wrong thing

docker rm static-site
docker rmi static-site:1.0

docker rm removes containers. docker rmi or docker image rm removes images. If a stopped container still references an image, Docker may refuse to remove the image until the container is removed. Volumes are separate again, so deleting a container does not automatically delete a named volume.

Depending on latest in automation

docker pull nginx:latest
docker run -d --name web nginx:latest

latest is a mutable tag, not a guarantee of freshness or safety. In CI/CD and production, prefer explicit version tags and record the image digest after testing.

Best Practices

  • Use docker COMMAND --help when checking flags; it is faster and more accurate than guessing.
  • Prefer explicit object names such as --name static-site, volume names, and network names in examples, scripts, and runbooks.
  • Use pinned image tags for repeatable builds and deployments. Treat latest as a convenience for experiments only.
  • Use docker run --rm for disposable one-shot containers, but avoid it for services whose writable layer you still need to inspect.
  • Publish ports explicitly with -p host:container or Compose ports:; remember that EXPOSE is documentation.
  • Use named volumes for persistent data and bind mounts for deliberate host-path sharing during development.
  • Use docker inspect --format for scripts instead of parsing human-oriented tables from docker ps.
  • Use docker compose for multi-service local and CI workflows, not the legacy docker-compose binary.
  • Clean up carefully: inspect before using prune commands on shared machines because unused images, containers, networks, and volumes may still matter to someone else.

Practice Exercises

  1. A teammate says the app container is running, but the browser cannot reach it. Identify the commands you would use to check container status, published ports, and recent logs. Hint: start with docker ps.
  2. Create a command sequence for a disposable Redis test container on a custom network named lab-net. Expected end state: the Redis container can be removed without affecting the network.
  3. Given a Compose project with a web service, find the commands to start it in the background, view only that service’s logs, list project containers, and remove the project.

Summary

  • The Docker CLI talks to the Docker daemon, which manages images, containers, networks, volumes, and registry communication.
  • Images are read-only layered templates; containers are instances with a writable layer and runtime settings.
  • docker run creates a new container, while docker exec runs a command in an existing running container.
  • docker logs, docker ps, and docker inspect are the core troubleshooting commands.
  • Compose is the standard tool for multi-container projects and should be invoked as docker compose.
  • Cleanup commands target different object types, so remove containers, images, networks, and volumes intentionally.