docker image 分层的问题

2023-07-14 12:00:43 +08:00
 guoguobaba

不知道有人碰到过没有

就是 gitlab ci 的时候,会 build docker image ,再 push 到 registry 上,我用的是公有云 的容器镜像服务,所以希望每次 push 都能做到尽可能小的增量

project 是 java springboot 的工程,每次都会生成一个 jar 包,这个 jar 包大概 200m ,如果 用类似 COPY xxxx.jar /app

这样的 Dockerfile ,每次 jar 这一层就要上传 200m+

所以采用了 jar 包分层的技术,用 $ java -Djarmode=layertools -jar target/xxx.jar extract 得到四个目录,

Step 7/11 : COPY dependencies/ /app
 ---> 9831e5b6f9ae
Step 8/11 : COPY spring-boot-loader/ /app
 ---> 82f47422bade
Step 9/11 : COPY snapshot-dependencies/ /app
 ---> 24658da80ea8
Step 10/11 : COPY application/ /app
 ---> 6d47ede4decb

这样每次 ci 的时候,前三个目录基本没有变化,这样生成 docker image 的 layer 是不变的 ,每次 push 只会 push step 10 之后的内容

这种方法在本地没有问题 mvn clean package... docker build -t ..., docker push ...显示只需要 push 最后一个 layer

e44c9b0a313a: Pushed
5732f7831cbe: Layer already exists
48d1ef8e0017: Layer already exists
025a15bbce04: Layer already exists
8460ea9541f4: Layer already exists
de24004afe49: Layer already exists
a52fcbff5465: Layer already exists
767f936afb51: Layer already exists

然后在 gitlab ci 里,显示每次还是要 push 多个 layer

看了一下日志,每次 gitlab ci 里 build 的时候,

Status: Downloaded newer image for ccr.ccs.tencentyun.com/.../xx:latest
 ---> 08909e73839f
Step 2/11 : ENV AppName xxx-system
 ---> Running in b66bf82ba02d

Step1 的 hash 值是一样的,但是 Step 2 的 hash 值就发生变化了,理论上相同的操作应该产 生相同的 hash 值

1835 次点击
所在节点    Linux
10 条回复
sadfQED2
2023-07-14 12:06:56 +08:00
分阶段编译?
Lax
2023-07-14 12:13:24 +08:00
"理论上相同的操作应该产 生相同的 hash 值" --- 这句话,是那个文档里说的?
ziwen1943
2023-07-14 12:23:35 +08:00
分层逻辑失败变成全量 docker 构建的原因主要有两个,第一是编译用基础镜像每次都会重新下载或者变动,那么第一层就变动了,后续也要重新来,第二种就是删除了历史的 image ,导致分层的逻辑没办法命中历史的缓存层。
结合你上面的情况,我认为是 gitlab-ci 每次编译的时候都启用了一个新环境(可能是 docker 模式的 gitlab-runner )导致编译都是全新编译,但是上传的时候缓存层在 hub 里面存在,然后出现全新打包,缓存上传的局面了。
( ps 如果是 shell 模式的 gitlab-runner ,你需要看一下.gitlab-ci.yaml 文件里面是不是加了 docker rm 的命令删除旧的镜像,因为我就是这么干的,为了节约磁盘空间,为了全新打包避免遗漏)
liantian
2023-07-14 12:30:15 +08:00
别用 docker build…换 buildah 就是啦…

buildah 一次 build 是一层,多余文件清理掉就好。
iBugOne
2023-07-14 13:05:23 +08:00
docker build --cache-from 拉下来的镜像

docker 默认不会复用拉下来的镜像里的层,所以每次都等于全新 build ,需要用 cache-from 钦点 docker 去尽量复用已有的层
newaccount
2023-07-14 13:08:52 +08:00
baseimage 不要使用 latest ,固定版本试一下呢?
xiaobai1213
2023-07-14 13:36:40 +08:00
看一下 gitlab-ci 使用的 runner 模式,有的 runner 模式是不会存储之前的工作空间的,这样就会无法命中缓存层,导致每一次都是全量构建

"理论上相同的操作应该产 生相同的 hash 值" 这个是在官方文档里面看到的吗? 之前有试验过 同样命令同一份代码同一个 maven 打出来的两个 jar 最后算出来的 sha1 都是不一样的......
Masoud2023
2023-07-14 13:44:18 +08:00
你 Gitlab 里的 docker 根本没配置缓存吧?

不过看这帖子也学习到了,原来 jar 包还能这么拆开。。
guoguobaba
2023-07-14 13:51:11 +08:00
@iBugOne best solution
每次 gitlab runner 起的是一个新环境,所以 ci 脚本增加下面的就完美解决了
```
- docker pull $IMAGE || echo "no image"
- docker build --cache-from $IMAGE -t $IMAGE .
```

看了一下 job 的运行时间,从 109s 下降到 29s

特别是我可以开启我之前购买的屮蛋的天翼云主机做 runner 服务器了,他只有 1m 的带宽,用完成 jar 包的 image 上传要 25 分钟以上,现在每次 ci ,只需要 2-3 分钟了。
guoguobaba
2023-09-28 17:49:54 +08:00
汇报一下,这个问题主要是 gitlab ci 是 docker:dind 对应的/var/lib/docker 目录都从
内存中生成导致每次都需要重新下载 image
所以设置一个 pvc ,缓存/var/lib/cache 就可以了

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/956719

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX