Docker 镜像管理基础:pull/push/tag/save/load 与镜像分层原理
全面讲解 Docker 镜像操作命令:docker pull/push/tag/save/load/rmi/inspect 的使用场景与参数详解,深入理解镜像分层存储(Union FS)结构、镜像 ID 与 Digest 的区别、多架构镜像(Multi-arch)原理,以及企业镜像管理的命名规范与版本策略。
Docker 镜像是容器的基础,掌握镜像管理是使用 Docker 的核心技能。本文从命令操作到底层原理,系统讲解镜像管理的完整知识体系。
镜像分层存储原理
在学命令之前,先理解镜像是如何存储的——这会让后续所有操作都更容易理解。
镜像分层示例(Nginx 镜像):
Layer 4: 622a1f2... COPY nginx.conf(应用配置层) 8KB
Layer 3: 9f8a3c1... RUN apt-get install nginx 45MB
Layer 2: 1a2b3c4... RUN apt-get update 23MB
Layer 1: sha256:0d5 debian:12-slim 基础镜像 74MB
──────────────────────────────────
合计:约 142MB(实际磁盘占用)
每一层都有:
- 唯一的 SHA256 ID(内容寻址)
- 只读属性(构建完成后不可修改)
- diff 文件(相对上一层的变更)
分层的好处:
场景:服务器上有 3 个镜像:
nginx:1.24 = debian:12 + nginx 1.24 层
nginx:1.25 = debian:12 + nginx 1.25 层
python:3.11 = debian:12 + python3.11 层
磁盘实际存储:
debian:12 基础层 74MB × 1(只存一份!)
nginx 1.24 层 68MB
nginx 1.25 层 69MB
python3.11 层 112MB
─────────────────────────
总计:323MB
如果没有分层(每个镜像完整存储):
nginx:1.24 142MB
nginx:1.25 143MB
python:3.11 186MB
─────────────────────────
总计:471MB
分层节省了约 30% 磁盘空间,网络传输同理(已有的层不重复下载)
一、docker pull — 拉取镜像
# 基础用法
docker pull nginx # 默认拉取 latest 标签
docker pull nginx:1.25 # 指定标签
docker pull nginx:1.25-alpine # alpine 轻量版
# 指定仓库地址
docker pull registry.cn-hangzhou.aliyuncs.com/library/nginx:1.25
# 指定 Digest(最精确,防止标签被覆盖)
docker pull nginx@sha256:a484819eb60211f5299034ac80f6a681b06f89e65866ce91f356ed7c72af059c
# 拉取所有标签(慎用,可能很大)
docker pull -a nginx
# 查看拉取进度
docker pull ubuntu:22.04
# ubuntu:22.04: Pulling from library/ubuntu
# 7b1a6ab2e44d: Pull complete ← 每行是一个层
# Digest: sha256:77906da86b... ← 镜像的唯一指纹
# Status: Downloaded newer image for ubuntu:22.04
镜像命名规则详解:
完整格式:[registry]/[namespace]/[name]:[tag]@[digest]
例子:
nginx → docker.io/library/nginx:latest
ubuntu:22.04 → docker.io/library/ubuntu:22.04
bitnami/redis:7.2 → docker.io/bitnami/redis:7.2
registry.cn-hz.aliyuncs.com/library/nginx:1.25
harbor.company.com/backend/api:v2.1.0
Tag 命名习惯:
latest → 最新版(不建议生产使用,版本不固定)
1.25 → 主版本.次版本
1.25.3 → 主版本.次版本.补丁版本
1.25-alpine → 带构建变体(alpine = 轻量)
1.25.3-amd64 → 带架构信息
二、docker images — 查看本地镜像
# 列出所有镜像
docker images
# 输出示例:
# REPOSITORY TAG IMAGE ID CREATED SIZE
# nginx latest a72860cb95fd 2 weeks ago 187MB
# nginx 1.25 605c77e624dd 8 months ago 141MB
# ubuntu 22.04 3b418d7b466a 6 weeks ago 77.9MB
# 过滤镜像
docker images nginx # 只看 nginx 镜像
docker images --filter "dangling=true" # 悬空镜像(<none>:<none>)
# 显示完整 Image ID(默认只显示前12位)
docker images --no-trunc
# 只显示 Image ID(常用于脚本)
docker images -q
# 格式化输出
docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}"
Image ID vs Digest:
# Image ID:镜像的本地标识(构建时生成)
docker images --format "{{.ID}}"
# a72860cb95fd ← 12位短ID,实际是64位SHA256
# Digest:镜像内容的唯一指纹(从仓库拉取时的Hash)
docker images --digests
# REPOSITORY TAG DIGEST IMAGE ID SIZE
# nginx latest sha256:a484819eb602... a72860cb95fd 187MB
# 区别:
# Image ID 可能因为本地 tag 操作而不同
# Digest 是内容 Hash,全球唯一,不可变
三、docker tag — 标记镜像
tag 命令为镜像创建别名,不会复制数据,只是添加引用。
# 基础用法:给已有镜像打 tag
docker tag nginx:1.25 nginx:stable
docker tag nginx:1.25 harbor.company.com/infra/nginx:1.25
# 推送到私有仓库的完整流程:
# 1. 登录私有仓库
docker login harbor.company.com -u admin -p <password>
# 2. 打 tag(原镜像:tag → 目标仓库:tag)
docker tag nginx:1.25 harbor.company.com/infra/nginx:1.25
docker tag nginx:1.25 harbor.company.com/infra/nginx:stable
# 3. 推送
docker push harbor.company.com/infra/nginx:1.25
docker push harbor.company.com/infra/nginx:stable
# tag 不创建新镜像,只是引用:
docker images nginx
# REPOSITORY TAG IMAGE ID
# nginx 1.25 605c77e624dd ← 同一个 Image ID
# nginx stable 605c77e624dd ← 同一个 Image ID
四、docker push — 推送镜像
# 推送到 Docker Hub
docker login # 登录(只需一次)
docker push myusername/myapp:v1.0
# 推送到阿里云 ACR
docker login registry.cn-hangzhou.aliyuncs.com \
-u <阿里云账号> -p <密码>
docker push registry.cn-hangzhou.aliyuncs.com/myns/myapp:v1.0
# 推送所有同名 tag
docker push harbor.company.com/backend/api --all-tags
五、docker inspect — 查看镜像详情
# 查看镜像元数据(JSON 格式)
docker inspect nginx:1.25
# 常用字段提取
# 查看镜像层
docker inspect nginx:1.25 --format '{{json .RootFS.Layers}}' | jq .
# 查看暴露端口
docker inspect nginx:1.25 --format '{{json .Config.ExposedPorts}}'
# 查看环境变量
docker inspect nginx:1.25 --format '{{json .Config.Env}}' | jq .
# 查看镜像大小(字节)
docker inspect nginx:1.25 --format '{{.Size}}'
# 查看构建历史(每层做了什么)
docker history nginx:1.25
# IMAGE CREATED CREATED BY SIZE
# a72860cb95fd 2 weeks ago CMD ["nginx" "-g" "daemon off;"] 0B
# <missing> 2 weeks ago EXPOSE map[80/tcp:{}] 0B
# <missing> 2 weeks ago COPY /etc/nginx /etc/nginx 4.74kB
# <missing> 2 weeks ago RUN /bin/sh -c apt-get install nginx 68.8MB
六、docker save / docker load — 导出与导入
用于在没有仓库的情况下传输镜像(离线环境、物理拷贝)。
# 导出镜像为 tar 包
docker save nginx:1.25 -o nginx-1.25.tar
# 导出多个镜像到一个 tar(打包批量传输)
docker save nginx:1.25 redis:7.2 ubuntu:22.04 | gzip > infra-images.tar.gz
# 查看 tar 包内容
tar tf nginx-1.25.tar
# manifest.json ← 描述文件
# repositories ← 镜像标签信息
# <layer_id>/layer.tar ← 每一层的内容
# 导入 tar 包
docker load -i nginx-1.25.tar
# Loaded image: nginx:1.25
docker load < infra-images.tar.gz
# 支持 gzip 压缩格式
# 导入后验证
docker images nginx
save vs export 的区别:
docker save(镜像操作):
保存镜像的完整分层结构和元数据
可以 docker load 还原,保留所有 tag 和历史
docker export(容器操作):
导出容器的文件系统快照(扁平化,无分层)
用 docker import 还原,但会失去历史和元数据
通常用于制作精简基础镜像
结论:备份/传输镜像用 save/load;导出容器文件系统用 export/import
七、docker rmi — 删除镜像
# 删除指定镜像
docker rmi nginx:1.24
# 删除多个
docker rmi nginx:1.24 nginx:1.23 ubuntu:20.04
# 强制删除(即使有容器在使用)
docker rmi -f nginx:latest # 慎用!
# 删除所有悬空镜像(<none>:<none>)
docker image prune
# 删除所有未使用镜像(更激进,慎用)
docker image prune -a
# 批量删除指定名称的镜像
docker images nginx -q | xargs docker rmi
# 脚本:删除超过 30 天的镜像
docker images --format "{{.ID}}\t{{.CreatedAt}}" | \
awk -v date="$(date -d '30 days ago' +%s)" \
'$2 < date {print $1}' | \
xargs -r docker rmi
八、多架构镜像(Multi-arch)
现代服务器有 x86_64 和 ARM(鲲鹏/飞腾)两种架构,多架构镜像让同一个 tag 在不同架构上自动拉取对应版本。
# 查看镜像支持的架构
docker manifest inspect nginx:latest | grep '"architecture"'
# "architecture": "amd64"
# "architecture": "arm64"
# "architecture": "arm"
# ... 等多种架构
# 在 ARM 机器上 pull nginx,自动获取 ARM 版本
# 在 x86 机器上 pull nginx,自动获取 x86 版本
# 手动指定架构(跨架构测试)
docker pull --platform linux/arm64 nginx:latest
docker pull --platform linux/amd64 nginx:latest
镜像管理最佳实践
1. 永远不要在生产使用 latest tag
latest 随时可能被更新,导致"代码没变但行为变了"
使用具体版本号:nginx:1.25.3
2. 建立镜像命名规范
格式:registry/namespace/name:版本-环境
示例:harbor.company.com/backend/api:v2.1.0-prod
3. 定期清理
每周执行 docker image prune 清理悬空镜像
配置 Harbor GC 策略,自动清理旧版本
4. 私有镜像必须鉴权
docker login 的凭据存储在 ~/.docker/config.json
生产环境使用 docker secret 或 K8s imagePullSecret
5. 信创/离线环境:用 save/load 而不是手动 pull
提前准备好镜像包,部署时直接 docker load
小结
镜像管理的核心命令:pull(拉取)、push(推送)、tag(打标签)、save/load(离线传输)、rmi(删除)、inspect(查看详情)。
理解分层存储有两个关键点:层是内容寻址的(SHA256 Hash),同内容的层只存一份;镜像 ID 是本地标识,Digest 是全球唯一内容指纹。
下一篇讲容器生命周期管理:如何运行、查看、进入、停止和删除容器。
