Chapter 2: Docker Image Management
9/1/25About 7 min
Chapter 2: Docker Image Management
Learning Objectives
- Gain a deep understanding of the layered structure of Docker images
- Master the operations of pulling, viewing, and deleting images
- Learn to create custom images from containers
- Become proficient in using Docker Hub and private image registries
Knowledge Points
Docker Image Layered Structure
Docker images use a layered storage architecture, which is one of Docker's core designs. Each image is composed of multiple read-only layers, connected by pointers.
Advantages of Layered Storage:
- Storage Efficiency: The same layers can be shared among different images, saving disk space.
- Transmission Efficiency: Only missing layers need to be downloaded, speeding up image pulling.
- Caching Mechanism: Existing layers can be reused during builds, improving build efficiency.
Image Layering Example:
┌─────────────────────────────────┐
│ Application Layer (nginx:latest) │ ← Writable layer (during container runtime)
├─────────────────────────────────┤
│ Nginx Configuration Layer │ ← Read-only layer
├─────────────────────────────────┤
│ Nginx Program Layer │ ← Read-only layer
├─────────────────────────────────┤
│ Ubuntu Base System Layer │ ← Read-only layer
├─────────────────────────────────┤
│ Kernel Boot Layer │ ← Read-only layer
└─────────────────────────────────┘
Image Naming Convention
Docker images follow a specific naming convention: [registry]/[namespace]/[repository]:[tag]
Component | Description | Example |
---|---|---|
registry | Image registry address | docker.io, gcr.io |
namespace | Namespace/username | library, nginx, mycompany |
repository | Repository name | nginx, mysql, ubuntu |
tag | Tag version | latest, 1.20, stable |
# Full Image Name Example
docker.io/library/nginx:1.20 # Official nginx version 1.20
gcr.io/kubernetes-e2e-test-images/busybox:1.29 # busybox from Google's registry
myregistry.com/myteam/myapp:v1.0 # Application from a private registry
Image Storage Drivers
Docker supports multiple storage drivers to manage image layers:
Storage Driver | Applicable System | Features |
---|---|---|
overlay2 | Modern Linux | Optimal performance, recommended |
aufs | Older Ubuntu | Older technology, being phased out |
devicemapper | RHEL/CentOS | Enterprise features, complex configuration |
btrfs | Supports Btrfs filesystem | Advanced features, snapshot support |
# View the current storage driver
docker info | grep "Storage Driver"
# Example output
Storage Driver: overlay2
Basic Image Operations
Searching for Images
# Basic search
docker search nginx
docker search mysql
docker search python
# Advanced search options
docker search --limit 10 nginx # Limit the number of results
docker search --filter stars=100 nginx # Filter by stars
docker search --filter is-official=true nginx # Show only official images
docker search --filter is-automated=true nginx # Show only automated builds
# Format search results
docker search --format "table {{.Name}}\t{{.Stars}}\t{{.Official}}" nginx
Pulling Images
# Pull the latest version
docker pull nginx # Equivalent to docker pull nginx:latest
docker pull ubuntu # Pull the latest version of Ubuntu
# Pull a specific version
docker pull nginx:1.20 # Pull nginx version 1.20
docker pull mysql:8.0 # Pull MySQL version 8.0
docker pull python:3.9-alpine # Pull Python 3.9 Alpine version
# Pull an image for a specific platform
docker pull --platform linux/amd64 nginx:latest # Specify platform architecture
docker pull --platform linux/arm64 nginx:latest # ARM64 architecture
# Pull all tags
docker pull -a nginx # Pull all tags from the nginx repository (use with caution)
# View pull progress
docker pull nginx:latest
# Example output:
# latest: Pulling from library/nginx
# b4d181a07f80: Pull complete
# 66b1c490df3f: Pull complete
# d0f91ae9b44c: Pull complete
Viewing Local Images
# List all images
docker images
docker image ls # Same as above, new syntax
# View a specific image
docker images nginx # Show only nginx-related images
docker images nginx:1.20 # Show a specific version
# Formatted output
docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}\t{{.CreatedSince}}"
# Show image digests
docker images --digests # Show image digest information
# Show intermediate layer images
docker images -a # Show all images, including intermediate layers
# Filter images
docker images --filter "before=nginx:1.20" # Show images before nginx:1.20
docker images --filter "since=nginx:1.20" # Show images since nginx:1.20
docker images --filter "reference=nginx:*" # Show all nginx images
docker images --filter "dangling=true" # Show dangling images
# View image disk space usage
docker system df # View overall Docker space usage
docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}"
Detailed Image Information
# View detailed image information
docker inspect nginx:latest
# View image history
docker history nginx:latest # Show image build history
docker history --no-trunc nginx:latest # Show full commands
# View image layer information
docker inspect nginx:latest | jq '.[0].RootFS.Layers'
# Example output:
[
"sha256:b4d181a07f80...",
"sha256:66b1c490df3f...",
"sha256:d0f91ae9b44c..."
]
Deleting Images
# Delete a single image
docker rmi nginx:latest # Delete by tag
docker rmi b4d181a07f80 # Delete by image ID
# Force delete
docker rmi -f nginx:latest # Force delete, even if a container is using it
# Batch delete
docker rmi $(docker images nginx -q) # Delete all nginx images
docker rmi $(docker images -f "dangling=true" -q) # Delete dangling images
# Clean up unused images
docker image prune # Delete dangling images
docker image prune -a # Delete all unused images
docker image prune --filter "until=24h" # Delete unused images older than 24 hours
# Interactive delete confirmation
docker image prune -a --filter "until=168h" # Delete images older than one week
Custom Image Creation
Creating an Image from a Container
# Start a base container
docker run -it --name mycontainer ubuntu:20.04 /bin/bash
# Perform custom operations inside the container
apt-get update
apt-get install -y nginx vim curl
echo "Hello from my custom image" > /var/www/html/index.html
# Exit the container (do not stop it)
exit
# Commit the container as a new image
docker commit mycontainer my-nginx:v1.0
# Commit with more parameters
docker commit \
--author "Your Name <your.email@example.com>" \
--message "Added nginx and custom index page" \
mycontainer \
my-nginx:v1.0
# Verify the new image
docker images my-nginx
docker history my-nginx:v1.0
Exporting and Importing Images
# Save an image to a tar file
docker save nginx:latest > nginx-latest.tar
docker save -o nginx-latest.tar nginx:latest
# Save multiple images to one file
docker save -o images.tar nginx:latest mysql:8.0 ubuntu:20.04
# Load an image from a tar file
docker load < nginx-latest.tar
docker load -i nginx-latest.tar
# Export a container to a tar file (not recommended, loses history and metadata)
docker export mycontainer > mycontainer.tar
# Import from a tar file as an image
docker import mycontainer.tar my-imported-image:latest
# Import an image from a URL
docker import http://example.com/image.tar my-image:latest
Image Tag Management
# Add a tag to an image
docker tag nginx:latest mynginx:latest
docker tag nginx:latest mynginx:v1.0
docker tag nginx:latest myregistry.com/mynginx:latest
# Create an alias tag
docker tag b4d181a07f80 nginx:stable # Create a tag by ID
# View all tags of an image
docker images nginx # Show all nginx tags
# Delete a tag (does not delete the image)
docker rmi mynginx:latest # Only deletes the tag, the image remains
# Rename an image (actually adds a new tag and deletes the old one)
docker tag oldname:tag newname:tag
docker rmi oldname:tag
Using Docker Hub
Registration and Login
# Login to Docker Hub (requires an account at https://hub.docker.com)
docker login
# Enter username and password
# Login to a specific registry
docker login myregistry.com
docker login -u username -p password myregistry.com # Command-line login (insecure)
# View login status
cat ~/.docker/config.json
# Logout
docker logout
docker logout myregistry.com
Pushing an Image to Docker Hub
# Prepare the image to be pushed (must have a username prefix)
docker tag my-nginx:v1.0 yourusername/my-nginx:v1.0
docker tag my-nginx:v1.0 yourusername/my-nginx:latest
# Push the image
docker push yourusername/my-nginx:v1.0
docker push yourusername/my-nginx:latest
# Push all tags
docker push -a yourusername/my-nginx
# Push progress display
# Example output:
# The push refers to repository [docker.io/yourusername/my-nginx]
# 08249ce7456f: Pushed
# 0d2b33356e6f: Pushed
# v1.0: digest: sha256:abc123... size: 1234
Pulling from Docker Hub
# Pull your own image
docker pull yourusername/my-nginx:v1.0
# Pull a public image from another user
docker pull someuser/their-image:latest
# Pull an official image (no username prefix needed)
docker pull nginx:latest
Private Image Registry
Setting up a Local Registry
# Run the official registry image
docker run -d \
--name local-registry \
-p 5000:5000 \
-v /opt/registry:/var/lib/registry \
registry:2
# Configure to allow HTTP connection (for testing only)
sudo tee /etc/docker/daemon.json <<EOF
{
"insecure-registries": ["localhost:5000"]
}
EOF
# Restart the Docker service
sudo systemctl restart docker
# Tag an image for pushing to the local registry
docker tag nginx:latest localhost:5000/nginx:latest
# Push to the local registry
docker push localhost:5000/nginx:latest
# Pull from the local registry
docker pull localhost:5000/nginx:latest
Configuring Registry Authentication
# Create an authentication configuration directory
mkdir -p /opt/registry/auth
# Create a user password file
docker run --rm \
--entrypoint htpasswd \
registry:2 -Bbn testuser testpass > /opt/registry/auth/htpasswd
# Run the registry with authentication
docker run -d \
--name secure-registry \
-p 5000:5000 \
-v /opt/registry:/var/lib/registry \
-v /opt/registry/auth:/auth \
-e "REGISTRY_AUTH=htpasswd" \
-e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
-e "REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd" \
registry:2
# Login to the private registry
docker login localhost:5000
# Username: testuser
# Password: testpass
Registry API Operations
# View all images in the registry
curl -X GET http://localhost:5000/v2/_catalog
# View all tags of an image
curl -X GET http://localhost:5000/v2/nginx/tags/list
# Get image manifest information
curl -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
http://localhost:5000/v2/nginx/manifests/latest
# Delete an image (requires getting the digest first)
# 1. Get the digest
DIGEST=$(curl -I -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
http://localhost:5000/v2/nginx/manifests/latest | grep Docker-Content-Digest | awk '{print $2}' | tr -d '\r')
# 2. Delete the image
curl -X DELETE http://localhost:5000/v2/nginx/manifests/$DIGEST
Image Optimization Techniques
Choosing the Right Base Image
# Size comparison
docker images ubuntu:20.04 # ~72MB
docker images alpine:latest # ~5MB
docker images scratch # 0MB (empty image)
# Base image selection for multi-stage builds
FROM golang:1.19-alpine AS builder # Use a full image for the build stage
FROM alpine:latest # Use a minimal image for the runtime stage
Image Layer Optimization
# Not recommended: creates multiple layers
RUN apt-get update
RUN apt-get install -y nginx
RUN apt-get install -y curl
RUN rm -rf /var/lib/apt/lists/*
# Recommended: combine commands to reduce layers
RUN apt-get update && \
apt-get install -y nginx curl && \
rm -rf /var/lib/apt/lists/* && \
apt-get clean
Using a .dockerignore File
# Create a .dockerignore file to exclude unnecessary files
cat > .dockerignore << EOF
.git
.gitignore
README.md
Dockerfile
.dockerignore
node_modules
npm-debug.log
.coverage
.nyc_output
EOF
Practical Case
Building a Custom Web Server Image
# 1. Create a working directory
mkdir my-web-server
cd my-web-server
# 2. Create a web page file
cat > index.html << 'EOF'
<!DOCTYPE html>
<html>
<head>
<title>My Custom Web Server</title>
<style>
body { font-family: Arial, sans-serif; margin: 40px; }
h1 { color: #333; }
.info { background: #f0f0f0; padding: 20px; border-radius: 5px; }
</style>
</head>
<body>
<h1>Welcome to my custom Web Server</h1>
<div class="info">
<p>This is a custom Nginx image based on Docker</p>
<p>Build time: $(date)</p>
<p>Server: Nginx + Custom Configuration</p>
</div>
</body>
</html>
EOF
# 3. Create a custom nginx configuration
cat > nginx.conf << 'EOF'
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html;
}
# Custom status page
location /status {
return 200 "Server is running!\n";
add_header Content-Type text/plain;
}
}
}
EOF
# 4. Start a container and customize it
docker run -it --name temp-nginx nginx:alpine /bin/sh
# 5. Configure inside the container (in another terminal)
docker cp index.html temp-nginx:/usr/share/nginx/html/
docker cp nginx.conf temp-nginx:/etc/nginx/
docker exec temp-nginx nginx -t # Test configuration
# 6. Commit as a new image
docker commit temp-nginx my-web-server:v1.0
# 7. Test the new image
docker stop temp-nginx
docker rm temp-nginx
docker run -d --name web-server -p 8080:80 my-web-server:v1.0
# 8. Verify the service
curl http://localhost:8080
curl http://localhost:8080/status
# 9. Clean up
docker stop web-server
docker rm web-server
Image Management Best Practices
- Versioning: Tag images with semantic versions, avoid using only
latest
. - Security Scanning: Regularly scan images for vulnerabilities and update base images promptly.
- Size Optimization: Choose appropriate base images, clean up cache files, and use multi-stage builds.
- Documentation: Write clear documentation and usage instructions for custom images.
- Automated Builds: Use CI/CD pipelines to automate image building and pushing.
Important Notes
- Ensure no sensitive information (passwords, keys, etc.) is included in the image before pushing.
- For private registries in a production environment, it is recommended to use HTTPS and authentication.
- Regularly clean up unused images to save storage space.
- Avoid hardcoding configurations in the image; use environment variables or configuration mounts instead.
Summary
By completing this chapter, you should have mastered:
- Image Structure: A deep understanding of the layered storage principle of Docker images.
- Image Operations: Proficient use of basic image operations like searching, pulling, viewing, and deleting.
- Custom Images: Learned to commit images from containers and import/export images.
- Registry Management: Mastered the use of Docker Hub and private registries.
- Optimization Techniques: Understood the best practices for image optimization and management.
In the next chapter, we will learn about container lifecycle management, including container creation, startup, stopping, monitoring, and other operations.