Docker Images vs Containers
Understand the key differences between Docker images and containers: images are read-only blueprints, containers are running instances. This lesson clarifies the mental model with a practical walkthrough, troubleshooting tips, and next steps.
Focus: docker images vs containers
Have you ever run docker run and wondered whether you're working with an image or a container — or if there's even a difference? You're not alone. Even experienced developers sometimes blur the line between these two, leading to confusion about what gets saved, what gets reused, and what disappears when you stop a process. Let's clear it up once and for all.
The problem this lesson solves
When you start using Docker, commands like docker build, docker run, docker ps, and docker images come at you fast. You might run docker run and see a running application, then make changes and expect them to persist — only to find the next docker run starts from scratch. Or you might delete an image and panic because you think your running container is lost. These reactions happen because the mental boundary between an image and a container isn't obvious.
The core pain is this: you can't manage Docker effectively if you treat images and containers as the same thing. Every command you run, every Dockerfile you write, every troubleshooting session depends on understanding this distinction. Without it, you'll accidentally lose work, waste disk space, or struggle to debug production issues.
Core concept / mental model
Think of a Docker image as a read-only blueprint or a template. It's a snapshot of a filesystem, including your application code, runtime, libraries, and configuration — but it never runs on its own. An image is like a .iso file of an operating system installer: you can't use it until you boot it up.
A Docker container, on the other hand, is a running instance of that image. It's the actual process that executes your application. When you start a container, Docker takes the image — the blueprint — adds a thin read-write layer on top, and launches your application inside that environment. Think of a container as a house built from the blueprint: you can live in it, modify the interior (the writable layer), and even tear it down and rebuild it from the same blueprint.
Pro tip: The classic analogy is "image = class, container = instance" from object-oriented programming. An image defines the structure and defaults; a container is a concrete, running object with its own state.
| Aspect | Docker Image | Docker Container |
|---|---|---|
| Nature | Read-only template | Running instance |
| Persistence | Immutable (unless rebuilt) | Ephemeral (state is in writable layer) |
| Lifecycle | Stored on disk or registry | Created, started, stopped, removed |
| Purpose | Distribution, reuse | Execution |
How it works step by step
- Define an image with a Dockerfile — You write a set of instructions (like
FROM,RUN,COPY) that describe exactly what goes into the image. - Build the image — Run
docker build -t my-app .. Docker executes the Dockerfile line by line, creating a read-only layer for each instruction. The result is a cached, reusable artifact. - Start a container from that image — Run
docker run my-app. Docker takes the image, creates a new read-write layer (the container layer) on top, and starts the process defined in theCMDorENTRYPOINT. - The container runs — changes happen in the writable layer — Your application writes logs, modifies files, or creates temporary data. These changes live only in the container layer, not in the image.
- Stop or remove the container — When you stop the container, the writable layer is preserved on disk (unless you pass
--rm). When you remove the container, that writable layer is gone forever — but the image remains safe. - Share or deploy the image — You push the image to a registry (e.g., Docker Hub). Someone else pulls it and runs their own containers. They start exactly where you started, not with your local modifications.
Common mental model: An image is the template; a container is the instance. You can have many containers from one image, each with different runtime state.
Hands-on walkthrough
Let's make this concrete. Fire up your terminal and follow along.
1. Pull a public image
docker pull alpine:latest
This downloads the image to your local cache. It does not create a container yet.
2. List images
docker images
Output (simplified):
REPOSITORY TAG IMAGE ID CREATED SIZE
alpine latest 04ee...f6b3 2 weeks ago 7.34MB
That's your blueprint.
3. Create and run a container
docker run --name my-first-container alpine echo "Hello from inside a container"
Output:
Hello from inside a container
What happened? Docker took the alpine:latest image, created a new container called my-first-container, ran the echo command, and exited.
4. See the container (even after it exits)
docker ps -a
Output:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0a1b... 04ee...f6b3 "echo 'Hello from i..." 1 minute ago Exited (0) my-first-container
Notice: status is "Exited" — the container exists but is not running.
5. Run another container from the same image
docker run alpine echo "Another container, clean slate"
This creates a brand-new container — it starts from the same image, not from any changes you made in the first container.
6. Clean up
docker rm my-first-container
docker rmi alpine:latest
The first removes the container (writable layer deleted). The second removes the image (blueprint deleted only after no container references it).
Compare options / when to choose what
| Use Case | Use Image | Use Container |
|---|---|---|
| Distribution | Push image to registry; others pull it | Never push a container — it's volatile |
| Testing changes | Rebuild image after Dockerfile edits | Run container, test, then docker rm |
| Persisting data | Image is read-only — use volumes or bind mounts | Container's writable layer is ephemeral |
| Debugging | Inspect image layers with docker history |
Get a shell in a running container (docker exec -it) |
| Saving state | Commit a container to a new image (docker commit) only for quick snapshots |
Prefer volumes or Dockerfile for reproducibility |
When should you rebuild the image versus modify a running container?
- Rebuild the image — always, for production. This creates a reproducible, versioned artifact.
- Modify a running container — only for quick experiments or debugging. Once you stop the container, changes are lost unless you commit or use volumes.
Troubleshooting & edge cases
"I deleted an image, but my container still runs!"
That's okay — the container uses a copy of the image's filesystem. The image can be deleted as long as no other containers reference it (by image ID or tag). The running container continues using its own snapshot of the layers.
"I modified a file inside a container, but when I start a new container, changes are gone"
Yes — that's expected. The writable layer is per-container. To persist changes, either:
- Use a volume (docker run -v /host/path:/container/path ...)
- Commit the container to a new image (docker commit CONTAINER_NAME new-image-name)
"I have multiple images with the same name but different tags — which does docker run use?"
If you don't specify a tag, Docker defaults to latest. Always use explicit tags (docker run my-app:1.0.0) to avoid confusion.
"docker image rm says 'image is being used by running container'"
Stop and remove the container first (docker stop <container> then docker rm <container>), or force removal (docker image rm -f IMAGE_NAME).
"My image is huge, but containers should be lightweight — what gives?"
The image size includes all layers. When you run a container, Docker mounts these layers as read-only and adds a thin read-write layer. The container overhead is just that thin layer (a few KB), but the total footprint on disk includes the underlying image layers. To reduce size, use multi-stage builds and slim base images.
What you learned & what's next
You now understand the fundamental distinction at the heart of Docker: images are read-only blueprints for building, sharing, and versioning your application, while containers are running instances of those blueprints — ephemeral, writable, and tied to a specific execution.
You learned: - How to pull, list, and remove images - How to create, run, stop, and remove containers - That changes inside a container live only in the writable layer (and are lost when the container is removed, unless committed) - When to choose an image vs a container for distribution, persistence, or debugging
What's next? In the next lesson, you'll learn how to manage container state and data — specifically, how to use volumes and bind mounts so that data survives container restarts and removals. You'll combine your understanding of images and containers with persistent storage to build real-world applications with confidence.
Practice recap
Try this mini exercise: Pull the nginx image (docker pull nginx), run a container (docker run --name nginx-test -d nginx), then create a small HTML file inside the container (docker exec -it nginx-test bash and echo '<h1>Hello</h1>' > /usr/share/nginx/html/index.html). Visit http://localhost to see your modified content. Now stop and remove that container (docker rm -f nginx-test). Run another container from the same image — notice the original nginx welcome page is back. The changes were in the container's writable layer, not the image.
Common mistakes
- Thinking that stopping a container destroys its writable layer — actually, the container stays on disk (with its layer) until you
docker rmit. - Confusing
docker images(list of blueprints) withdocker ps(list of running or stopped containers). - Expecting changes made inside a container to appear in a new container started from the same image — they don't; the writable layer is per-container.
- Deleting an image while a container created from it is still running — Docker allows this, but it can confuse beginners when they later try to run matching containers.
Variations
- Use
docker committo save a container's modified state as a new image — useful for quick snapshots but not recommended for production pipelines. - Alternative terminology: some resources call images 'build artifacts' and containers 'runtime environments'.
- In Kubernetes, the distinction blurs slightly because Pods wrap containers, but the image vs container concept remains the same.
Real-world use cases
- Deploying microservices: each service is built as an image and pushed to a registry; production clusters pull the image and run hundreds of containers from it.
- CI/CD pipelines: a build step creates an image with tests and application code; subsequent pipeline stages run containers from that image for integration tests.
- Data science workflows: an image defines the environment (Python, libraries, Jupyter), and each data scientist runs their own container with unique notebooks.
Key takeaways
- Docker images are read-only blueprints; containers are running instances of those blueprints with a thin writable layer.
- You can have many containers from one image, each with its own state, and changes inside a container are lost upon removal unless committed or persisted via volumes.
- Image lifecycle: build, store, share. Container lifecycle: create, start, stop, remove. They are distinct objects managed by separate Docker commands.
- Use
docker imagesto see locally stored images anddocker ps -ato see all containers (running or stopped). - For production, always rebuild and redeploy an image rather than modifying a running container — this ensures reproducibility.
- Deleting an image does not stop running containers; they continue using a copy of the image's filesystem.
Keep learning
Related tutorials, quizzes, and articles for this topic.
Discussion
Questions, corrections, and tips help everyone reading this page.
0 comments
Add a comment
No comments yet — start the thread.