What is Docker, and what problem does it solve?
Quick Answer
Docker is a platform for packaging an application together with everything it needs to run — code, runtime, libraries, system tools — into a single, portable image, and running that image as an isolated, lightweight container. It solves "works on my machine": the exact same image runs identically on a developer's laptop, a CI runner, and a production server, because the image bundles the application's whole runtime environment rather than depending on whatever happens to already be installed on the host.
Detailed Answer
The problem before containers
Deploying an application traditionally meant hoping the target machine had the right language runtime version, the right system libraries, and no conflicting versions of anything else already installed. The phrase "it works on my machine" became common for exactly this reason: a developer's laptop, a QA server, and production rarely had identical environments. Subtle mismatches, such as a different OpenSSL version or a missing system package, caused failures that were maddening to reproduce and debug.
What Docker packages together
A Docker image bundles:
- The application's own code
- The specific language runtime/interpreter version it needs
- Every library and system dependency it depends on
- Configuration and environment setup
FROM node:20-slim
WORKDIR /app
COPY package.json .
RUN npm install
COPY . .
CMD ["node", "server.js"]
Building this once produces a single artifact that contains everything needed to run the application — no more "make sure Node 20 and these specific npm packages are installed on the server first."
Images vs. containers, briefly (covered fully in the next question)
The image is the packaged, immutable artifact. A container is a running instance of that image, isolated from other processes on the host via Linux kernel features (namespaces and cgroups — see that question). It shares the host's kernel rather than virtualizing an entire separate operating system.
Why this matters practically
docker run myapp:1.0
Running this exact command, with this exact image, produces the exact same running environment whether it's executed on a developer's laptop, a CI server, or production. The image is the single source of truth for "what the application needs to run," eliminating an entire class of environment-mismatch bugs. This also makes deployment portable across infrastructure: the same image can run on a bare-metal server, a cloud VM, or be scheduled by an orchestrator like Kubernetes (see that stack), without rebuilding anything for each target.
Beyond consistency: additional benefits
- Isolation — a container's process, filesystem, and network namespace are separated from the host and from other containers, so one application's dependencies can't silently conflict with another's. For example, two apps needing different, incompatible versions of the same library can run side by side, each in its own container, with no conflict.
- Efficiency relative to virtual machines — containers share the host's kernel rather than each running a full separate OS, making them dramatically lighter-weight to start and to run many of them side by side (see the VM comparison question for the full contrast).
- A standard packaging and distribution format — images can be pushed to and pulled from a registry (see that topic), giving teams a consistent way to share, version, and deploy applications.
The core mental model
Docker essentially answers: "how do I package an application so it carries its own environment with it, and run that package in a way that's isolated from everything else on the machine, without the overhead of a full virtual machine per application?" Every other Docker concept — images, layers, volumes, networks — exists in service of that core idea.