Chapter 2: Docker Image Management

Haiyue
16min

Chapter 2: Docker Image Management

Learning Objectives
  • Gain deep understanding of Docker image layered architecture
  • Master image pull, view, and delete operations
  • Learn to create custom images from containers
  • Become proficient in using Docker Hub and private image registries

Key Concepts

Docker Image Layered Structure

Docker images use a layered storage architecture, which is one of Docker’s core design principles. Each image consists of multiple read-only layers connected by pointers.

Advantages of layered storage:

  • Storage Efficiency: Identical layers can be shared across different images, saving disk space
  • Transfer Efficiency: Only missing layers need to be downloaded, speeding up image pulls
  • Caching Mechanism: Existing layers can be reused during builds, improving build efficiency
Image Layer Example:
┌─────────────────────────────────┐
│  Application Layer (nginx:latest)│  ← Writable layer (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 Rules

Docker images follow specific naming conventions: [registry]/[namespace]/[repository]:[tag]

ComponentDescriptionExample
registryImage registry addressdocker.io, gcr.io
namespaceNamespace/Usernamelibrary, nginx, mycompany
repositoryRepository namenginx, mysql, ubuntu
tagVersion taglatest, 1.20, stable
# Complete image name examples
docker.io/library/nginx:1.20        # Official nginx 1.20 version
gcr.io/kubernetes-e2e-test-images/busybox:1.29   # Busybox from Google registry
myregistry.com/myteam/myapp:v1.0     # Application in private registry

Image Storage Drivers

Docker supports multiple storage drivers to manage image layers:

Storage DriverApplicable SystemCharacteristics
overlay2Modern LinuxBest performance, recommended
aufsOlder UbuntuOlder technology, being phased out
devicemapperRHEL/CentOSEnterprise features, complex configuration
btrfsSystems with Btrfs filesystemAdvanced features, snapshot support
# Check current storage driver
docker info | grep "Storage Driver"

# Example output
Storage Driver: overlay2

Basic Image Operations

Searching Images

# Basic search
docker search nginx
docker search mysql
docker search python

# Advanced search options
docker search --limit 10 nginx                    # Limit result count
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 latest version
docker pull nginx                    # Equivalent to docker pull nginx:latest
docker pull ubuntu                   # Pull latest Ubuntu

# Pull specific version
docker pull nginx:1.20               # Pull nginx 1.20 version
docker pull mysql:8.0               # Pull MySQL 8.0 version
docker pull python:3.9-alpine       # Pull Python 3.9 Alpine version

# Pull image for 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 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 specific image
docker images nginx                  # Show only nginx-related images
docker images nginx:1.20            # Show specific version

# Format output
docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}\t{{.CreatedSince}}"

# Show image digest
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 after nginx:1.20
docker images --filter "reference=nginx:*"      # Show all nginx images
docker images --filter "dangling=true"          # Show dangling images

# View image disk usage
docker system df                     # View overall Docker space usage
docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}"

Image Details

# 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 complete commands

# View image layer information
docker inspect nginx:latest | jq '.[0].RootFS.Layers'

# Example output:
[
  "sha256:b4d181a07f80...",
  "sha256:66b1c490df3f...",
  "sha256:d0f91ae9b44c..."
]

Deleting Images

# Delete 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 containers are 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 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

Creating Custom Images

Creating Images from Containers

# 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 container (don't stop it)
exit

# Commit container as 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 new image
docker images my-nginx
docker history my-nginx:v1.0

Exporting and Importing Images

# Save image as 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 image from tar file
docker load < nginx-latest.tar
docker load -i nginx-latest.tar

# Export container as tar file (not recommended, loses history and metadata)
docker export mycontainer > mycontainer.tar

# Import from tar file as image
docker import mycontainer.tar my-imported-image:latest

# Import image from URL
docker import http://example.com/image.tar my-image:latest

Image Tag Management

# Add tag to image
docker tag nginx:latest mynginx:latest
docker tag nginx:latest mynginx:v1.0
docker tag nginx:latest myregistry.com/mynginx:latest

# Create alias tag
docker tag b4d181a07f80 nginx:stable    # Create tag by ID

# View all tags for an image
docker images nginx                      # Show all nginx tags

# Delete tag (not the image)
docker rmi mynginx:latest                # Only delete tag, keep image

# Rename image (actually add new tag then delete old tag)
docker tag oldname:tag newname:tag
docker rmi oldname:tag

Using Docker Hub

Registration and Login

# Login to Docker Hub (need to register at https://hub.docker.com first)
docker login
# Enter username and password

# Login to specific registry
docker login myregistry.com
docker login -u username -p password myregistry.com  # Command line login (insecure)

# Check login status
cat ~/.docker/config.json

# Logout
docker logout
docker logout myregistry.com

Pushing Images to Docker Hub

# Prepare image to push (must include username prefix)
docker tag my-nginx:v1.0 yourusername/my-nginx:v1.0
docker tag my-nginx:v1.0 yourusername/my-nginx:latest

# Push 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 other users' public images
docker pull someuser/their-image:latest

# Pull official images (no username prefix needed)
docker pull nginx:latest

Private Image Registries

Setting Up Local Registry

# Run 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 Docker service
sudo systemctl restart docker

# Tag image for pushing to local registry
docker tag nginx:latest localhost:5000/nginx:latest

# Push to local registry
docker push localhost:5000/nginx:latest

# Pull from local registry
docker pull localhost:5000/nginx:latest

Configuring Registry Authentication

# Create authentication configuration directory
mkdir -p /opt/registry/auth

# Create user password file
docker run --rm \
  --entrypoint htpasswd \
  registry:2 -Bbn testuser testpass > /opt/registry/auth/htpasswd

# Run 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 private registry
docker login localhost:5000
# Username: testuser
# Password: testpass

Registry API Operations

# View all images in registry
curl -X GET http://localhost:5000/v2/_catalog

# View all tags for 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 image (need to get digest first)
# 1. Get 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 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   # Full image for build stage
FROM alpine:latest                   # Minimal image for runtime stage

Image Layer Optimization

# Not recommended: Create 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 .dockerignore File

# Create .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 Custom Web Server Image

# 1. Create working directory
mkdir my-web-server
cd my-web-server

# 2. Create 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 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 container and customize
docker run -it --name temp-nginx nginx:alpine /bin/sh

# 5. Configure inside 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 new image
docker commit temp-nginx my-web-server:v1.0

# 7. Test 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 service
curl http://localhost:8080
curl http://localhost:8080/status

# 9. Cleanup
docker stop web-server
docker rm web-server
Image Management Best Practices
  1. Version Control: Use semantic versioning tags for images, avoid using only latest
  2. Security Scanning: Regularly scan images for vulnerabilities, update base images promptly
  3. Size Optimization: Choose appropriate base images, clean cache files, use multi-stage builds
  4. Documentation: Write clear documentation and usage instructions for custom images
  5. Automated Builds: Use CI/CD pipelines to automatically build and push images
Important Notes
  • Ensure images don’t contain sensitive information (passwords, keys, etc.) before pushing
  • Private registries should use HTTPS and authentication in production environments
  • Regularly clean unused images to save storage space
  • Avoid hardcoding configurations in images, use environment variables or mounted configurations

Summary

Through this chapter, you should have mastered:

  • Image Structure: Deep understanding of Docker image layered storage principles
  • Image Operations: Proficiency in searching, pulling, viewing, and deleting images
  • Custom Images: Ability to commit images from containers and import/export images
  • Registry Management: Understanding of Docker Hub and private registry usage
  • Optimization Techniques: Knowledge of image optimization and management best practices

In the next chapter, we’ll learn about container lifecycle management, including container creation, starting, stopping, and monitoring operations.