Understanding Docker Images
Docker images are the foundation of containers. Understanding how images work helps you make better decisions about building and managing your containerized applications.
What is a Docker Image?
A Docker image is a read-only template containing:
- A base operating system (often minimal, like Alpine Linux)
- Application code and dependencies
- Configuration files
- Environment variables
- Instructions for running the application
Images are used to create containers. You can think of an image as a class and a container as an instance of that class.
Image Layers
Images are built in layers. Each layer represents a set of filesystem changes:
┌─────────────────────────┐
│ Layer 5: ENTRYPOINT │ ← Sets default command
├─────────────────────────┤
│ Layer 4: COPY app │ ← Adds application code
├─────────────────────────┤
│ Layer 3: npm install │ ← Installs dependencies
├─────────────────────────┤
│ Layer 2: WORKDIR │ ← Sets working directory
├─────────────────────────┤
│ Layer 1: node:18 │ ← Base image with Node.js
└─────────────────────────┘
Benefits of Layers
- Caching: Unchanged layers are cached and reused
- Sharing: Multiple images can share common layers
- Efficiency: Only changed layers are transferred
- Version control: Each layer has a unique ID
Image Naming Convention
Docker images follow a naming convention:
[registry/][repository/]name[:tag][@digest]
Examples:
nginx # Official image, latest tag
nginx:1.25 # Official image, specific version
mycompany/myapp:v1.0 # User/org repository
gcr.io/myproject/myapp:latest # Private registry
nginx@sha256:abc123... # Image by digest
Understanding Tags
Tags are labels for different versions of an image:
| Tag Pattern | Meaning |
|---|---|
latest | Most recent version (default) |
1.25 | Major.minor version |
1.25.3 | Specific version |
alpine | Alpine Linux variant |
slim | Smaller image variant |
bullseye | Debian Bullseye base |
# These all refer to the same image name with different tags
node:latest
node:18
node:18.19
node:18-alpine
node:18-slim
Viewing Local Images
# List all images
docker images
# Alternative command
docker image ls
# Example output:
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest a6bd71f48f68 2 days ago 187MB
node 18 b3db67c7d3a3 5 days ago 1.1GB
postgres 15 ceccf204404e 1 week ago 379MB
# Show all images (including intermediate layers)
docker images -a
# Show only image IDs
docker images -q
# Filter images
docker images --filter "dangling=true"
docker images --filter "reference=node"
Image Digests
Each image has a unique SHA256 digest that never changes:
# Show digests
docker images --digests
# Pull by digest (guarantees exact version)
docker pull nginx@sha256:a8281ce42034b078dc7d88a5bfe6406a6cf1439df5c9f8fdd3d7b7645ee77fca
Using digests ensures you get the exact same image every time, even if the tag is updated.
Image Size
Understanding image size helps optimize storage and transfer times:
# View image sizes
docker images
# Detailed size info
docker system df -v
# Analyze image layers
docker history nginx
What Contributes to Image Size
- Base image: The starting point (ubuntu: ~77MB, alpine: ~5MB)
- Dependencies: Libraries and packages installed
- Application code: Your actual application
- Build artifacts: Leftover files from installation
Image Internals
View the layers that make up an image:
# Show image history
docker history nginx
# Example output:
IMAGE CREATED CREATED BY SIZE
a6bd71f48f68 2 days ago /bin/sh -c #(nop) CMD ["nginx" "-g" "daem… 0B
<missing> 2 days ago /bin/sh -c #(nop) STOPSIGNAL SIGQUIT 0B
<missing> 2 days ago /bin/sh -c #(nop) EXPOSE 80 0B
<missing> 2 days ago /bin/sh -c #(nop) ENTRYPOINT ["/docker-en… 0B
<missing> 2 days ago /bin/sh -c set -x && groupadd --system … 112MB
Image vs Container Filesystem
┌─────────────────────────────────────────┐
│ Container (runtime) │
│ ┌─────────────────────────────────┐ │
│ │ Writable Container Layer │ │ ← Changes here
│ └─────────────────────────────────┘ │
│ ┌─────────────────────────────────┐ │
│ │ Image Layer 3 (R/O) │ │
│ ├─────────────────────────────────┤ │
│ │ Image Layer 2 (R/O) │ │ ← Read-only
│ ├─────────────────────────────────┤ │
│ │ Image Layer 1 (R/O) │ │
│ └─────────────────────────────────┘ │
└─────────────────────────────────────────┘
When you modify a file in a container:
- Docker copies the file to the writable layer (copy-on-write)
- The original file in the image layer remains unchanged
- Multiple containers share the same image layers
Inspecting Images
Get detailed information about an image:
# Full image metadata (JSON)
docker inspect nginx
# Specific fields
docker inspect -f '{{.Config.Cmd}}' nginx
docker inspect -f '{{.Config.Env}}' nginx
docker inspect -f '{{.Config.ExposedPorts}}' nginx
# Image architecture
docker inspect -f '{{.Architecture}}' nginx
# Image creation date
docker inspect -f '{{.Created}}' nginx
Image Manifest
Multi-architecture images contain manifests pointing to platform-specific versions:
# View manifest (requires experimental CLI features)
docker manifest inspect nginx
# The image automatically selects the correct platform:
# - linux/amd64 for Intel/AMD processors
# - linux/arm64 for Apple Silicon, ARM servers
Official vs Community Images
Official Images
- Maintained by Docker or the software vendor
- No username prefix:
nginx,postgres,node - Regularly updated and scanned for vulnerabilities
- Best practices followed
Community Images
- Created by individuals or organizations
- Include username:
myuser/myapp,company/product - Quality varies
- May not be regularly maintained
Key Takeaways
- Images are read-only templates built in layers
- Layers enable caching, sharing, and efficient storage
- Tags identify different versions; digests ensure exact versions
- The
latesttag doesn't always mean the newest version - Use official images when available
- Inspect images to understand their configuration
- Image size impacts pull times and storage costs

