1. 引言

在离线或网络隔离的生产环境中部署 Docker 应用时,常常需要将预先构建好的镜像通过物理介质(如光盘、U盘)传输。然而,单个 Docker 镜像的体积可能远超常见存储介质的容量(例如 DVD 光盘的 4.7GB)。直接使用 docker save 命令保存的镜像文件(.tar)往往无法直接刻录到一张光盘上。

本文将详细介绍一种可靠的解决方案:将大型 Docker 镜像保存为压缩包,分割成适合光盘容量(如 4GB)的小块,分多张光盘刻录,最后在目标离线机器上重新合并并加载。这种方法完美解决了单介质容量限制的问题。

操作案例

例如:
vscode-ray-test:tensorflow    20.5GB

在有镜像的电脑上保存并压缩

sudo docker save vscode-ray-test:tensorflow | gzip -9 > vscode-ray-test_tensorflow.tar.gz

查看大小:

ls -lh vscode-ray-test_tensorflow.tar.gz

切成适合光盘的小块
光盘标称 4.5GB,实际可用空间通常不到 4.5GB,所以建议每块切成 3900MB:

split -b 3900M -d -a 3 vscode-ray-test_tensorflow.tar.gz vscode-ray-test_tensorflow.tar.gz.part-

查看每块大小:

ls -lh vscode-ray-test_tensorflow.tar.gz.part-*

生成校验文件

sha256sum vscode-ray-test_tensorflow.tar.gz.part-* > SHA256SUMS.txt

刻录到多张光盘
在不联网电脑上恢复
把所有光盘里的 part 文件复制到同一个目录
先校验:

sha256sum -c SHA256SUMS.txt

如果都显示 OK,再加载镜像:

cat vscode-ray-test_tensorflow.tar.gz.part-* | gunzip -c | sudo docker load

查看镜像是否导入成功:

sudo docker images | grep vscode-ray-test

注意:
ubuntu操作系统,光盘不能多次添加文件进行刻录,只能一次刻录,不然识别不出来,原因未知。

2. 核心思路与流程概览

整个操作流程可以概括为以下四个步骤:

  1. 保存与压缩:在有网络的环境中,使用 docker save 将镜像导出为 .tar 文件,并使用压缩工具(如 gzip)减小其体积。
  2. 分割文件:使用文件分割工具(如 split)将压缩后的单个大文件切割成多个指定大小(例如 4GB)的小文件。
  3. 分盘刻录:将每个分割后的小文件分别刻录到不同的物理光盘上。
  4. 离线还原:在目标离线机器上,将所有光盘中的文件复制到同一目录,按顺序合并,解压缩,最后使用 docker load 加载镜像。

下面的流程图清晰地展示了这一过程:

有网络环境
大型 Docker 镜像

docker save -o image.tar

gzip image.tar
生成 image.tar.gz

split -b 4G image.tar.gz
image_part_

分割文件
image_part_aa, image_part_ab, ...

分盘刻录
Part_aa -> 光盘1, Part_ab -> 光盘2

离线环境
复制所有 part 文件至同一目录

cat image_part_* > image_restored.tar.gz
合并文件

gzip -d image_restored.tar.gz
解压还原为 .tar

docker load -i image_restored.tar
加载镜像

成功!
离线环境可用 docker images 查看

3. 操作步骤详解

3.1 步骤一:保存并压缩 Docker 镜像

首先,在可以访问 Docker Hub 或内部仓库的联网机器上操作。

  1. 查看镜像列表,确认需要导出的镜像名称和标签。

    docker images
    
  2. 保存镜像为 .tar 文件docker save 命令会将镜像及其所有层导出为一个归档文件。

    docker save -o my_large_image.tar myregistry.com/myapp:latest
    
    • -o: 指定输出文件名。
    • 请将 myregistry.com/myapp:latest 替换为你的实际镜像名。
  3. 压缩 .tar 文件。为了减少总体积,便于分割和传输,我们使用 gzip 进行压缩。

    gzip my_large_image.tar
    

    执行后,会生成 my_large_image.tar.gz 文件,原始 .tar 文件会被删除。压缩率取决于镜像内容,通常可以显著减小体积。

3.2 步骤二:分割压缩文件

使用 split 命令将大文件分割成小块。这里以每块 4GB(即 4G)为例,以适应 DVD 光盘。

split -b 4G my_large_image.tar.gz my_image_part_
  • -b 4G: 指定每个输出文件的大小为 4GB。单位可以是 K (KB), M (MB), G (GB)。
  • my_large_image.tar.gz: 需要分割的输入文件。
  • my_image_part_: 输出文件的前缀。分割后的文件将被命名为 my_image_part_aa, my_image_part_ab, my_image_part_ac … 依此类推。

执行后检查

ls -lh my_image_part_*

你应该能看到一系列大小约为 4GB 的文件(最后一个文件可能较小)。

3.3 步骤三:分盘刻录

现在,将每个分割后的文件(my_image_part_aa, my_image_part_ab, …)分别刻录到不同的光盘上。

  • Windows: 可以使用如 ImgBurnCDBurnerXP 或系统自带的刻录功能,选择“刻录数据光盘”,将单个 .part 文件拖入并刻录。
  • Linux/macOS: 可以使用 braseroK3b 或命令行工具 wodimgrowisofs

关键提示:务必记录好文件的刻录顺序!建议在光盘封面或文件名中标记顺序(如 光盘1_of_3_part_aa),这对于后续正确合并至关重要。

3.4 步骤四:离线环境合并与加载

在目标离线服务器或工作站上操作。

  1. 复制所有分割文件:将所有光盘中的 my_image_part_* 文件复制到服务器上的同一个目录中,例如 ~/offline_images/

  2. 合并文件:使用 cat 命令按照字母顺序(即 aa, ab, ac… 的顺序)将所有部分合并成一个完整的 .tar.gz 文件。

    cd ~/offline_images
    cat my_image_part_* > my_large_image_restored.tar.gz
    
  3. 解压文件:将合并后的压缩包解压,还原为 Docker 可识别的 .tar 格式。

    gzip -d my_large_image_restored.tar.gz
    

    解压后会得到 my_large_image_restored.tar 文件。

  4. 加载 Docker 镜像:最后,使用 docker load 命令将镜像导入到本地 Docker 引擎。

    docker load -i my_large_image_restored.tar
    
    • -i: 指定输入文件。
  5. 验证:加载成功后,使用 docker images 命令检查镜像是否已出现在列表中。

4. 完整命令示例与验证

假设我们有一个名为 bigapp:prod 的镜像,以下是在 源机器(联网)目标机器(离线) 上执行的完整命令序列对比:

步骤源机器(联网)目标机器(离线)
1. 保存docker save -o bigapp.tar bigapp:prod
2. 压缩gzip bigapp.tar
3. 分割split -b 4G bigapp.tar.gz bigapp_part_
4. 刻录(将 bigapp_part_aa, ab, ac 分别刻盘)
5. 复制(将所有 bigapp_part_* 文件从光盘复制到 ~/restore/)
6. 合并cd ~/restore && cat bigapp_part_* > bigapp_restored.tar.gz
7. 解压gzip -d bigapp_restored.tar.gz
8. 加载docker load -i bigapp_restored.tar
9. 验证docker images | grep bigapp

5. 注意事项与最佳实践

  • 校验完整性:在刻录前和合并后,可以使用 md5sumsha256sum 校验源文件和目标文件的一致性,确保传输过程没有出错。

    # 在源机器计算原始压缩包的哈希
    md5sum my_large_image.tar.gz
    # 在目标机器计算合并后文件的哈希
    md5sum my_large_image_restored.tar.gz
    

    两个哈希值应该完全相同。

  • 处理更多分区:如果分割后文件超过 26 个(aazz),split 命令会自动使用更长的后缀(如 aaa, aab),cat 命令合并时能正确识别,无需担心。

  • 使用更高效的压缩算法:如果镜像压缩率不佳,可以考虑使用 pigz(并行 gzip)或 xz 算法以获得更高的压缩比,但解压时可能需要相应工具。

    # 使用 pigz 压缩 (更快)
    docker save myapp:latest | pigz > myapp.tar.gz
    # 使用 xz 压缩 (压缩比更高,但更慢)
    docker save myapp:latest | xz > myapp.tar.xz
    
  • 直接分割 .tar 文件:如果不进行压缩,也可以直接分割 docker save 产生的 .tar 文件。但分割后的总文件体积会更大,可能需要更多光盘。

  • 备选方案:私有仓库中转:如果条件允许,可以在离线网络内部搭建一个私有的 Docker Registry,先将镜像推送到内网仓库,其他离线机器再从内网仓库拉取。这更适合需要频繁分发镜像的场景。

6. 总结

通过 docker savegzipsplitcatdocker load 这一系列标准 Linux 工具的组合,我们可以有效地解决大体积 Docker 镜像的离线物理传输问题。这种方法不依赖于特定商业软件,通用性强,是系统管理员和运维工程师在面对严格网络隔离环境时的必备技能。关键点在于保持文件顺序在关键步骤进行完整性校验,以确保整个流程万无一失。

更多推荐