Cybersecurity

Docker Images vs Containers Explained

Python Docker RAG SQL Injection XSS SQL
1,293 words Includes Code

Docker Images vs Containers Explained

One is a blueprint. The other is a running instance. Understanding this difference eliminates 80% of Docker confusion.

KEY TAKEAWAY
A Docker image is a read-only blueprint containing your application, dependencies and configuration — like a class definition or a recipe. A Docker container is a running instance of that image with a writable layer on top — like an object or a prepared dish. You can run many containers from one image, and removing a container does not affect the image.

If you are new to Docker, the terms "image" and "container" are often used interchangeably in casual conversation. But they refer to fundamentally different things, and confusing them leads to misconceptions about data persistence, rebuild behavior and debugging.

This article explains the difference with simple diagrams, practical commands and a complete lifecycle walkthrough.

The Core Concept: Blueprint vs Instance

The simplest analogy: an image is a recipe, and a container is a prepared dish. You can cook many dishes from one recipe. Throwing away a dish does not affect the recipe.

Property Image Container
What it is Blueprint / template Running instance
State Read-only, immutable Writable layer added
Can run? No (it is a template) Yes (has a process)
Multiple copies Shared (same image) Independent instances
Persistence Permanent (until deleted) Ephemeral by default
Commands build, pull, push, rmi run, start, stop, rm
OOP Analogy Class definition Object / instance
Real Analogy Recipe Prepared dish

What Is a Docker Image?

An image is a read-only template stored on disk. It contains everything needed to run an application: the base operating system, application code, installed dependencies, configuration files and a default startup command.

Images are built in layers. Each instruction in a Dockerfile creates one layer:

FROM python:3.12-slim        # Layer 1: Base OS
WORKDIR /app                 # Layer 2: Directory
COPY requirements.txt .      # Layer 3: Dependencies
RUN pip install -r .         # Layer 4: Installed packages
COPY . .                     # Layer 5: Application code
CMD ["python", "main.py"]    # Layer 6: Startup command

Each layer is immutable and cached. If you change only the application code (Layer 5), Docker reuses Layers 1-4 from cache. This makes rebuilds fast.

Image Properties

  • Immutable — once built, the layers never change
  • Layered — each Dockerfile instruction = one layer
  • Shareable — push to a registry, pull anywhere
  • Versioned — tagged with name:version (e.g., myapp:v1)
  • Cached — unchanged layers are reused across builds

What Is a Docker Container?

A container is a running (or stopped) instance of an image. It takes the image's read-only layers and adds a writable layer on top where the process can create files, write logs and modify temporary data.

# One image, three containers
docker run -d --name web1 nginx
docker run -d --name web2 nginx
docker run -d --name web3 nginx

# All three share the same nginx image layers
# Each has its own writable layer and its own process

Containers are ephemeral by default. When you remove a container, its writable layer is destroyed. The image remains unchanged. This is by design — containers should be disposable.

Container Properties

  • Running process — has a PID, network, filesystem
  • Writable layer — changes go here, not to the image
  • Ephemeral — destroyed on removal (use volumes for persistence)
  • Multiple per image — run as many as you need

The Container Lifecycle

A container moves through states from creation to removal:

docker create / docker run      Created
         |
         v
docker start                    Running
         |
    +---------+-----------+
    |         |           |
    v         v           v
docker stop  docker pause  crash/error
    |         |           |
    v         v           v
 Stopped    Paused       Exited
    |         |
    v         v
docker start docker unpause
(restart)    (resume)
    |
    v
docker rm                  Removed (gone)
    |
    v
Image unchanged            Blueprint still on disk

State Transitions

Transition Command What Happens
Created → Running docker start Process begins executing
Running → Stopped docker stop SIGTERM then SIGKILL after timeout
Running → Paused docker pause Process frozen (cgroup freezer)
Stopped → Running docker start Restart the container
Any → Removed docker rm -f Force remove (stops if running)

Practical Example: Full Lifecycle

Here is a complete walkthrough using real Docker commands:

# Step 1: Pull an image (download the blueprint)
docker pull alpine:3.19
# Image now exists on disk — nothing is running

# Step 2: Create a container (not running yet)
docker create --name mybox alpine:3.19 echo "Hello"
# Container exists in CREATED state — process not started

# Step 3: Start the container
docker start mybox
# Process runs, prints "Hello", then exits

# Step 4: Check the state
docker ps -a --filter name=mybox
# Shows: mybox  alpine:3.19  Exited (0)  ...

# Step 5: Read the output
docker logs mybox
# Output: Hello

# Step 6: Remove the container
docker rm mybox
# Container removed. Image alpine:3.19 still on disk.

# The image is unchanged. You can create new containers from it:
docker run alpine:3.19 echo "Hello again"

Volumes: Persisting Data Beyond Containers

Since containers are ephemeral, data written inside them is lost on removal. Volumes solve this by mounting external storage into the container:

# Without volume (data lost on removal):
docker run --name db1 postgres
# ... write data ...
docker rm db1
# Data is GONE

# With named volume (data persists):
docker volume create pgdata
docker run -v pgdata:/var/lib/postgresql/data --name db2 postgres
# ... write data ...
docker rm db2
# Data is still in the pgdata volume

docker run -v pgdata:/var/lib/postgresql/data --name db3 postgres
# db3 has all of db2's data!

Image Layers and Caching

Understanding layers explains why Docker rebuilds are fast. Each layer is cached and shared between images:

# Dockerfile
FROM python:3.12-slim        # Layer 1 — cached
COPY requirements.txt .      # Layer 2 — cached
RUN pip install -r .         # Layer 3 — cached
COPY . .                     # Layer 4 — REBUILT (code changed)

# If only your code changed, Docker reuses layers 1-3 from cache.
# Only layer 4 is rebuilt. This makes docker build very fast.

Layers are shared across images. If two images use the same base layer, Docker stores it once on disk, saving space.

Quick Command Reference

Task Image Command Container Command
Create docker build -t app:v1 . docker run -d --name web app:v1
List docker images docker ps -a
Inspect docker history app:v1 docker logs web
Stop/Start N/A (images do not run) docker stop web / docker start web
Remove docker rmi app:v1 docker rm web
Shell into N/A docker exec -it web bash

Try It Yourself

Related BestWordz Articles

Further Reading

Conclusion

The image-versus-container distinction is the foundation of everything in Docker. An image is a read-only template with layered filesystem contents. A container is a running instance with a writable layer added on top. You build images, you run containers. Removing a container does not affect the image. Running multiple containers from one image gives each instance its own isolated process and filesystem.

Once you internalize this — blueprint versus instance, recipe versus dish, class versus object — the rest of Docker (volumes, networks, Compose, orchestration) becomes much easier to reason about.

BOTTOM LINE
Images are blueprints. Containers are instances. You build images with docker build, run containers with docker run. Changing a container does not change the image. Removing a container does not remove the image.

Try the JSON Formatter

Put what you've learned into practice with this free BestWordz tool.

Open Tool →

💬 Discuss on BestWordz Community

Join the conversation about Python, Docker, RAG on the BestWordz Community forum.

Visit Forum →