21.3. Images
Table of Contents
What Is a Docker Image?
A Docker image is a read-only template that contains everything needed to run a piece of software: code, runtime, libraries, system tools, and configuration.
When you start an image, Docker creates a container from it. You can think of:
- Image as a class in object-oriented programming.
- Container as an instance of that class.
You build an image once, then run it many times to create many containers.
Common examples:
python:3.12-slimimage used to run Python scripts.postgres:16image used to run a PostgreSQL database server.- Your own
my-api:1.0.0image used to run your backend API in production.
Important rule:
You never modify a running image.
You modify the container, then if you want to keep those changes, you build a new image.
Image Layers and Union Filesystem
How layering works
Docker images are built in layers. Each instruction in a Dockerfile typically creates a new layer:
- One layer might add system packages.
- Another layer might install Python dependencies.
- Another layer might copy your application code.
These layers stack on top of each other using a union filesystem. To Docker and to your app, they look like a single filesystem.
Example Dockerfile snippet:
FROM python:3.12-slim # Layer 1
RUN apt-get update # Layer 2
RUN pip install fastapi # Layer 3
COPY . /app # Layer 4This creates an image composed of 4 layers.
Why layers are useful
Layers give three big advantages:
- Caching builds
If only your code changes, Docker can reuse the base layers:
- It reuses the base
python:3.12-slimlayer. - It reuses the
apt-getandpip installlayers. - It only rebuilds the
COPY . /applayer.
This makes rebuilds much faster.
- Sharing between images
Different images can share common layers.
For example, my-api:1.0 and my-api:1.1 can both reuse the same base Python layer and dependency layer.
- Smaller downloads
When pulling a new image from a registry, Docker only downloads layers it does not already have.
Read-only vs writable layers
- Image layers are read-only.
- When you run a container from an image, Docker adds a thin writable layer on top.
Inside the container, this looks like a normal filesystem. But under the hood:
- Changes you make only exist in the writable layer.
- When the container stops, that layer is deleted (unless you commit or use volumes, which you will see later).
Table summary:
| Concept | Type | Lifetime |
|---|---|---|
| Image layer | Read-only | Persistent until you delete image |
| Container writable | Writable | Exists only while container exists |
Image Tags and Naming
Image name format
Images live in registries (like Docker Hub) and have a full name:
[registry/]repository[:tag]
Examples:
| Full name | Meaning |
|---|---|
python | repo python on Docker Hub, default tag latest |
python:3.10 | repo python, tag 3.10 |
myuser/my-api:1.0.0 | repo myuser/my-api, tag 1.0.0 |
ghcr.io/myorg/app:prod | registry ghcr.io, repo myorg/app, tag prod |
If you omit the tag, Docker uses :latest.
Important rule:
Do not rely on :latest in production.
Always use a specific tag like :1.0.3 so you know exactly which version you are running.
What is a tag?
A tag is just a label that points to a specific image.
- Many tags can point to the same image.
- You can retag an image without changing its contents.
Example:
# Build a local image
docker build -t my-api:1.0.0 .
# Tag the same image as "latest"
docker tag my-api:1.0.0 my-api:latest
# Now both tags point to the same image ID
docker images my-apiOutput (simplified):
REPOSITORY TAG IMAGE ID
my-api latest 123abc...
my-api 1.0.0 123abc...Inspecting and Managing Images
Listing images
To see all images on your machine:
docker images
# or
docker image lsExample output:
REPOSITORY TAG IMAGE ID CREATED SIZE
python 3.12 f8e1c1234abc 2 weeks ago 1.1GB
my-api 1.0.0 a7d9e8765def 5 minutes ago 350MB
postgres 16 9b2cdef12345 3 days ago 400MBKey columns:
- REPOSITORY the image name without tag.
- TAG version label.
- IMAGE ID unique identifier of the image content.
- SIZE total size of all layers.
Inspecting image details
If you need deep details about an image:
docker inspect my-api:1.0.0You will see JSON output that includes:
- Environment variables set in the image.
- Default command and entrypoint.
- Exposed ports.
- Layer information.
You can also inspect by image ID:
docker inspect a7d9e8765defChecking image history
To see which instructions created which layers:
docker history my-api:1.0.0Example output (simplified):
IMAGE CREATED CREATED BY
a7d9e8765def 5 minutes ago COPY . /app
a1b2c3d4e5f6 6 minutes ago RUN pip install -r requirements.txt
...This helps you understand:
- Which lines in your Dockerfile created large layers.
- Where you might optimize the image.
Building, Pulling, and Pushing Images
Building an image from a Dockerfile
If you have a Dockerfile in the current directory:
docker build -t my-api:1.0.0 .Explanation:
buildtells Docker to build an image.-t my-api:1.0.0sets the image name and tag..is the build context, usually your project directory.
Common pattern for backend services:
docker build -t myuser/task-api:0.1.0 .Then run it:
docker run --rm -p 8000:8000 myuser/task-api:0.1.0Pulling images
To download an image from a registry (often Docker Hub):
docker pull python:3.12-slim
docker pull postgres:16If you try to run a container from an image that is not present locally, Docker will attempt to pull it automatically:
docker run -it --rm alpine sh
# If "alpine" is not present, Docker pulls it firstPushing your own images
To share your image or deploy it to another machine, you push it to a registry.
Basic steps with Docker Hub:
- Create a repository on Docker Hub (for example
myuser/task-api). - Log in from the command line:
docker login- Tag your image with the full repository name:
docker tag my-api:0.1.0 myuser/task-api:0.1.0- Push the image:
docker push myuser/task-api:0.1.0On a server, you can then pull and run:
docker pull myuser/task-api:0.1.0
docker run -d -p 80:8000 myuser/task-api:0.1.0Cleaning Up Images and Disk Space
Images and layers can take a lot of disk space, especially during backend development where you rebuild often.
Removing a single image
To remove an image:
docker rmi my-api:0.1.0
# or by image ID
docker rmi a7d9e8765defIf Docker says the image is in use by a container, remove the container first:
docker ps -a # find the container
docker rm <container-id>
docker rmi my-api:0.1.0Removing unused images
To remove dangling images (images without tags, usually leftovers from builds):
docker image pruneDocker will ask for confirmation.
To remove all unused images, not just dangling ones:
docker image prune -a
Important rule:
docker image prune -a removes all images not used by any container.
Be careful, you might need to rebuild or re-pull them later.
Cleaning everything
To reclaim space from containers, networks, and images:
docker system prune
# more aggressive:
docker system prune -aThese commands are helpful on development machines after many experiments.
Practical Examples for Backend Developers
Example 1: Using an official image as a base
You want to create a FastAPI backend image using Python 3.12 slim:
FROM python:3.12-slim # base image
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]Build and tag:
docker build -t myuser/fastapi-backend:0.1.0 .Run:
docker run --rm -p 8000:8000 myuser/fastapi-backend:0.1.0Example 2: Versioning your backend image
You can use tags to track versions:
# First version
docker build -t myuser/task-api:0.1.0 .
# After changes
docker build -t myuser/task-api:0.2.0 .Now you can run either:
docker run -d --name task-api-v1 myuser/task-api:0.1.0
docker run -d --name task-api-v2 myuser/task-api:0.2.0This is very helpful when:
- Testing new versions without deleting the old one.
- Rolling back if a new version has bugs.
Example 3: Testing with a database image
You can quickly start a PostgreSQL database using an image:
docker pull postgres:16
docker run -d \
--name my-postgres \
-e POSTGRES_PASSWORD=secret \
-p 5432:5432 \
postgres:16Your backend can connect to this local database for development or tests.
Summary
- A Docker image is a read-only template used to create containers.
- Images are built from layers, which come from Dockerfile instructions.
- Tags like
:1.0.0and:latestare labels that point to specific image versions. - Use
docker build,docker pull, anddocker pushto work with images in development and deployment. - Use
docker images,docker inspect, anddocker historyto understand what is inside an image. - Clean up with
docker rmi,docker image prune, anddocker system pruneto save disk space.
Understanding images is essential for packaging and shipping backend applications in a consistent, reproducible way.
Views: 6
KAHIBARO