Day 4: Understanding Docker Images
What You'll Learn Today
- What Docker images are
- The layer structure of images
- Image naming and tags
- Pulling images from Docker Hub
- Image management commands
What is a Docker Image?
A Docker image is a read-only template for creating containers. It contains everything needed to run an application.
flowchart TB
subgraph Image["Docker Image"]
OS["Base OS\n(e.g., Ubuntu)"]
Runtime["Runtime\n(e.g., Python)"]
Libs["Libraries\n(e.g., Flask)"]
App["Application\nCode"]
Config["Configuration"]
end
Image --> |"docker run"| Container1["Container 1"]
Image --> |"docker run"| Container2["Container 2"]
Image --> |"docker run"| Container3["Container 3"]
style Image fill:#3b82f6,color:#fff
style Container1 fill:#22c55e,color:#fff
style Container2 fill:#22c55e,color:#fff
style Container3 fill:#22c55e,color:#fff
What's Included in an Image
| Element | Description |
|---|---|
| Base OS | Minimal OS environment (Ubuntu, Alpine, etc.) |
| Runtime | Language execution environment (Python, Node.js, etc.) |
| Libraries | Packages needed by the app |
| Application | The actual code |
| Configuration | Environment variables, config files |
The Relationship Between Images and Containers
Images and containers are similar to the relationship between a class (blueprint) and an instance (object).
flowchart LR
subgraph ImageLayer["Image (Read-only)"]
direction TB
I1["Layer 1: Base OS"]
I2["Layer 2: Packages"]
I3["Layer 3: App"]
end
subgraph Container["Container"]
direction TB
C1["Layer 1: Base OS"]
C2["Layer 2: Packages"]
C3["Layer 3: App"]
RW["Writable Layer"]
end
ImageLayer --> |"docker run"| Container
style ImageLayer fill:#3b82f6,color:#fff
style RW fill:#f59e0b,color:#fff
- Image: Read-only, can be shared by multiple containers
- Container: Adds a writable layer on top of the image
Image Naming Conventions
Full Image Name Structure
[registry/][username/]image-name[:tag]
| Part | Description | Example |
|---|---|---|
| Registry | Where the image is stored | docker.io, ghcr.io |
| Username | Image owner | nginx, myuser |
| Image name | Name of the image | nginx, python |
| Tag | Version or variant | latest, 3.11, alpine |
Examples
# Official image (no username)
nginx
nginx:latest
nginx:1.25
# User's image
myuser/myapp:v1.0
# Different registry
ghcr.io/owner/image:tag
About Tags
Tags identify versions or variants of an image.
# Same image name, different versions via tags
python:3.11
python:3.10
python:3.11-slim # Lightweight version
python:3.11-alpine # Alpine Linux based
Important: The latest tag doesn't always mean "most recent." In production, specify explicit versions.
Image Layer Structure
Docker images consist of multiple layers. This enables efficient storage and fast builds.
flowchart TB
subgraph Image["Python Image"]
direction TB
L1["Layer 1\nDebian base"]
L2["Layer 2\nRequired libraries"]
L3["Layer 3\nPython installation"]
L4["Layer 4\npip installation"]
L1 --> L2 --> L3 --> L4
end
style L1 fill:#3b82f6,color:#fff
style L2 fill:#3b82f6,color:#fff
style L3 fill:#3b82f6,color:#fff
style L4 fill:#3b82f6,color:#fff
Layer Characteristics
- Read-only: Each layer is immutable
- Shareable: Same layers are shared across multiple images
- Cached: Unchanged layers are reused during builds
Layer Sharing Example
flowchart TB
subgraph Shared["Shared Layer"]
Base["Debian base"]
end
subgraph Python["Python Image"]
P1["Python"]
end
subgraph Node["Node.js Image"]
N1["Node.js"]
end
Base --> Python
Base --> Node
style Shared fill:#22c55e,color:#fff
style Python fill:#3b82f6,color:#fff
style Node fill:#f59e0b,color:#fff
The same base layer is downloaded only once and shared on disk.
Pulling Images: docker pull
Pull images from Docker Hub or other registries.
Basic Usage
# Pull latest version
docker pull nginx
# Specify a tag
docker pull nginx:1.25
# Pull from a specific registry
docker pull ghcr.io/owner/image:tag
Understanding Pull Output
$ docker pull nginx:1.25
1.25: Pulling from library/nginx
a2abf6c4d29d: Pull complete
a9edb18cadd1: Pull complete
589b7251471a: Pull complete
186b1aaa4aa6: Pull complete
b4df32aa5a72: Pull complete
a0bcbecc962e: Pull complete
Digest: sha256:0d17b565c37bcbd895e9d92315a05c1c3c9a29f762b011a10c54a66cd53c9b31
Status: Downloaded newer image for nginx:1.25
docker.io/library/nginx:1.25
| Item | Description |
|---|---|
a2abf6c4d29d: Pull complete |
Download status for each layer |
Digest |
Unique identifier for the image (SHA256) |
Status |
Download result |
Listing Images: docker images
List images available locally.
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx 1.25 a6bd71f48f68 2 weeks ago 187MB
nginx latest a6bd71f48f68 2 weeks ago 187MB
python 3.11 22140f8f7b81 3 weeks ago 1.01GB
ubuntu 22.04 3b418d7b466a 4 weeks ago 77.8MB
Understanding the Output Columns
| Column | Description |
|---|---|
| REPOSITORY | Image name |
| TAG | Tag |
| IMAGE ID | Unique image identifier |
| CREATED | When the image was created |
| SIZE | Image size |
Filtering
# Show only specific images
docker images nginx
# Show dangling images (no tag)
docker images -f dangling=true
Image Details: docker inspect
Get detailed image information in JSON format.
docker inspect nginx:1.25
Useful Examples
# Check image layers
docker inspect nginx:1.25 | grep -A 100 "Layers"
# Check environment variables
docker inspect -f '{{json .Config.Env}}' nginx:1.25 | jq
# Check CMD (default command)
docker inspect -f '{{json .Config.Cmd}}' nginx:1.25
Image History: docker history
See how an image was built.
$ docker history nginx:1.25
IMAGE CREATED CREATED BY SIZE
a6bd71f48f68 2 weeks ago CMD ["nginx" "-g" "daemon off;"] 0B
<missing> 2 weeks ago STOPSIGNAL SIGQUIT 0B
<missing> 2 weeks ago EXPOSE map[80/tcp:{}] 0B
<missing> 2 weeks ago ENTRYPOINT ["/docker-entrypoint.sh"] 0B
<missing> 2 weeks ago COPY 30-tune-worker-processes.sh ... 4.62kB 4.62kB
...
Each line corresponds to a Dockerfile instruction.
Removing Images: docker rmi
# Remove an image
docker rmi nginx:1.25
# Remove by image ID
docker rmi a6bd71f48f68
# Force removal
docker rmi -f nginx:1.25
Bulk Remove Unused Images
# Remove dangling images
docker image prune
# Remove all unused images
docker image prune -a
Exploring Docker Hub
Docker Hub is Docker's official image registry.
Official Images
Highly reliable images managed and verified by Docker.
# Official image examples
docker pull nginx
docker pull python
docker pull postgres
docker pull redis
Searching for Images
# Search via CLI
docker search python
# Example results
NAME DESCRIPTION STARS
python Python is an interpreted, interactive... 9280
pypy PyPy is a fast, compliant alternative... 365
Tips for Choosing Good Images
| Point | Description |
|---|---|
| Official Image | Has "Official Image" badge |
| Star count | Used by many people |
| Last updated | Recently updated |
| Documentation | Has comprehensive README |
Multi-Architecture Images
Modern images support multiple CPU architectures.
flowchart TB
subgraph Manifest["nginx:latest Manifest List"]
AMD["linux/amd64\n(Intel/AMD)"]
ARM["linux/arm64\n(Apple Silicon, AWS Graviton)"]
ARMV7["linux/arm/v7\n(Raspberry Pi)"]
end
User["docker pull nginx"] --> Manifest
Manifest --> |"Auto-select"| AMD
Manifest --> |"Auto-select"| ARM
Manifest --> |"Auto-select"| ARMV7
style Manifest fill:#3b82f6,color:#fff
docker pull automatically selects the appropriate architecture for your environment.
Understanding Image Size
Why Size Matters
- Download time: Larger images take longer to pull
- Storage: Consumes disk space
- Security: Larger images have more attack surface
Size Comparison
# Same language, big difference
python:3.11 # ~1GB
python:3.11-slim # ~150MB
python:3.11-alpine # ~50MB
Alpine-Based Images
Alpine Linux-based images are very lightweight.
# Comparison
ubuntu:22.04 # ~78MB
alpine:3.19 # ~7MB
Note: Alpine is lightweight but uses musl instead of glibc, which may cause compatibility issues with some applications.
Hands-On: Trying Various Images
Step 1: Compare Different Python Images
# Pull three variants
docker pull python:3.11
docker pull python:3.11-slim
docker pull python:3.11-alpine
# Compare sizes
docker images python
Step 2: Explore Inside the Images
# Start a shell in each image to explore
docker run -it python:3.11 bash
docker run -it python:3.11-slim bash
docker run -it python:3.11-alpine sh # Alpine doesn't have bash
Step 3: Compare Layer Differences
docker history python:3.11
docker history python:3.11-alpine
Summary
| Command | Description |
|---|---|
docker pull |
Pull image from registry |
docker images |
List local images |
docker inspect |
Show image details |
docker history |
Show image build history |
docker rmi |
Remove an image |
docker image prune |
Remove unused images |
Key Points
- Images are read-only and serve as blueprints for containers
- Images are composed of layers that are efficiently shared
- Use tags for versioning; prefer explicit tags over
latest - Official images are highly reliable
- Alpine-based images are lightweight but watch for compatibility
Practice Problems
Problem 1: Pulling Images
Pull the following images and compare their sizes:
node:20node:20-slimnode:20-alpine
Problem 2: Image Investigation
Pull the redis:latest image and find out:
- Image size
- Number of layers (using
docker history) - Default command (using
docker inspect)
Challenge Problem
Search Docker Hub for the official PostgreSQL image and research the available tag types (regular, Alpine, etc.). Consider what use cases each tag is suited for.
References
Next Up: In Day 5, we'll learn about "Creating Images with Dockerfiles." You'll master how to containerize your own applications.