Key Docker Concepts

By Vishvesh Patel · DevOps EngineerUpdated September 16, 2026

The Docker object model in one page. Image, container, layer, Dockerfile, registry, volume, network and Compose, and how they fit together.

Docker has perhaps eight ideas in it. Most early confusion comes from three of them sounding interchangeable when they are not, image, container and Dockerfile, so this page defines each precisely and shows how they connect.

The one-line version

A Dockerfile is a recipe. Building it produces an image, which is a read-only template. Running an image produces a container, which is a live process. A registry is where images are stored and shared.

Dockerfile ──docker build──▶ Image ──docker run──▶ Container
                              │  ▲
                    docker push│  │docker pull
                              ▼  │
                            Registry

Everything else, volumes, networks, Compose, exists to make containers useful together.

Image

A read-only template containing everything needed to run an application: the code, the language runtime, system libraries, and the metadata describing how to start it.

An image is built from layers, one per instruction in the Dockerfile, stacked and presented as a single filesystem. Layers are what make Docker efficient: they are content-addressed and shared, so ten images built on node:22-alpine store that base exactly once on disk and pull it exactly once from a registry.

docker images
REPOSITORY   TAG       IMAGE ID       CREATED        SIZE
myapp        1.0       a3f2c1d4e5b6   2 hours ago    142MB
node         22-alpine 7b8c9d0e1f2a   3 days ago     135MB

Two consequences of the layer model worth internalising early. Layers are immutable, so a file added in one layer and deleted in a later one still occupies space in the image, and is still recoverable, which is why a deleted secret is a leaked secret. And layers are cached, so the order of instructions in a Dockerfile largely determines how fast rebuilds are.

Go deeper: Docker images and image layers.

Container

A running instance of an image. If the image is the recipe, the container is the meal.

Technically it is an ordinary Linux process with restricted visibility. Namespaces give it its own view of the filesystem, process table, network stack and hostname; cgroups cap what CPU and memory it can consume. There is no virtual machine and no guest operating system. This is why a container starts in milliseconds where a VM takes a minute.

Docker adds one thin writable layer on top of the image's read-only layers. Every file the container creates or modifies lands there, and it is deleted with the container. That single fact explains most Docker surprises for newcomers: your database is empty again because its data lived in the writable layer of a container that no longer exists.

docker ps
CONTAINER ID   IMAGE       STATUS         PORTS                    NAMES
9f2c1a4b7e3d   myapp:1.0   Up 4 minutes   0.0.0.0:3000->3000/tcp   api

Containers are ephemeral by design. Treat them as disposable and keep anything that must survive in a volume.

Go deeper: Docker containers and the container lifecycle.

Dockerfile

A plain text file of instructions for building an image, executed top to bottom:

FROM node:22-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
EXPOSE 3000
USER node
CMD ["node", "server.js"]
docker build -t myapp:1.0 .

Each instruction produces a layer. The reason the package manifest is copied and installed before the source is that Docker reuses cached layers up to the first changed instruction, so copying source first would reinstall every dependency on every code edit.

Go deeper: Dockerfile basics.

Registry

Storage and distribution for images. GitHub, but for images rather than source. You push to share and pull to consume.

docker pull postgres:17
docker tag myapp:1.0 ghcr.io/acme/myapp:1.0
docker push ghcr.io/acme/myapp:1.0

Docker Hub is the default: if you run docker pull nginx with no registry prefix, that is where it comes from. Most organisations also use a private registry. GitHub Container Registry, Amazon ECR, Google Artifact Registry, Azure Container Registry. For their own images.

A tag such as 1.0 or latest is a mutable pointer to an image, not a permanent name. latest in particular is just a default tag with no special meaning; it does not track the newest version. A digest (@sha256:…) is immutable and is what you pin when reproducibility matters.

Go deeper: Docker Hub and registries.

Volume

Storage that outlives the container. Since the container's writable layer is destroyed with it, anything that must persist, database files, uploads, goes in a volume.

docker volume create pgdata
docker run -d -v pgdata:/var/lib/postgresql/data postgres:17

Three kinds, and the distinction comes up constantly:

TypeWritten asUse
Named volume-v pgdata:/var/lib/…Docker manages it; the default for data
Bind mount-v ./src:/app/srcA host directory; the default for development
tmpfs--tmpfs /tmpMemory only; never touches disk

Go deeper: Docker volumes.

Network

Containers on the same user-defined network reach each other by container name, which is Docker's built-in DNS at work:

docker network create appnet
docker run -d --name db --network appnet postgres:17
docker run -d --name api --network appnet myapp:1.0

The API connects to db:5432. No IP addresses, no --link, nothing to update when a container restarts with a different address.

Note that localhost inside a container means that container, not the host and not another container. Expecting localhost:5432 to reach a database in a different container is one of the most common beginner errors.

Go deeper: container networking.

Docker Compose

Real applications are several containers. Compose describes them in one file so the whole stack starts together:

services:
  api:
    build: .
    ports:
      - "3000:3000"
    environment:
      DATABASE_URL: postgres://app:secret@db:5432/app
    depends_on:
      db:
        condition: service_healthy

  db:
    image: postgres:17
    environment:
      POSTGRES_PASSWORD: secret
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      retries: 5

volumes:
  pgdata:
docker compose up -d
docker compose logs -f api
docker compose down

Compose creates a network automatically, which is why db resolves as a hostname without any extra configuration.

It is a single-host tool. Excellent for development and small deployments, not a replacement for an orchestrator. Once you need scheduling across machines, rolling updates and self-healing, that is Kubernetes.

Client and daemon

One more piece, because it explains a whole class of error messages.

The docker command is a client. It does almost nothing itself. It sends requests over a socket to the daemon (dockerd), which builds images, runs containers and manages storage.

docker CLI ──/var/run/docker.sock──▶ dockerd ──▶ containerd ──▶ runc ──▶ your process

So Cannot connect to the Docker daemon means the CLI is installed and working, and nothing is listening. Start the service. And permission denied ... docker.sock means the daemon is running but your user cannot talk to its socket.

It also explains why the build context is sent to the daemon: the daemon may not be on your machine at all.

The vocabulary, condensed

TermWhat it is
ImageRead-only template built from layers
LayerOne filesystem diff, produced by one instruction
ContainerA running instance, plus a thin writable layer
DockerfileBuild instructions for an image
Build contextThe directory sent to the daemon at build time
RegistryWhere images are stored and shared
TagA mutable pointer to an image
DigestAn immutable content hash
VolumeStorage that outlives the container
Bind mountA host directory mounted into a container
NetworkContainer-to-container connectivity with DNS
ComposeMulti-container definition for one host
Daemondockerd, the process doing the work

Key takeaways

  • Image is the template, container is the running instance. Recipe and meal.
  • A container's writable layer dies with it. Anything that must survive belongs in a volume.
  • Layers are immutable and cached: which sets both your rebuild speed and why deleted files still ship.
  • Containers are processes, not virtual machines. Namespaces isolate, cgroups limit.
  • latest is just a default tag, not the newest version. Pin a digest when it matters.
  • Containers on a user-defined network resolve each other by name, and localhost means that container alone.
  • The CLI only talks to the daemon, which is why "cannot connect" is a different problem from "not installed".

Check your understanding

Exercise

A database that keeps forgetting

A Postgres container is started with docker run, data is written, then the container is removed and recreated from the same image. The data is gone. Which concept explains this?


Frequently Asked Questions

What is the difference between a Docker image and a container?

An image is a read-only template: the application, its runtime, its libraries and the metadata describing how to start it, stored as a stack of layers. A container is a running instance created from that image, with a thin writable layer on top for anything it changes. One image can back any number of containers simultaneously, each with its own writable layer, in the same way one class can have many instances. The practical consequence is that images persist and containers are disposable.

Where does data written inside a container go?

Into the container's writable layer, which exists only as long as the container does. Remove the container and every file it created is removed with it, which is why a database restarted from the same image comes back empty. Mount a named volume at the path that matters (-v pgdata:/var/lib/postgresql/data) and the data lives outside the container lifecycle. Bind mounts do the same thing with a specific host directory, which is what you usually want in development.

What is a Docker layer and why does it matter?

Each Dockerfile instruction produces one layer, a filesystem diff, and the image is those layers stacked into a single view. They matter for three reasons. They are shared, so images built on the same base store and transfer it once. They are cached, so ordering instructions from least to most frequently changing makes rebuilds dramatically faster. And they are immutable, so a file added in one layer and deleted in a later one still occupies space and remains extractable from the image.

What is a Docker registry and is Docker Hub the only one?

A registry stores and distributes images, the way a Git host stores repositories. Docker Hub is the default, docker pull nginx with no prefix goes there, and hosts official images for most common software. It is not the only option, and most organisations push their own images to a private registry such as GitHub Container Registry, Amazon ECR, Google Artifact Registry or Azure Container Registry. Prefixing the image name with a hostname selects one: ghcr.io/acme/myapp:1.0.

Do I need Docker Compose or Kubernetes?

Compose if you are running several containers on one machine. A local development stack, a small single-server deployment. It defines services, networks and volumes in one file and starts them together, and it is the right tool most of the time. Kubernetes when you need containers scheduled across multiple machines with rolling updates, self-healing and autoscaling. They solve different problems, and starting with Compose costs nothing if you later move: the concepts transfer directly.

Why can't my container reach another container on localhost?

Because localhost inside a container refers to that container and nothing else. Each one has its own network namespace and its own loopback interface. Put both on the same user-defined network and use the container name as the hostname: docker network create appnet, start each with --network appnet, then connect to db:5432. Compose does this for you automatically, which is why service names work as hostnames there without any configuration.

Continue Learning

Explore Related Topics

Try the Tool

Practise this in the browser

Docker Playground

Run the commands in a simulated terminal, no install needed.

When it breaks

Related Resources