What Is Docker? Containers, Images & the Problem They Solve
Learn what Docker is and why it exists. Understand containers vs virtual machines, Docker images, the Docker daemon, and how Docker solves the 'works on my machine' problem.

"It works on my machine." Every developer has said it. The code runs fine locally but fails in staging, or breaks on a colleague's laptop because they have a different version of Node, Python, or a system library. Docker was built to eliminate this problem.
Docker is a platform for packaging, distributing, and running applications in containers — isolated, portable units that include everything the application needs to run. This lesson explains what Docker is, why containers exist, and how Docker differs from virtual machines.
The Problem Docker Solves
Modern applications depend on a precise combination of runtime versions, libraries, environment variables, and configuration. Getting that combination exactly right across development, staging, and production environments — and across team members' laptops — is surprisingly hard.
The traditional solution was documentation ("install Python 3.11, then pip install these packages, then set these environment variables..."). This is fragile, error-prone, and doesn't scale.
Docker's solution is to package the application together with its entire environment into a single, portable unit. That unit — a container — runs identically everywhere Docker is installed.
What Is a Container?
A container is an isolated process on the host machine. It has its own filesystem, its own network interface, its own process namespace — but it shares the host operating system's kernel.
Think of it like a self-contained apartment within a building. Each apartment (container) has its own interior (filesystem, dependencies, environment), but all apartments share the building's structural infrastructure (the OS kernel). This is fundamentally different from a virtual machine, which is more like having a separate building entirely.
What a Container Includes
- The application code
- The runtime (Node.js, Python, Java JDK, etc.) at a specific version
- All dependencies (npm packages, pip libraries, system packages)
- Environment variables and configuration
- A minimal filesystem layer
What a Container Does NOT Include
- A full operating system kernel
- A hypervisor
- Virtualised hardware
This is why containers start in milliseconds, use tens of megabytes instead of gigabytes, and can run dozens on a modest laptop.
Containers vs Virtual Machines
Both containers and VMs provide isolation, but they achieve it differently:
| Aspect | Container | Virtual Machine |
|---|---|---|
| Isolation level | Process / filesystem | Full hardware virtualisation |
| Startup time | Milliseconds | Minutes |
| Size | MBs | GBs |
| OS | Shares host kernel | Full guest OS |
| Performance overhead | Near-zero | Significant |
| Density | Hundreds per host | Tens per host |
| Security isolation | Good (namespaces + cgroups) | Stronger (hardware boundary) |
| Use case | Application packaging | Full OS isolation, legacy apps |
Containers and VMs are not mutually exclusive — in cloud environments, containers usually run inside VMs. Docker runs inside an EC2 instance or a GCE VM, combining both layers.
The Docker Architecture
Docker uses a client-server architecture:
Docker CLI (client)
|
| REST API
↓
Docker Daemon (dockerd) — runs on the host
|
├── Images (stored locally)
├── Containers (running processes)
├── Networks
└── VolumesDocker Daemon (dockerd)
The Docker daemon is a background service that manages all Docker objects — images, containers, networks, and volumes. It listens for Docker API requests.
Docker CLI
The command-line tool you type docker commands into. It communicates with the daemon via the Docker API. When you run docker run nginx, the CLI sends that instruction to the daemon, which does the actual work.
Docker Registry
A storage and distribution system for Docker images. Docker Hub is the default public registry — it hosts official images for thousands of popular software packages. You can also run private registries.
What Is a Docker Image?
A Docker image is a read-only template used to create containers. It's a layered filesystem snapshot: each layer represents a change to the filesystem (install a package, copy a file, set an environment variable).
Think of an image as a recipe and a container as the meal cooked from it. You can cook many meals from the same recipe; you can run many containers from the same image.
nginx:1.25 image layers:
Layer 4: COPY app files
Layer 3: RUN npm install
Layer 2: Install Node.js 20
Layer 1: Debian slim baseImages are immutable. You can't change a running image — you build a new one. This immutability is what guarantees containers run identically regardless of where or when they're started.
The Docker Workflow
The typical Docker workflow has four steps:
- Write a Dockerfile — instructions for building your image
- Build the image —
docker buildprocesses the Dockerfile and creates the image - Push to a registry —
docker pushuploads the image to Docker Hub or a private registry - Run containers —
docker runpulls the image and starts a container from it
# Build an image tagged "myapp:1.0"
docker build -t myapp:1.0 .
# Push to Docker Hub
docker push myusername/myapp:1.0
# Run a container from it
docker run -p 3000:3000 myusername/myapp:1.0In production, step 4 is typically handled by Kubernetes rather than running docker run manually.
Key Docker Concepts at a Glance
| Concept | Description |
|---|---|
| Image | Read-only blueprint for creating containers |
| Container | Running instance of an image |
| Dockerfile | Text file with build instructions |
| Registry | Storage for images (Docker Hub, ECR, GCR) |
| Layer | A filesystem change cached as part of an image |
| Volume | Persistent storage mounted into a container |
| Network | Virtual network connecting containers |
| Daemon | Background service managing Docker objects |
Why Docker Changed Everything
Before Docker (2013), deploying an application meant configuring servers manually, managing dependency conflicts, and hoping that "works on my machine" translated to "works in production." Configuration management tools (Chef, Puppet, Ansible) helped, but they operated at the machine level rather than the application level.
Docker shifted the packaging boundary from "the machine" to "the application." Once you containerise an app, it doesn't matter whether it's running on Ubuntu 20 or 22, on your MacBook or an EC2 instance — the container behaves identically.
This shift enabled microservices (each service runs in its own container with its own runtime and dependencies), CI/CD pipelines (build once, deploy the same image everywhere), infrastructure as code (Dockerfiles version-control your environment alongside your application), and ultimately Kubernetes (container orchestration at scale becomes possible when the unit of deployment is a portable image).
Next: Lesson 2 — How to Install Docker
Part of the Docker & Kubernetes Mastery course.
External references:
