Featured image of post Docker 镜像与容器导入导出:save/load/export/import 实战

Docker 镜像与容器导入导出:save/load/export/import 实战

docker save / load / export / import 的差异、A 服务器容器迁移到 B 服务器、commit 容器成镜像、批量备份与版本管理

“我要把 A 服务器上跑得好好的容器,搬到 B 服务器上去”——这种需求在生产环境很常见,但很多人会卡在 save / export 该用哪个。这一篇把镜像 / 容器的导入导出分清楚,再给出几个常见场景的实战方案。

阅读对象:需要在不同环境之间迁移容器 / 镜像、要做离线备份的运维 / 开发者 覆盖范围:save vs export + load vs import + 容器打包成新镜像 + 批量备份脚本

一、四种命令的差异

命令对象保留历史保留元数据典型用途
docker save镜像(所有层)镜像备份、离线迁移
docker load镜像加载 save 产物镜像恢复
docker export容器(扁平化)容器快照
docker import容器 export 产物加载成新镜像从容器快照恢复

核心区别

  • save / load 操作的是镜像,保留完整历史(每一层构建步骤、tag、标签)
  • export / import 操作的是容器当前文件系统快照扁平化成单层,丢失历史
  • export 出来的 import 后默认无 tag,需要手动 docker tag

二、save / load:镜像备份与离线迁移

1
2
3
4
5
6
7
8
# 导出镜像(保留原名称和 tag)
docker save <IMAGE_NAME>:<IMAGE TAG> > save.tar

# 实际例子
docker save nginx:1.19.9-alpine > nginx1.19.9-alpine.tar
docker save mysql:8.0.23 > mysql8.0.23.tar
docker save influxdb:2.0.4-alpine > influxdb2.0.4-alpine.tar
docker save anapsix/alpine-java:8_server-jre_unlimited > alpine-java8.tar

保留

  • 镜像名、tag
  • 所有构建历史(docker history 能看到每一层)
  • 标签 / env / 入口点等元数据
1
2
3
# 导入镜像
docker load < nginx1.19.9-alpine.tar
docker load < mysql8.0.23.tar

注意save 默认输出到 stdout(用 > 重定向),load 默认从 stdin 读取(用 < 喂入)。

三、export / import:容器快照

1
2
3
4
5
# 导出容器当前文件系统
docker export <container-id> > snapshot.tar

# 实际例子
docker export 2acd22312bbe > tomcat80824.tar
1
2
3
4
5
# 从快照导入成新镜像(**默认无 tag**)
docker import snapshot.tar

# 命名(推荐)
docker import snapshot.tar myimage:v1

丢弃

  • 所有构建历史——扁平化为单层
  • 容器名 / 标签 / 启动参数——只是个文件系统快照
  • 环境变量 / 入口点——可以 import 后用 docker run 重新指定

典型场景:容器 A 上有手动修改的文件(不写在 Dockerfile 里),想"原样"搬走。export 拿到的就是 A 当前文件系统。

四、把运行中的容器打包成新镜像

需求:服务器 A 上一个容器跑得好好的,有大量数据 + 手工修改,直接迁移到 B 上

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# 1. 在 A 上:把容器 commit 成新镜像
docker commit <container-id> <new-image-name>:<tag>

# 实际例子
docker commit 135a0d19f757 jenkins:1.0

# 2. 镜像存到 tar
docker save jenkins:1.0 > jenkins1.0.tar

# 3. 拷到 B(scp / u盘 / 内网)
scp jenkins1.0.tar root@<B-host>:/tmp/

# 4. 在 B 上:加载镜像
docker load < /tmp/jenkins1.0.tar

# 5. 在 B 上:用同样的参数启动
docker run -d --name jenkins jenkins:1.0

Why 用 commit 而不是 exportcommit 把容器当前的差异化层(基于原镜像的修改)保留下来,新镜像的"基础层"还是原镜像——体积小、有历史、FROM 关系清晰。export 是纯文件系统,体积大且无继承。

五、批量备份所有镜像

1
2
3
4
5
6
7
8
9
# 备份所有镜像到一个目录
mkdir -p /backup/docker-images
for IMAGE in $(docker images --format '{{.Repository}}:{{.Tag}}' | grep -v '<none>'); do
  SAFE_NAME=$(echo $IMAGE | tr '/:' '_')
  docker save $IMAGE > /backup/docker-images/${SAFE_NAME}.tar
done

# 验证
ls -lh /backup/docker-images/

六、常见问题

6.1 docker load 之后镜像名变长 hash

save 没指定镜像名时,load 后镜像名是 hash

1
2
3
4
5
$ docker load < nginx.tar
Loaded image ID: sha256:7d0a4dc9b...
$ docker images
REPOSITORY   TAG       IMAGE ID       CREATED       SIZE
<none>       <none>    7d0a4dc9b...   2 weeks ago   187MB

解决:手动 tag。

1
docker tag 7d0a4dc9b... nginx:1.19.9-alpine

6.2 跨大版本 Docker 不兼容

docker save 产物在跨大版本 Docker 之间可能不能 load

  • Docker 1.10+ 改了镜像 schema,老 daemon 可能不认新镜像
  • 新 daemon 一般能 load 老镜像(向后兼容)

如果跨大版本不兼容:

1
2
3
4
5
# 在老 daemon 上导出
docker save -o old.tar image:tag

# 在新 daemon 上导入
docker load -i old.tar

如果还不行,升级老 daemon 或用 docker pull + 私有 registry 中转。

6.3 save 文件很大,传输慢

镜像层是去重的,多个镜像可以合并成一个 save 文件

1
docker save -o multi.tar nginx:1.19 mysql:8.0 redis:6.0

load所有镜像都会出现

七、save / export 的取舍速查

场景推荐
离线环境装镜像save / load
容器整体迁移到另一台机器commit + save + load
容器当前状态备份(含手工修改)export / import
镜像要保留构建历史save / load
大镜像分发私有 registry + docker push / pull(更高效)
跨大版本 Docker升级老 daemon 或走 registry 中转

八、生产最佳实践

  1. 优先用私有 registry——docker push / pull 内部仓库比 save / load 更快、支持增量、可以做权限控制
  2. save 文件作为离线备份、应急恢复用——不要作为日常分发方式
  3. 写 Dockerfile + rebuild——比 commit 容器更可追溯、更可复现
  4. CI 流水线用 commit / tag 标识版本,避免"无 tag 镜像"堆积

九、要点回顾

  1. save / load 保留历史export / import 扁平化
  2. commit + save + load 是"运行中容器迁移"的标准三件套
  3. 跨大版本 Docker save / load 可能不兼容——优先升级 daemon
  4. 多镜像可以合并到一个 save 文件(-o flag)
  5. load 后无 tag 要手动 docker tag 命名

十、小结

把镜像 / 容器的导入导出搞清楚,离线环境、内部 Harbor / Registry 没起来的应急场景都能 hold 住。但生产环境强烈建议走私有 registry——save / load 是"应急"工具,不是"日常"工具。

下一步:理解了单镜像的导入导出,下一步是 Harbor / Docker Registry / Distribution 私有仓库的搭建、镜像签名、漏洞扫描——save / load 解决"单文件"问题,registry 解决"仓库级"问题。

参考资料

使用 Hugo 构建
主题 StackJimmy 设计