Images vs containers
The single most important distinction in Docker, explained with a class-and-object analogy and real commands.
The distinction everything else builds on
If you only remember one thing from this module, make it this:
An image is a blueprint. A container is a running instance of that blueprint.
This is exactly like the relationship between a class and an object in programming, if you've done any OOP: a class defines the structure and behavior once, and you can create as many independent object instances from it as you want. Each object has its own state, but they all follow the same blueprint.
Docker images work the same way:
- An image is a read-only, packaged filesystem containing an application, its dependencies, and instructions for how to run it. It is built once and never changes.
- A container is a running (or stopped) instance created from an image — with its own writable layer, its own process, its own network address, its own lifecycle. You can create many containers from the same image, and they won't interfere with each other.
docker run nginx
Image: nginx ───────────────▶ Container A (running)
│ docker run nginx
└────────────────────────▶ Container B (running)
nginx image itself.
Where images come from
Images are built in layers. Each layer represents one step in the image's construction — installing a package, copying in application code, setting an environment variable. Layers stack on top of each other, and each layer only stores the changes from the layer below it (a technique enabled by the union filesystem mentioned back in the fundamentals module).
This layering has a genuinely practical benefit: layers are cached and shared. If two images both start from the same base layer (say,ubuntu:22.04), Docker only stores that base layer once on disk, and only re-downloads or rebuilds the layers that actually changed. This is why rebuilding an image after a tiny code change is usually near-instant — Docker reuses every unchanged layer from cache.
We'll write our own images with a Dockerfile in a later lesson. For now, all you need is that images either come pre-built from a registry (like Docker Hub) or you build them yourself from a Dockerfile.
Pulling and inspecting an image
Before you can run a container, Docker needs the image locally.docker pull downloads one explicitly (though docker run will also auto-pull if the image isn't already present):
docker pull nginx:latest
latest — is a tag. Tags let a single image name have multiple versions (nginx:1.25, nginx:1.27, nginx:latest). If you omit a tag, Docker assumes latest — but be careful: latest is just a convention for "the most recently pushed default tag," not a guarantee of the newest version, and relying on it in production is a common source of "it worked yesterday" bugs. Pin a specific version tag for anything beyond local experiments.
List every image sitting on your machine:
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest a1b2c3d4e5f6 2 weeks ago 187MB
Creating and managing containers
docker run creates a new container from an image and starts it:
docker run nginx
Ctrl+C. Two flags you'll use constantly:
docker run -d nginx # -d = detached, runs in the background
docker run -p 8080:80 nginx # -p = publish a port (host:container)
docker run -d -p 8080:80 --name my-web nginx # combine flags, name it
-p 8080:80 maps port 8080 on your host machine to port 80 inside the container (where nginx listens by default) — without it, the container's port is only reachable from inside its own network namespace, and you couldn't open it in a browser at all.
List running containers:
docker ps # running containers only
docker ps -a # all containers, including stopped ones
CONTAINER ID IMAGE COMMAND STATUS PORTS NAMES
7f2a9c1d4e3b nginx "/docker-entrypoint.…" Up 2 minutes 0.0.0.0:8080->80/tcp my-web
Stop, start, and remove containers by ID or name:
docker stop my-web
docker start my-web
docker rm my-web # removes a stopped container permanently
docker rm -f my-web # force-stop and remove in one step
A crucial habit: docker run creates a new container every time
A very common beginner mistake is running docker run nginx repeatedly, expecting it to reuse the same container. It doesn't — every docker run creates a brand-new container instance from the image. If you want to resume an existing (stopped) container, use docker start <name> instead. Running docker ps -a after a few days of experimenting and seeing a dozen stopped nginx containers piling up is a rite of passage — clean them up with docker rm, or the shortcut docker container prune to remove all stopped containers at once.
What's next
The next lesson covers the commands you'll reach for constantly while a container is running or misbehaving — logs, exec'ing into a shell inside it, and inspecting its details.