Docker: Docker镜像管理

最后更新:2026-08-26

镜像(Image)是 Docker 的核心构建块——掌握镜像管理,就掌握了容器世界的"软件仓库"。

1. 你将学到


2. 一个运维工程师的真实故事

(1) 痛点:CI 服务器磁盘告警

Bob 收到 CI 服务器磁盘告警——Docker 镜像占用了 40 GB 空间。他检查发现大量 <none> 悬空镜像(旧构建残留)和 5 个版本的 Node.js 镜像(每个 1.2 GB),而团队实际只需要最新的 2 个版本。磁盘 80% 满了,构建开始失败。

(2) 镜像清理的解法

Bob 用 3 条命令清掉了 20 GB 无用镜像。

BASH
# Remove dangling images (untagged leftovers)
docker image prune -f

# Remove images not used by any container
docker image prune -a -f

# Check disk usage after cleanup
docker system df

(3) 收益:磁盘空间恢复

20 GB 空间被释放,磁盘使用率从 80% 降到 35%,CI 构建恢复正常运行时间。


3. 镜像与 Docker Hub

(1) 镜像的组成

Docker 镜像由多个只读层(layer)叠加构成,每层代表一个文件系统变更。

100%
graph TB
    L4["CMD ['nginx', '-g', 'daemon off;']<br/>启动命令"]
    L3["COPY html /usr/share/nginx/html<br/>应用代码"]
    L2["RUN apt-get install nginx<br/>安装软件"]
    L1["FROM debian:bookworm-slim<br/>基础系统"]
    L4 --> L3 --> L2 --> L1

(2) 镜像命名规范

TEXT 📖 仅展示
registry/repository:tag
组成部分 说明 示例
registry 仓库地址(默认 Docker Hub) docker.io / localhost:5000
repository 仓库名(用户/镜像名) library/nginx / myorg/myapp
tag 版本标签(默认 latest) 1.25-alpine / latest / v2.0

(3) 常见 tag 命名规范

tag 后缀 含义 大小参考 适用场景
latest 默认最新版 最大 快速体验
alpine Alpine Linux 基础 最小(5-50 MB) 生产/资源受限
slim 精简版 Debian 较小(80-150 MB) 生产(需 glibc)
bookworm / jammy 指定 Debian/Ubuntu 版本 中等(100-300 MB) 需特定系统库
v1.25.3 精确版本号 取决于基镜像 生产锁定版本

4. 镜像基本操作

▶ 示例:拉取不同 tag 的 nginx 镜像(难度⭐)

BASH
# Pull nginx with different tags
docker pull nginx:latest
docker pull nginx:1.25-alpine
docker pull nginx:1.25

# View pulled images
docker images
💻 输出:

TEXT 📖 仅展示
REPOSITORY   TAG            SIZE
nginx        latest         187MB
nginx        1.25-alpine    42.5MB
nginx        1.25           187MB
💡 提示: 同一基础镜像的不同 tag 共享底层,实际占用远小于三个镜像大小之和(去重存储)。

▶ 示例:查看本地镜像列表(难度⭐)

BASH
# List all local images
docker images

# Filter by repository name
docker images nginx

# Show only image IDs
docker images -q

▶ 示例:标记镜像(docker tag)(难度⭐⭐)

BASH
# Tag an existing image for a private registry
docker tag nginx:1.25-alpine localhost:5000/myapp/nginx:v1

# Verify the new tag
docker images | grep myapp
💻 输出:

TEXT 📖 仅展示
localhost:5000/myapp/nginx   v1       42.5MB
📌 重点: docker tag 不复制镜像,只创建一个指向同一镜像的别名。两个 tag 共享存储,不额外占用空间。

▶ 示例:删除镜像(难度⭐⭐)

BASH
# Remove an image by name:tag
docker rmi nginx:1.25

# Remove by image ID
docker rmi a1b2c3d4e5f6

# Force remove (even if used by stopped containers)
docker rmi -f nginx:latest
⚠️ 注意: 镜像被运行中的容器使用时无法删除。需要先 docker stop + docker rm 容器,再删除镜像。

▶ 示例:查看磁盘占用(难度⭐)

BASH
# Show Docker disk usage breakdown
docker system df

# Show detailed per-image size
docker system df -v
💻 输出:

TEXT 📖 仅展示
TYPE            TOTAL   ACTIVE  SIZE      RECLAIMABLE
Images          5       2       1.2GB     800MB (66%)
Containers      3       1       150MB     120MB (80%)
Local Volumes   2       1       500MB     250MB (50%)
Build Cache     10      0       300MB     300MB (100%)

5. 镜像分层与缓存

(1) 分层原理

每个 Dockerfile 指令生成一个镜像层。docker pull 时按层下载,已存在的层会跳过。

100%
graph TB
    subgraph "Image Layers (Shared, Read-only)"
        L1["Layer 1: Base OS<br/>debian:bookworm-slim"]
        L2["Layer 2: apt install<br/>nginx + deps"]
        L3["Layer 3: COPY html<br/>Custom content"]
    end
    subgraph "Container Layer (Writable)"
        C["Container Layer<br/>Runtime changes<br/>logs, temp files"]
    end
    C --> L3 --> L2 --> L1

(2) 分层的好处

好处 说明
存储去重 相同层只存一份,多个镜像共享
传输加速 pull 时跳过已有层,只下载新层
构建加速 未变的层使用缓存,不重新构建

(3) 查看镜像构建历史

BASH
# Show image build history (each layer)
docker history nginx:1.25-alpine
💻 输出(节选):

TEXT 📖 仅展示
IMAGE          CREATED       CREATED BY                                      SIZE
e1ade32        2 weeks ago   CMD ["nginx" "-g" "daemon off;"]                0B
<missing>      2 weeks ago   STOPSIGNAL SIGQUIT                              0B
<missing>      2 weeks ago   ENTRYPOINT ["/docker-entrypoint.sh"]            0B
<missing>      2 weeks ago   COPY 15-local-resolvers.envsh /etc...           389B
<missing>      2 weeks ago   COPY 30-tune-worker-processes.sh /etc...        4.61kB
<missing>      2 weeks ago   RUN /bin/sh -c set -x ... && apk add...         30.4MB
<missing>      2 months ago  /bin/sh -c #(nop)  CMD ["/bin/sh"]              0B

6. 镜像清理策略

(1) 三种清理命令对比

命令 清理范围 风险 适用场景
docker rmi <image> 删除指定镜像 低(精确控制) 删除已知不需要的镜像
docker image prune 删除悬空镜像(<none> tag) 极低(无人引用) 日常清理
docker image prune -a 删除所有未被容器使用的镜像 中(可能删掉还要用的) 磁盘紧张时
docker system prune 清理所有(镜像+容器+卷+缓存) 高(删除范围大) 全面清理

▶ 示例:清理悬空镜像(难度⭐)

BASH
# Remove dangling (untagged) images
docker image prune -f
💻 输出:

TEXT 📖 仅展示
Deleted Images:
untagged: <none>
deleted: sha256:a1b2c3d4...
Total reclaimed space: 150MB

(2) 常用基础镜像大小对比

镜像 大小 包管理器 特点
alpine:3.19 7 MB apk 极小,musl libc
debian:bookworm-slim 74 MB apt 标准 glibc,兼容性好
ubuntu:22.04 77 MB apt 生态丰富
node:20-alpine 135 MB apk + npm Node.js 运行时
python:3.12-slim 155 MB apt + pip Python 运行时
golang:1.22 780 MB apt + go Go 编译环境

7. 完整示例:镜像拉取→标记→推送→清理

BASH
# ============================================
# Complete walkthrough: Image lifecycle management
# Covers: pull, tag, push (local registry), clean
# ============================================

# 1. Pull nginx Alpine image
docker pull nginx:1.25-alpine

# 2. View image details
docker images nginx
docker history nginx:1.25-alpine

# 3. Tag for a local registry
docker tag nginx:1.25-alpine localhost:5000/web/nginx:v1.0

# 4. Start a local registry (for push target)
docker run -d -p 5000:5000 --name registry registry:2

# 5. Push the tagged image to local registry
docker push localhost:5000/web/nginx:v1.0

# 6. Verify the push
curl -s http://localhost:5000/v2/web/nginx/tags/list | python3 -m json.tool

# 7. Remove local copies
docker rmi localhost:5000/web/nginx:v1.0

# 8. Pull back from local registry to verify
docker pull localhost:5000/web/nginx:v1.0

# 9. Clean up: stop registry and remove all unused images
docker stop registry && docker rm registry
docker image prune -a -f

# 10. Check final disk usage
docker system df
💻 输出(节选):

TEXT 📖 仅展示
# docker push localhost:5000/web/nginx:v1.0
The push refers to repository [localhost:5000/web/nginx]
5f0e3b...: Pushed
latest: digest: sha256:7be1... size: 1361

# curl http://localhost:5000/v2/web/nginx/tags/list
{"name":"web/nginx","tags":["v1.0"]}

# docker system df
TYPE            TOTAL   ACTIVE  SIZE      RECLAIMABLE
Images          1       0       42.5MB    42.5MB (100%)

❓ 常见问题

Q :latest 标签会自动更新吗?
A 不会。本地已有的 :latest 不会自动更新。需要显式 docker pull nginx:latest 才能获取最新版本。生产环境应避免用 :latest,用精确版本号(如 nginx:1.25.4)确保可复现。
Q alpine 和 slim 镜像有什么区别?
A Alpine 基于 musl libc 和 BusyBox,极小(7 MB)但可能有兼容性问题(如 Python C 扩展)。Slim 基于 Debian,用 glibc,兼容性好但更大(80-150 MB)。优先用 slim,磁盘极度紧张时用 alpine。
Q 悬空镜像(dangling)是什么?
A 没有标签的镜像(显示为 <none>:<none>),通常由新构建覆盖旧镜像产生——旧镜像失去标签但层还在。用 docker image prune 安全清理,不会影响任何正在使用的镜像。
Q 怎么查看镜像的构建历史?
A docker history <image> 显示每一层的大小、创建时间和对应的 Dockerfile 指令。加 --no-trunc 可查看完整命令。这是分析镜像体积和优化 Dockerfile 的关键工具。
Q 私有仓库怎么搭建?
A 最简单的方式是 docker run -d -p 5000:5000 registry:2,5 秒内就有了一个本地 Registry。生产环境建议用 Harbor(带 Web UI + 认证 + 镜像扫描),或使用云服务商的 Container Registry(AWS ECR / 阿里云 ACR)。
Q 镜像删除后空间没有释放?
A Docker 使用 OverlayFS 分层存储,多个镜像可能共享底层。删除一个镜像只释放它独占的层。用 docker system df -v 查看每个镜像的实际可回收空间。

📖 小节


📝 作业

  1. 基础题(难度⭐):从 Docker Hub 拉取三个不同 tag 的 Ubuntu 镜像(latest / 22.04 / 20.04),用 docker images 对比大小。
  2. 进阶题(难度⭐⭐):用 docker history nginx:latest 分析 Nginx 镜像的分层,找出最大的一层并说明它对应什么操作。
  3. 挑战题(难度⭐⭐⭐):运行 docker system df -v,分析本机 Docker 的磁盘占用分布,然后执行 docker image prune -a -f 清理,对比清理前后回收了多少空间。
Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏