Docker 镜像拉取与离线分发实践
背景
在内网部署、离线交付、跨环境迁移时,常见需求不是直接运行容器,而是先把镜像拉到本地,再导出成文件发给其他人。
这类场景下,最稳妥的流程通常是:
docker pull将目标镜像拉到本地docker save将镜像导出为.tar- 按统一命名规则整理文件
- 将导出的包分发给目标环境
- 对方使用
docker load导入
本文整理一套可直接复用的操作方式。
核心命令
拉取镜像:
bash
docker pull 镜像名:tag
导出镜像:
bash
docker save -o myimage.tar 镜像名:tag
例如:
bash
docker pull nginx:latest
docker save -o nginx--latest.tar nginx:latest
为什么用 docker save
docker save 导出的是镜像本身,适合做离线分发。
它和下面几种方式的区别需要分清:
docker save
导出镜像,适合发送给别人导入。docker export
导出容器文件系统,不保留镜像层和元数据,通常不适合镜像分发。- 直接拷贝 Docker Desktop 的底层磁盘文件
不适合单镜像交付,文件大且不可控。
如果目标是"把某个镜像发给别人用",优先选 docker save。
命名规则
为了便于识别和批量管理,可以将导出文件命名为:
text
镜像名最后一个 path--tag.tar
例如:
text
docker.io/library/nginx:latest
导出后命名为:
text
nginx--latest.tar
再例如:
text
docker.io/library/mysql:8.0
导出后命名为:
text
mysql--8.0.tar
这个规则的优点很直接:
- 文件名短,适合分发
- 能保留服务名和版本号
- 比把完整仓库路径塞进文件名更清晰
单个镜像导出
下面是一套最小操作:
bash
image="nginx:latest"
repo="${image%:*}"
tag="${image##*:}"
name="${repo##*/}"
docker pull "$image"
docker save -o "${name}--${tag}.tar" "$image"
执行后会生成:
text
nginx--latest.tar
批量导出镜像
如果镜像很多,手工执行容易出错。更实用的做法是写一个简单脚本。
bash
#!/usr/bin/env bash
set -u
out_dir="./web-images"
mkdir -p "$out_dir"
images=(
"nginx:latest"
"mysql:8.0"
"redis:7.2"
)
for image in "${images[@]}"; do
repo="${image%:*}"
tag="${image##*:}"
name="${repo##*/}"
tar_path="${out_dir}/${name}--${tag}.tar"
echo "=== $image ==="
docker pull "$image" || continue
docker save -o "$tar_path" "$image" || continue
echo "SAVED -> $tar_path"
done
这个脚本的特点是:
- 逻辑简单,便于维护
- 目录按用途分开,比如
web-images、db-images - 文件名统一
- 某个镜像失败不会阻塞后续镜像
实际整理方式
如果项目里存在多套业务镜像,建议按目录区分:
text
web-images/
nginx--latest.tar
redis--7.2.tar
db-images/
mysql--8.0.tar
postgres--16.tar
这样比全部堆在一个目录里更好管理,尤其适合:
- 按系统交付
- 按环境备份
- 按项目归档
常见问题
1. docker save 生成的是不是"压缩包"
严格来说,docker save 生成的是 .tar 包,不一定是压缩过的。
如果你还想进一步压缩,可以再执行:
bash
gzip nginx--latest.tar
压缩后会变成:
text
nginx--latest.tar.gz
但很多场景下,直接保留 .tar 就已经够用了。
2. 为什么 docker pull 会提示 unauthorized
这通常不是命令写错,而是仓库权限问题。常见原因有:
- 没有执行
docker login - 当前账号没有目标仓库拉取权限
- 镜像路径写错
- tag 不存在
遇到这种情况,先确认:
bash
docker login
然后再重试 docker pull。
3. docker save 会不会带上容器运行时的数据
不会。
docker save 只导出镜像,不包含容器运行过程中写入的数据卷内容。
如果你需要一起迁移业务数据,还要额外处理:
- Docker volume
- 挂载目录
- 数据库备份
4. 对方如何使用导出的镜像
对方收到 .tar 后,直接执行:
bash
docker load -i nginx--latest.tar
导入完成后,可通过下面命令确认:
bash
docker images
推荐的交付流程
比较稳妥的一套流程如下:
- 整理镜像清单
- 创建分类目录,例如
web-images、db-images - 批量执行
docker pull - 按
服务名--版本.tar导出 - 校验导出文件是否齐全
- 如有需要,再统一压缩或打总包
- 交付对方使用
docker load导入
一套可直接复用的模板
bash
#!/usr/bin/env bash
set -u
out_dir="./images"
mkdir -p "$out_dir"
images=(
"镜像1:tag"
"镜像2:tag"
"镜像3:tag"
)
for image in "${images[@]}"; do
repo="${image%:*}"
tag="${image##*:}"
name="${repo##*/}"
tar_path="${out_dir}/${name}--${tag}.tar"
echo "pull -> $image"
docker pull "$image" || {
echo "pull failed: $image"
continue
}
echo "save -> $tar_path"
docker save -o "$tar_path" "$image" || {
echo "save failed: $image"
continue
}
done
总结
如果目标是做离线交付,最实用的办法就是:
text
docker pull -> docker save -> 统一命名 -> 分类归档 -> docker load
这里最关键的不是命令本身,而是两点:
- 命名规则要统一
- 目录结构要清晰
当镜像数量一多,规范化管理比单次执行更重要。