本文最后编辑于 前,其中的内容可能需要更新。
在生产中有时候会遇上一个比较恶心的问题,因为经常性需要去各个甲方部署,公司的平台基于docker-compose
部署,另外还有大大小小各种乱七八糟几百个镜像的业务依赖,每部署一次都需要重新挑出所需的镜像对其进行导出,再将其部署。
原有方案 将docker镜像通过docker save
的方式导出为tar包,然后再到需要部署的机器上导入:
1 2 # 导出操作 docker images|grep -v "REPOSITORY"|awk '{print "docker save -o "NR".tar " $1":"$2}' |awk '{system($0)}'
1 2 # 导入操作 ls *.tar|awk '{print $NF}'|sed -r 's#(.*)#sudo docker load -i \1#' |bash
问题 这个方案存在两个问题,一来是docker容器通过docker save
导出后会占用大量的磁盘空间,而且费时费力,另外需要在某台机器先部署好镜像才能进行导出,
为了提高效率,拟采用新的方式进行镜像的搬运。
使用私有镜像仓库来进行搬运 docker 官方镜像中存在docker registry的镜像,该镜像可比较方便的进行导入导出,并且镜像分层,可以较好的解决磁盘占用和导入时间长的问题。这个方式类似上一章中提到的harbor做镜像存储操作,
1 2 3 4 5 6 # 运行容器 docker pull registry docker run -d -p 80:5000 -v /root/registry:/var/lib/registry registry # 推送镜像 docker images|grep -v "REPOSITORY"|awk '{print "docker tag " $1":"$2 "localhost:5000/" $1":"$2}' |awk '{system($0)}' docker images|grep "localhost"|awk '{print "docker push " $1":"$2}' |awk '{system($0)}'
此时registry文件夹即保存的镜像,
部署:
1 2 3 # 导入registry镜像 docker load -i registry.tar docker run -d -p 5000:5000 -v /root/registry:/var/lib/registry registry
通过python脚本简单下载:
1 2 3 4 5 6 7 8 import requestsimport jsonimport osres = requests.get("http://127.0.0.1:5000/v2/_catalog" ) imagelist = res.json()["repositories" ] for i in imagelist: os.system(f"docker pull localhost:5000/{i} " ) os.system(f"docker tag localhost:5000/{i} {i} " )
问题 这个方案虽然解决磁盘占用问题,但仍需要通过本地的docker 导出镜像。同样会带来大量的镜像。
最终方案(?) 最近听说了skopeo
之后发现它可以比较方便的解决这个问题,但执行起来还是有一些阻碍:
各种依赖镜像原本都是使用Dockerfile
进行构建的,此时使用skopeo
去获取镜像并不容易
skopeo
保存的镜像仍然存在分层重复的问题,重复占用磁盘的问题仍旧存在。
解决问题:
搭建私有的harbor仓库 不多做赘述,可以参考此处
在本地构建镜像后推送到私有harbor 先构建全部的可能用到的镜像,构建过程略,在harbor建立一个image仓库,然后推送:
1 2 docker images|grep -v "REPOSITORY"|awk '{print "docker tag " $1":"$2 "harbor.local/images/" $1":"$2}' |awk '{system($0)}' docker images|grep "harbor.local"|awk '{print "docker push " $1":"$2}' |awk '{system($0)}'
使用skopeo拉取镜像 skopeo
镜像拉取方式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 skopeo sync --src docker harbor.local/image/nginx:latest --dest dir image --insecure-policy --tls-verify=false WARN[0000] '--tls-verify' is deprecated, please set this on the specific subcommand INFO[0000] Tag presence check imagename="harbor.local/image/nginx:latest" tagged=true INFO[0000] Copying image ref 1/1 from="docker://harbor.local/image/nginx:latest" to="dir:image/nginx:latest" Getting image source signatures Copying blob 7dbe7f8c80d3 done Copying blob 89a5e550c323 done Copying blob 2ef7f86534fd done Copying blob b2109f84b5d3 done Copying blob f88e263879e1 done Copying blob e445148a2a87 done Copying config 4f380adfc1 done Writing manifest to image destination Storing signatures INFO[0006] Synced 1 images from 1 sources
通过脚本获取需要的镜像列表,然后对其分别拉取到image
目录。
此时image
的目录结构如下:
1 2 3 4 5 6 7 8 9 10 11 12 tree images/ images/ └── nginx:latest ├── 2ef7f86534fdfcd45609e1f26fae69dff48828665da24023b86ce80a4efdea06 ├── 4f380adfc10f4cd34f775ae57a17d2835385efd5251d6dfe0f246b0018fb0399 ├── 7dbe7f8c80d3a2e99a0d1e07e4314dc18fecaf591563e596c1080698173d3724 ├── 89a5e550c32388274bd4ced3c636fa8a3f21b1fd01e0f3b91bad4769ead317c6 ├── b2109f84b5d3876f7fe664c298f91e4de086ce6d892cf6b885820e168fe6d10b ├── e445148a2a87d1e55db8d9e3f0f554481cb2ff8bf70383ad3f34d5379c5ad984 ├── f88e263879e1903b1cdf9fe53ace2241fc3995aaa77b6524a1dcf3f9447bfd06 ├── manifest.json └── version
转换拉取的镜像文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 import osimport jsonimport hashlibos.mkdir("registry" ) os.makedirs(f"registry/docker/registry/v2/blobs/sha256" ) imagelist=["nginx:latest" ] for i in imagelist: os.system(f"skopeo sync --src docker harbor.local/test/{i} --dest dir image --insecure-policy --tls-verify=false" ) imagename=i.split(':' )[0 ] imagetag=i.split(':' )[1 ] os.makedirs(f"registry/docker/registry/v2/repositories/{imagename} " ) with open (f"image/{i} /manifest.json" ) as f: manifestdata = f.read() with open (f"image/{i} /manifest.json" ,'r' ,encoding="utf-8" ) as f: man_sha=f.read() data = json.loads(man_sha) m = hashlib.sha256() m.update(bytes (man_sha,encoding='utf-8' )) manifest_sha = m.hexdigest() os.makedirs(f"registry/docker/registry/v2/repositories/{imagename} /_manifests/revisions/sha256/{manifest_sha} " ) with open (f"registry/docker/registry/v2/repositories/{imagename} /_manifests/revisions/sha256/{manifest_sha} /link" ,"w" ) as f: f.write(f"sha256:{manifest_sha} " ) os.makedirs(f"registry/docker/registry/v2/repositories/{imagename} /_manifests/tags/{imagetag} /index/sha256/{manifest_sha} " ) with open (f"registry/docker/registry/v2/repositories/{imagename} /_manifests/tags/{imagetag} /index/sha256/{manifest_sha} /link" ,"w" ) as f: f.write(f"sha256:{manifest_sha} " ) os.makedirs(f"registry/docker/registry/v2/repositories/{imagename} /_manifests/tags/{imagetag} /current" ) with open (f"registry/docker/registry/v2/repositories/{imagename} /_manifests/tags/{imagetag} /current/link" ,"w" ) as f: f.write(f"sha256:{manifest_sha} " ) sim_man_sha = manifest_sha[:2 ] os.makedirs(f"registry/docker/registry/v2/blobs/sha256/{sim_man_sha} /{manifest_sha} " ) with open (f"registry/docker/registry/v2/blobs/sha256/{sim_man_sha} /{manifest_sha} /data" ,"w" ) as f: f.write(man_sha) man_digest=data['config' ]["digest" ].split(":" )[1 ] os.makedirs(f"registry/docker/registry/v2/blobs/sha256/{man_digest[:2 ]} /{man_digest} " ) os.system(f"ln -f image/{i} /{man_digest} registry/docker/registry/v2/blobs/sha256/{man_digest[:2 ]} /{man_digest} /data" ) os.makedirs(f"registry/docker/registry/v2/repositories/{imagename} /_layers/sha256/{man_digest} " ) with open (f"registry/docker/registry/v2/repositories/{imagename} /_layers/sha256/{man_digest} /link" ,"w" ) as f: f.write(f"sha256:{man_digest} " ) for layer in data['layers' ]: print (layer) layerhash = layer["digest" ].split(":" )[2 ] layerpath = f"registry/docker/registry/v2/repositories/{imagename} /_layers/sha256/{layerhash} " sim_layerhash = layerhash[:2 ] os.makedirs(layerpath) with open (f"{layerpath} /link" ,'w' ,encoding="utf-8" ) as f: f.write(layer["digest" ]) os.makedirs(f"registry/docker/registry/v2/blobs/sha256/{sim_layerhash} /{layerhash} " ) os.system(f"ln -f image/{i} /{layerhash} registry/docker/registry/v2/blobs/sha256/{sim_layerhash} /{layerhash} /data" )
导出后文件夹格式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 registry/ └── docker └── registry └── v2 ├── blobs │ └── sha256 │ ├── 2e │ │ └── 2ef7f86534fdfcd45609e1f26fae69dff48828665da24023b86ce80a4efdea06 │ │ └── data │ ├── 4f │ │ └── 4f380adfc10f4cd34f775ae57a17d2835385efd5251d6dfe0f246b0018fb0399 │ │ └── data │ ├── 7d │ │ └── 7dbe7f8c80d3a2e99a0d1e07e4314dc18fecaf591563e596c1080698173d3724 │ │ └── data │ ├── 89 │ │ └── 89a5e550c32388274bd4ced3c636fa8a3f21b1fd01e0f3b91bad4769ead317c6 │ │ └── data │ ├── b2 │ │ └── b2109f84b5d3876f7fe664c298f91e4de086ce6d892cf6b885820e168fe6d10b │ │ └── data │ ├── d1 │ │ └── d1ad002da32d49eed600f7fcff543396a57a7e2c913063ac9bb68ca78219bfd1 │ │ └── data │ ├── e4 │ │ └── e445148a2a87d1e55db8d9e3f0f554481cb2ff8bf70383ad3f34d5379c5ad984 │ │ └── data │ └── f8 │ └── f88e263879e1903b1cdf9fe53ace2241fc3995aaa77b6524a1dcf3f9447bfd06 │ └── data └── repositories └── nginx ├── _layers │ └── sha256 │ ├── 2ef7f86534fdfcd45609e1f26fae69dff48828665da24023b86ce80a4efdea06 │ │ └── link │ ├── 4f380adfc10f4cd34f775ae57a17d2835385efd5251d6dfe0f246b0018fb0399 │ │ └── link │ ├── 7dbe7f8c80d3a2e99a0d1e07e4314dc18fecaf591563e596c1080698173d3724 │ │ └── link │ ├── 89a5e550c32388274bd4ced3c636fa8a3f21b1fd01e0f3b91bad4769ead317c6 │ │ └── link │ ├── b2109f84b5d3876f7fe664c298f91e4de086ce6d892cf6b885820e168fe6d10b │ │ └── link │ ├── e445148a2a87d1e55db8d9e3f0f554481cb2ff8bf70383ad3f34d5379c5ad984 │ │ └── link │ └── f88e263879e1903b1cdf9fe53ace2241fc3995aaa77b6524a1dcf3f9447bfd06 │ └── link └── _manifests ├── revisions │ └── sha256 │ └── d1ad002da32d49eed600f7fcff543396a57a7e2c913063ac9bb68ca78219bfd1 │ └── link └── tags └── latest ├── current │ └── link └── index └── sha256 └── d1ad002da32d49eed600f7fcff543396a57a7e2c913063ac9bb68ca78219bfd1 └── link 42 directories, 18 files
拉取镜像测试 1 2 3 4 5 6 7 8 9 10 11 12 docker pull localhost:5000/nginx Using default tag: latest latest: Pulling from nginx 7dbe7f8c80d3: Pull complete 89a5e550c323: Pull complete 2ef7f86534fd: Pull complete b2109f84b5d3: Pull complete f88e263879e1: Pull complete e445148a2a87: Pull complete Digest: sha256:d1ad002da32d49eed600f7fcff543396a57a7e2c913063ac9bb68ca78219bfd1 Status: Downloaded newer image for localhost:5000/nginx:latest localhost:5000/nginx:latest