Skip to content

🖼️ Image Management

Pulling and Listing Images

bash
# Pull an image from Docker Hub
docker pull nginx
Using default tag: latest
latest: Pulling from library/nginx
a2abf6c4d29d: Pull complete
a9edb18cadd1: Pull complete
589b7251471a: Pull complete
Digest: sha256:0d17b565c37bcbd895e9d92315a05c1c3c9a29f762b011a10c54a66cd53c9b31
Status: Downloaded newer image for nginx:latest

# Pull a specific version
docker pull nginx:1.24
docker pull python:3.11-slim
docker pull mysql:8.0

# List local images
docker images
REPOSITORY   TAG          IMAGE ID       CREATED        SIZE
nginx        latest       605c77e624dd   2 weeks ago    141MB
nginx        1.24         a8758716bb6a   3 weeks ago    141MB
python       3.11-slim    f9a40a850103   1 week ago     137MB
mysql        8.0          3218b38490ce   3 weeks ago    516MB

# Search for images
docker search redis
NAME       DESCRIPTION                    STARS   OFFICIAL
redis      Redis is an open source ...    11000   [OK]

Deleting Images

bash
# Delete a specific image
docker rmi nginx:1.24

# Force delete (even if containers are using it)
docker rmi -f nginx:latest

# Clean up all unused images (free up space)
docker image prune

# Nuclear option: delete all unused images, containers, networks
docker system prune -a

Understanding Image Layers

Docker images are stacked layer by layer, like a mille-feuille cake 🍰. Each layer only records the differences from the previous layer.

bash
# View layer information of an image
docker history nginx:latest
IMAGE ID         CREATED       COMMAND                                          SIZE
605c77e624dd   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 /docker...     4.62kB
<missing>      2 weeks ago   RUN /bin/sh -c set -x && addgroup -g 101...     61.1MB
<missing>      2 weeks ago   /bin/sh -c #(nop) ADD file:caec368f5a54f...     77.8MB

💡 Tip: 💡 Why do layers matter? Multiple images can share the same layers! For example, both nginx and python are based on debian — the debian base layer is stored only once, saving disk space.

Building Images with Dockerfile

A Dockerfile is the recipe for an image — it tells Docker step by step how to "cook" it.

dockerfile
# Base image
FROM python:3.11-slim

# Set working directory (equivalent to cd /app)
WORKDIR /app

# Copy dependency files first (leverages caching — if deps haven't changed, no reinstall)
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Copy application code
COPY . .

# Expose port
EXPOSE 8000

# Startup command
CMD ["python", "app.py"]
bash
# Build the image
docker build -t myapp:1.0 .
[+] Building 12.5s (10/10) FINISHED
 => [internal] load build definition from Dockerfile
 => [internal] load .dockerignore
 => [internal] load metadata for docker.io/library/python:3.11-slim
 => [1/5] FROM docker.io/library/python:3.11-slim@sha256:...
 => [2/5] WORKDIR /app
 => [3/5] COPY requirements.txt .
 => [4/5] RUN pip install --no-cache-dir -r requirements.txt
 => [5/5] COPY . .
 => exporting to image
 => => naming to docker.io/library/myapp:1.0

# Run a container with the built image
docker run -d -p 8000:8000 myapp:1.0

Multi-Stage Builds (Advanced)

Multi-stage builds are like preparing the dish in the kitchen, then only bringing the dish out — not the pots and pans. This can dramatically reduce the final image size.

dockerfile
# ===== Stage 1: Build =====
FROM node:18 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build

# ===== Stage 2: Run =====
FROM nginx:alpine
# Only copy the build output, no node_modules
COPY --from=builder /app/dist /usr/share/nginx/html

💡 Tip: 💡 Result: the Node.js image is ~900MB, while nginx:alpine is only 40MB. The final image is 800MB+ smaller!