Docker Vocabulary

42 essential Docker terms in plain English — what each one means, a Dockerfile, CLI, or Compose example, and the gotcha worth knowing.

Last reviewed:

Sections

Core concepts

image

A read-only template containing your app, its dependencies, and a filesystem. You build an image once and run it as many containers.

docker build -t myapp:1.0 .
docker images

💡 An image is the blueprint; a container is a running instance of it.

container

A running (or stopped) instance of an image — an isolated process with its own filesystem, network, and process tree.

docker run -d --name web myapp:1.0
docker ps

💡 Containers are ephemeral by design; persist data in volumes, not in the container.

layer

Each Dockerfile instruction creates a stacked, cached filesystem layer. Layers are shared between images, which is why pulls and builds are fast.

docker history myapp:1.0

💡 Order instructions least- to most-changing so the cache survives small edits.

tag

A human-readable label on an image, usually a version. The part after the colon in name:tag. Defaults to "latest" if omitted.

docker tag myapp:1.0 myapp:stable

💡 "latest" is just a default tag, not a guarantee of the newest build — pin real versions.

digest

A content-addressable SHA256 hash that identifies an exact image, immutably. Unlike a tag, a digest never moves.

docker pull myapp@sha256:9b2c...e1

💡 Pin by digest in production for reproducible, tamper-evident deploys.

base image

The image your Dockerfile starts FROM. Everything else is layered on top of it — e.g. node:22-alpine or scratch.

FROM node:22-alpine

💡 Smaller bases (alpine, distroless) mean smaller images and a smaller attack surface.

multi-stage build

Using several FROM stages in one Dockerfile — build in a fat stage, then copy only the artefacts into a tiny final stage.

FROM golang:1.23 AS build
WORKDIR /src
COPY . .
RUN go build -o app

FROM gcr.io/distroless/base
COPY --from=build /src/app /app
ENTRYPOINT ["/app"]

💡 Keeps compilers and dev dependencies out of the shipped image.

Dockerfile directives

FROM

Sets the base image for the build stage. Must be the first instruction (after optional ARGs). Can appear multiple times in a multi-stage build.

FROM python:3.12-slim AS base

💡 Add "AS <name>" to name a stage you can copy from later.

RUN

Executes a command during the build and commits the result as a new layer — installing packages, compiling, etc.

RUN apt-get update && apt-get install -y curl \
    && rm -rf /var/lib/apt/lists/*

💡 Chain commands with && in one RUN to avoid extra layers and stale caches.

COPY

Copies files/directories from the build context into the image. The plain, predictable way to add your source code.

COPY package*.json ./
COPY src ./src

💡 Copy dependency manifests first, install, then copy source — keeps the install layer cached.

ADD

Like COPY but with extras: it can fetch remote URLs and auto-extract local tar archives.

ADD release.tar.gz /opt/app/

💡 Prefer COPY for plain files; reach for ADD only when you need its tar/URL behaviour.

CMD

The default command run when a container starts. Easily overridden by arguments to docker run.

CMD ["node", "server.js"]

💡 Use the JSON exec form ["..."] so signals reach your process directly.

ENTRYPOINT

The fixed executable a container always runs. Arguments from docker run (and CMD) are appended to it.

ENTRYPOINT ["python", "manage.py"]
CMD ["runserver"]

💡 ENTRYPOINT = the binary, CMD = its default args — they work as a pair.

ARG

A build-time variable, passed with --build-arg. Available only during the build, not in the running container.

ARG VERSION=1.0
RUN echo "building $VERSION"

💡 Do not use ARG for secrets — values can leak into image history.

ENV

Sets an environment variable baked into the image and present at runtime in every container.

ENV NODE_ENV=production \
    PORT=8080

💡 Override at runtime with docker run -e KEY=value.

EXPOSE

Documents which port the container listens on. It is metadata only — it does not actually publish the port.

EXPOSE 8080

💡 You still need -p / ports: to make the port reachable from the host.

WORKDIR

Sets the working directory for subsequent RUN, CMD, COPY, and ENTRYPOINT instructions. Creates it if missing.

WORKDIR /usr/src/app

💡 Cleaner and safer than RUN cd ... which does not persist between instructions.

VOLUME

Declares a mount point whose data should live in a volume, outside the container's writable layer.

VOLUME ["/var/lib/data"]

💡 Creates an anonymous volume at runtime unless you mount a named one over it.

USER

Sets the user (and optionally group) that RUN, CMD, and ENTRYPOINT run as. Use it to avoid running as root.

RUN adduser -D app
USER app

💡 Running as a non-root user is a baseline container-security best practice.

HEALTHCHECK

Tells Docker how to test that the container is actually healthy, not just running. Sets the container status to healthy/unhealthy.

HEALTHCHECK --interval=30s --timeout=3s \
  CMD curl -f http://localhost:8080/health || exit 1

💡 Orchestrators and Compose depends_on can wait on healthy status.

Docker Compose

services

The top-level map in a Compose file. Each entry is one container definition — image or build, ports, env, volumes.

services:
  web:
    image: myapp:1.0
    ports: ["8080:8080"]
  db:
    image: postgres:16

💡 Service names double as DNS hostnames on the Compose network.

depends_on

Declares startup order between services. With a condition it can wait until a dependency is healthy.

services:
  web:
    depends_on:
      db:
        condition: service_healthy

💡 Plain depends_on only waits for start, not readiness — pair with a healthcheck.

healthcheck (compose)

Defines a health probe for a service directly in the Compose file, overriding any in the image.

services:
  db:
    image: postgres:16
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 10s
      retries: 5

💡 Makes condition: service_healthy meaningful for dependents.

networks (compose)

Defines custom networks and which services join them. Services on the same network reach each other by service name.

services:
  web:
    networks: [frontend]
networks:
  frontend: {}

💡 By default Compose puts all services on one shared network.

volumes (compose)

Declares named volumes and mounts them into services for persistent data that outlives container restarts.

services:
  db:
    volumes:
      - db-data:/var/lib/postgresql/data
volumes:
  db-data: {}

💡 Named volumes survive docker compose down; add -v to also delete them.

ports

Publishes container ports to the host, mapping HOST:CONTAINER. The Compose equivalent of docker run -p.

services:
  web:
    ports:
      - "8080:80"

💡 Omit the host part ("80") to let Docker pick a random host port.

environment

Sets environment variables for a service, as a list or a map. Often paired with an env_file.

services:
  web:
    environment:
      NODE_ENV: production
      DATABASE_URL: postgres://db:5432/app

💡 Reference db by service name — Compose DNS resolves it on the network.

build

Tells Compose to build an image from a Dockerfile instead of pulling one. Can point at a context and a specific Dockerfile.

services:
  web:
    build:
      context: .
      dockerfile: Dockerfile
      args:
        VERSION: "1.0"

💡 Run docker compose build, or docker compose up --build to rebuild on start.

Networking

bridge

The default network driver. Containers get a private IP on a virtual bridge and reach the outside world via NAT.

docker network create --driver bridge appnet
docker run --network appnet myapp:1.0

💡 On a user-defined bridge, containers can resolve each other by name; on the default bridge they cannot.

host

The container shares the host's network stack directly — no isolation, no port mapping needed. Linux only.

docker run --network host nginx

💡 Fastest networking but the container can bind any host port — use with care.

none

Disables networking entirely. The container gets only a loopback interface — fully isolated.

docker run --network none myapp:1.0

💡 Useful for batch jobs that must not touch the network.

port mapping

Publishing a container port to a host port so external clients can reach it. The -p HOST:CONTAINER flag.

docker run -p 8080:80 nginx

💡 Add an interface to bind locally only: -p 127.0.0.1:8080:80.

container DNS

Docker runs an embedded DNS server on user-defined networks so containers resolve each other by name or alias.

# from the "web" container, on a shared network:
ping db
curl http://db:5432

💡 This is why Compose lets you use service names as hostnames.

Storage

volume

Docker-managed persistent storage living outside the container. The preferred way to keep data across container restarts and rebuilds.

docker volume create db-data
docker run -v db-data:/var/lib/data myapp:1.0

💡 Managed by Docker under /var/lib/docker/volumes — portable and backup-friendly.

bind mount

Mounts a specific host directory or file into the container. Changes flow both ways — great for live-reloading source in development.

docker run -v $(pwd)/src:/app/src myapp:1.0

💡 Tied to the host path; less portable than named volumes.

tmpfs

An in-memory mount that never touches disk and vanishes when the container stops. For secrets and scratch data.

docker run --tmpfs /run:size=64m myapp:1.0

💡 Fast and leaves no trace on disk — Linux only.

anonymous volume

A volume with a random name created automatically — by a VOLUME directive or a -v with no source name. Easy to leave dangling.

docker run -v /var/lib/data myapp:1.0

💡 Run docker volume prune to clean up unused anonymous volumes.

Registry

registry

A server that stores and distributes images. Docker Hub is the public default; you can run private registries (Harbor, ECR, GHCR).

docker login registry.example.com
docker pull registry.example.com/team/app:1.0

💡 A full image reference is registry/namespace/name:tag.

Docker Hub

Docker's default public registry. When you pull "nginx", you are really pulling docker.io/library/nginx.

docker pull nginx:1.27   # = docker.io/library/nginx:1.27

💡 Anonymous pulls are rate-limited — authenticate or mirror for CI.

push

Upload a local image to a registry so others (or your cluster) can pull it.

docker push registry.example.com/team/app:1.0

💡 You must tag the image with the registry hostname before you can push it there.

pull

Download an image from a registry to your local machine. docker run pulls automatically if the image is missing.

docker pull postgres:16

💡 Pull by digest (@sha256:...) for an exact, immutable image.

tag-and-push

The standard publish flow: tag a local image with the target registry path, then push it there.

docker tag myapp:1.0 ghcr.io/acme/myapp:1.0
docker push ghcr.io/acme/myapp:1.0

💡 The tag's registry prefix decides where push sends the image.

English phrases engineers use

  • "Copy the package manifest first, install, then copy the source — otherwise every code change busts the dependency layer cache."
  • "Use a multi-stage build so the compiler doesn't ship in the final image."
  • "ENTRYPOINT is the binary and CMD is the default args — they work as a pair."
  • "Don't run as root — add a USER instruction near the end of the Dockerfile."
  • "In Compose, set depends_on with condition: service_healthy so the app waits for the database."
  • "Persist the data in a named volume, not the container — it's wiped on every rebuild otherwise."
  • "Tag and push to the registry, then pin the deploy to the digest for a reproducible release."