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.
| Component | Role | Notes |
|---|---|---|
| Docker CLI | Command-line client | Talks to the daemon over a socket or API |
| Docker Engine (dockerd) | Manages images, containers, networks and volumes | Runs as a background daemon |
| containerd and runc | Container lifecycle and process creation | Also used independently by Kubernetes |
| BuildKit | Builds images from Dockerfiles | Parallel steps and build caching |
| Docker Compose | Defines multi-container applications in YAML | Common for development stacks |
| Container registry | Stores and distributes images | Docker Hub or private registries |
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.
| Object | What it is | Persistence |
|---|---|---|
| Image | Read-only template made of layers | Immutable, identified by a digest |
| Container | A running or stopped instance of an image | Writable layer lost on removal |
| Volume | Storage managed by Docker outside the container | Survives container removal |
| Bind mount | A host directory mapped into a container | Lives on the host filesystem |
| Network | Bridge, host, overlay or none | Defines how containers communicate |
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 compared with related tools
Docker is one tool in the container landscape, and several neighboring tools overlap with or build on its functions.
| Technology | Main purpose | Relation to Docker |
|---|---|---|
| Virtual machine | Virtualizes full hardware with its own kernel | Heavier isolation; Docker often runs inside VMs |
| Podman | Daemonless, rootless container engine | Largely compatible CLI and images |
| Kubernetes | Orchestrates containers across many nodes | Runs OCI images built by Docker, via containerd |
| Docker Compose | Runs several containers on one host | Part of the Docker toolset |
| Docker Swarm | Built-in clustering mode | Simpler than Kubernetes, less widely adopted |
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.
| Practice | Effect | Typical result |
|---|---|---|
| Multi-stage builds | Leaves compilers and build tools out of the final image | Images often shrink from hundreds of MB to tens |
| Slim or distroless base images | Fewer packages to patch | Smaller vulnerability surface |
| Ordering layers by change frequency | Dependencies are cached between builds | Rebuilds in seconds instead of minutes |
| Non-root user | Limits damage if the process is compromised | Safer default at runtime |
| .dockerignore file | Keeps secrets and junk out of the build context | Faster, cleaner builds |
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.