如何高效迁移容器镜像

不借助公网镜像中心

·

1 min read

2024突然新增了几个PoC,需要在客户现场私有化部署(我的快速部署方案成了不二之选)。但是客户现场情况复杂:

  • 客户所提供部署用主机为内网机器,不允许访问公网;

  • 客户只提供一个跳板机可供我们远程连接;

  • 跳板机可访问公网;

历史做法

使用seafile

Seafile 是一款开源的企业云盘,注重可靠性和性能。支持 Windows, Mac, Linux, iOS, Android 平台。支持文件同步或者直接挂载到本地访问。

PoC所需要的容器镜像加起来有50G左右,这里以nginx镜像为例:

  1.  docker save nginx -o nginx.tar
    
  2. nginx.tar 上传到seafile上

  3. 远程连接到客户的跳板机,从seafile上下载nginx.tar包

  4. 解压并上传镜像到客户的镜像中心

     docker load -i nginx.tar
     docker tag nginx yourharbor.com/dev/nginx
     docker push theharbor.com/dev/nginx
    

问题

因为网速的原因,光是上传下载tar包,就相当费时间,整个过程相当地不友好,这种低效会让人非常难受,得想想办法了。

分析确定的现状:

  1. 不能用公网的镜像中心

  2. 只能用seafile

解决办法

压缩

在这种情况下只能想办法减少镜像包大小, 我最先想到是使用高压缩比,比如xz

xz使用LZMA算法进行压缩,压缩率可以达到gzip的2~3倍,是目前Linux系统中压缩率最高的压缩程序。但压缩速度非常慢。xz压缩文件的扩展名为.xz

nginx.tar: 271M

压缩后

tar -cJf nginx.tar.xz nginx.tar

nginx.tar.xz: 64M,压缩体积相当出色

tar -cJf nginx.tar.xz nginx.tar  118.46s user 1.92s system 95% cpu 2:06.01 total
tar -xf nginx.tar.xz  5.00s user 0.22s system 94% cpu 5.499 total

正如前面提到xz的缺点,压缩需2min左右,解压超过5s,但,高压缩比带来收益还是很可观的,从271M->64M,网速相对稳定的情况下,数据从seafile上传时间减少到原先的1/4,不能不说很优秀了。但是,xz对于大文件压缩时间感人,略加测试后,所以果断弃坑。那,还有没有其它的办法呢?

终极大招

前面提到nginx.tar文件大小为271M,但是使用docker images查看镜像大小为141M

nginx        latest    605c77e624dd   2 years ago   141MB

而在Harbor上看到的大小为仅为54.09M 而已,这个体积甚至低于nginx.tar.xz的64M,这已经不能用优秀来形容了,but why?

  • harbor上显示的是压缩后的镜像体积;

  • docker images看到的是镜像下载到本地后展开的体积(可以试着下载一个大一点的镜像,可以观察到DownloadingExtracting)过程,可以印证这一点。

  • docker save: 因为docker镜像采用的是分层存储方式,每一层只存储与上一层的差异内容。save命令将整个镜像一起保存,导致重复内容也会被重复保存,增加了文件的大小; save命令保存的是完整可运行的镜像,包含所有的所有历史版本、元数据、环境变量和配置

经过以上分析可知,docker镜像中心对镜像的存储优化已经做到极致了(仅限于笔者的认知),所以解决方案也就呼之欲出了: 使用镜像中心 harbor? 必须是registry

Distribution implementation for storing and distributing of container images and artifacts

当然不是,轻量级本地registry即可,将镜像数据挂载到本地的 image_data 目录

docker run -d -p 12345:5000 --restart=always --name registry \
  -v `pwd`/image_data:/var/lib/registry \
  registry:2

registry体积小,占用资源少,在这个场景下无疑是比harbor更好的选择

重新打tag

docker tag nginx localhost:12345/dev/nginx

推送

docker push localhost:12345/dev/nginx

看一下image_data目录大小

 55M    image_data

xz压缩后的体积

 53M    image_data.tar.xz

压缩后仅减少了2M,足以可见docker对容器镜像存储的压缩技术有多优秀了。所以,xz级别的压缩就显得没那么必要了,普通tar包即可

 54M    image_data.tar

将 image_data.tar 上传到seafile,客户现场启用本地registry,剩下就是一些体力活了,如果客户使用的是harbor,还可以直接使用harbor的复制管理功能,稍加配置即可完成镜像从本地registry到客户的harbor这一步,好了,打完收工。

总结

念念不忘,必有回响。对于低效的不满是因,想到registry是灵光一现,也是果。高压缩比方式是最容易想到的,但是细细整理下来,才发现docker生态对于镜像存储优化下了很大功夫,实在是让人佩服。这让我想起2020年还在网银时,当时老大亮哥给我分一任务,好像是梳理镜像下载的瓶颈,现在我只记得当时使用了sisdig各种工具测试,最后得出的结论是网络是瓶颈,但是后来又发现本地解压也很费时间,CPU为陡然变高,很可惜当时没有将过程记录下来,还是要多写哇。然后本篇我也是先做完再梳理的,也会有新的收获,最重要的是将数据对比记录并展现出来了。感叹当年Solomon Hykes做docker的魄力,也对“docker”背后公司现在的处境不胜唏嘘,最后祝愿Solomon Hykes 的新项目Dagger越来越好。

参考: