Docker

On this page 7

Docker is an open-source platform and toolset for building, distributing and running containers, which package an application together with its libraries, runtime and configuration into a portable image that runs the same way on a laptop, a server or a cloud cluster. Among containers, Docker is the tool that made the technology mainstream after its release in 2013, and its image format became the basis of the OCI standards that other tools now follow.

Docker does not virtualize hardware. Containers it starts are ordinary Linux processes isolated by kernel namespaces and limited by control groups, so they start in well under a second and share the host kernel. The name refers both to the Docker Engine that runs containers and to the wider ecosystem of the Docker CLI, Dockerfile, Docker Compose and the Docker Hub registry.

How Docker builds and runs containers

A developer describes the image in a Dockerfile, a text file of build instructions such as the base image, files to copy and commands to run. The docker build command executes these steps with the BuildKit builder and produces an image made of read-only layers, one for each filesystem-changing instruction.

The docker run command asks the Docker daemon, dockerd, to start a container. The daemon delegates to containerd, which uses the low-level runtime runc to create namespaces and cgroups, mount the image layers through a union filesystem such as overlay2 and add a thin writable layer on top. When the container is removed, that writable layer disappears unless data was placed in a volume.

The table lists the main components and their roles.

ComponentRoleNotes
Docker CLICommand-line clientTalks to the daemon over a socket or API
Docker Engine (dockerd)Manages images, containers, networks and volumesRuns as a background daemon
containerd and runcContainer lifecycle and process creationAlso used independently by Kubernetes
BuildKitBuilds images from DockerfilesParallel steps and build caching
Docker ComposeDefines multi-container applications in YAMLCommon for development stacks
Container registryStores and distributes imagesDocker Hub or private registries
Main components of the Docker platform

Core Docker objects

Working with Docker means working with a small set of objects. Understanding which are immutable and which hold state prevents most beginner mistakes.

ObjectWhat it isPersistence
ImageRead-only template made of layersImmutable, identified by a digest
ContainerA running or stopped instance of an imageWritable layer lost on removal
VolumeStorage managed by Docker outside the containerSurvives container removal
Bind mountA host directory mapped into a containerLives on the host filesystem
NetworkBridge, host, overlay or noneDefines how containers communicate
Docker objects and their persistence

Images are referenced by tag, such as nginx:1.27, or by content digest. Tags can be moved to a new image, whereas a digest always identifies exactly the same content, which is why production deployments often pin images by digest.

Docker is one tool in the container landscape, and several neighboring tools overlap with or build on its functions.

TechnologyMain purposeRelation to Docker
Virtual machineVirtualizes full hardware with its own kernelHeavier isolation; Docker often runs inside VMs
PodmanDaemonless, rootless container engineLargely compatible CLI and images
KubernetesOrchestrates containers across many nodesRuns OCI images built by Docker, via containerd
Docker ComposeRuns several containers on one hostPart of the Docker toolset
Docker SwarmBuilt-in clustering modeSimpler than Kubernetes, less widely adopted
Docker and neighboring technologies

Kubernetes removed its built-in Docker integration in version 1.24, but this changed little in practice: images built with Docker remain standard OCI images that Kubernetes runs through containerd or CRI-O.

Practical guidance for Docker images

Image quality determines build speed, security and deployment size. The following choices have the largest effect.

PracticeEffectTypical result
Multi-stage buildsLeaves compilers and build tools out of the final imageImages often shrink from hundreds of MB to tens
Slim or distroless base imagesFewer packages to patchSmaller vulnerability surface
Ordering layers by change frequencyDependencies are cached between buildsRebuilds in seconds instead of minutes
Non-root userLimits damage if the process is compromisedSafer default at runtime
.dockerignore fileKeeps secrets and junk out of the build contextFaster, cleaner builds
Image practices and their effect

At runtime, containers should receive explicit memory and CPU limits, because an unlimited container can consume the whole host. Each container should run one main process that writes logs to standard output, so that Docker can collect them and restart policies can react to failures. Images should also be scanned for known vulnerabilities and rebuilt regularly, since a base image that was clean at build time accumulates published security flaws over the following months.

Limitations and common mistakes

  • Shared kernel: containers are weaker isolation than virtual machines, so untrusted multi-tenant code needs extra hardening or VMs.
  • Data in the writable layer is lost when a container is replaced; databases need volumes.
  • Secrets baked into images stay readable in image layers even if a later step deletes them.
  • Floating tags such as latest make deployments unrepeatable.
  • Access to the Docker socket effectively grants root on the host and must be restricted.

The short version

Software often works on one computer and fails on another because something small differs, such as a library version. Docker solves this the way shipping containers solved freight: everything the application needs is packed into one standard box.

Any machine with Docker can open that box and run it, without installing anything else. The same box runs the same way everywhere, from a developer’s laptop to a large cloud server.

Where it makes a difference

A development team maintains a web application built on Node.js, PostgreSQL and Redis. New team members used to spend one or two days installing the right versions on their laptops, and bugs regularly appeared only in production because of version differences.

The team writes a multi-stage Dockerfile for the application and a Docker Compose file that starts all three services with one command. A new developer is now productive in under an hour. The build pipeline produces a single image, pins it by digest and deploys exactly the tested image to staging and production, and the class of environment-specific bugs largely disappears.