Docker镜像本地拉取与迁移

由于网络连通性原因,DockerHub的访问变得困难。然而在服务器上部署服务时,又经常需要使用Docker。

为了避免在服务器上进行复杂的网络设置,一种相对折中的方法是:在一台网络流畅(下面称为本机)的机器上获取Docker镜像,再将镜像复制到服务器上使用。

工具 - Skopeo

一种传统的方法是,在本机上也安装一个Docker Engine,使用docker pull命令拉取镜像,再使用docker save导出镜像。

这种方法的缺点在于,我们在本机上或许并不需要/不想要/难以安装Docker引擎。

而维新派指出,在Docker引擎官方代码仓库moby/moby/contrib下,有一个download-frozen-image-v2.sh脚本,该脚本提供了对Docker镜像的下载功能。听起来不错?

而当然,也有更便捷的工具:containers/skopeo。这也是本文介绍的主角。

安装Skopeo

安装skopeo相当简单,例如在Debian 11+/Ubuntu 20.10+内,可以直接在apt源中下载安装。Alpine Linux同样可以使用apk直接添加。

尽管skopeo不支持Windows版本,但完全可以创建一个简易的Alpine Linux WSL环境完成以上任务。

使用Skopeo获取镜像

主要使用的是skopeo copy命令,文档参见skopeo/docs/skopeo-copy.1.md

具体来说,在拷贝时,我们常常希望把镜像打成一个tar包,可以方便地在网络上传输。skopeo可以直接导出tar文件,具体如下:

1
skopeo copy docker://<image>:<tag> docker-archive:/path/to/archive.tar:<image>:<tag>

例如,如果想要拉取busybox的最新版本镜像busybox:latest,可以执行:

1
skopeo copy docker://busybox:latest docker-archive:myarchive.tar:busybox:latest

如果镜像是由非Docker官方发布的,镜像名称中会含有斜杠,请放心,此时镜像名称<image>就是包含斜杠的完整字符串。例如,以下命令当然是没问题的。

1
skopeo copy docker://bitnami/postgresql:14 docker-archive:/path/to/archive.tar:bitnami/postgresql:14

值得注意的是,在上述命令里,附加在打包文件名后的<image>:<tag>,即为之后导入docker时,该镜像所关联到的名称。

例如,如果执行:

1
skopeo copy docker://busybox:latest docker-archive:myarchive.tar:busybox:10086

导入到docker中的镜像名称也会被显示为busybox:10086

1
2
3
user@server:~$ docker images                                                                                                                 
REPOSITORY TAG IMAGE ID CREATED SIZE
busybox 10086 1234567890ab 1 months ago 1.23MB

打包后,为了节约传输带宽和时间,可以对打包好的tar文件压缩一下。可以使用zstdgz等当然也行),大约能缩小2/3的体积。

1
zstd -9 myarchive.tar

在服务器上导入镜像

使用喜欢的方法将打包文件传输到服务器后,就可以导入Docker引擎:

1
docker load < myarchive.tar.zstd

这里使用的是重定向输入文件流,当然也可以使用-i参数引导读取指定路径的文件。同时,docker load也可以加载包括gz, xz, bzip2, zstd在内的压缩文件。

与同名同tag现有镜像的冲突

导入时会覆盖掉同名镜像,即原有镜像的名称会被置空,变成孤立的镜像。运行docker images prune可以删除这些孤立镜像。