Docker: Docker镜像管理
最后更新:2026-08-26
镜像(Image)是 Docker 的核心构建块——掌握镜像管理,就掌握了容器世界的"软件仓库"。
1. 你将学到
- Docker Hub 镜像仓库的使用
- 镜像标签(tag)的命名规范
- 镜像的拉取与推送
- 镜像分层与缓存机制
- 镜像清理策略
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)叠加构成,每层代表一个文件系统变更。
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 时按层下载,已存在的层会跳过。
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 查看每个镜像的实际可回收空间。📖 小节
- 镜像由只读层叠加构成,分层存储实现去重和缓存加速
- 镜像命名规范:
registry/repository:tag,生产环境避免用:latest docker pull/images/tag/rmi是镜像管理的四大基本操作docker tag只创建别名不复制镜像,docker rmi删除镜像前需先清理关联容器- 悬空镜像用
docker image prune清理,全面清理用docker system prune - Alpine 最小(7 MB)但可能兼容性差,Slim 兼容性好(80-150 MB),按需选择
📝 作业
- 基础题(难度⭐):从 Docker Hub 拉取三个不同 tag 的 Ubuntu 镜像(
latest/22.04/20.04),用docker images对比大小。 - 进阶题(难度⭐⭐):用
docker history nginx:latest分析 Nginx 镜像的分层,找出最大的一层并说明它对应什么操作。 - 挑战题(难度⭐⭐⭐):运行
docker system df -v,分析本机 Docker 的磁盘占用分布,然后执行docker image prune -a -f清理,对比清理前后回收了多少空间。