使用Dockerfile构建镜像推Artifactory时apk --no-cache致层SHA256变化的疑问
首先咱们拆解下你遇到的问题:同一份Dockerfile三次构建却出现层SHA256不一致,以及对应的存储空间复用疑问,下面给你逐一说明:
为什么层SHA256会不一致?
核心原因出在apk --no-cache add指令上:虽然--no-cache不会在镜像中留存apk缓存文件,但每次执行apk add时,它都会临时从指定仓库拉取最新的包索引。哪怕你的Dockerfile没改动,仓库索引文件可能包含时间戳、包元数据变化或者微小版本更新,这些细微差异都会导致RUN指令执行后生成的层内容发生变化,最终让层的SHA256值改变。
另外你拆分了两个apk add为独立的RUN指令,这也增加了层变化的概率——第二个apk add同样会触发索引拉取,两次拉取的索引可能不完全一致。
关于Artifactory的存储空间复用
Artifactory是基于内容寻址存储镜像层的:只要两个层的SHA256完全相同,就只会存储一份,其他镜像仅做引用。但如果某一层SHA256不同,这个层就会被单独存储,无法复用之前的版本。所以你当前的情况是:两个相同的层会被复用,那个不同的层会额外占用一份存储空间。
如何让构建层SHA256完全一致?
这里有几个实用的解决办法:
合并多个apk指令为单个RUN
把两个apk add合并成一条命令,减少层的数量,同时避免多次拉取索引带来的差异:RUN apk --no-cache add curl gosu --repository http://myartifactory.com:8081/artifactory/alpine-nl-remote/alpine/edge/testing固定安装包的具体版本
给要安装的包指定精确版本,这样哪怕仓库有新版本,也会安装你指定的版本,确保层内容完全一致:RUN apk --no-cache add curl=7.66.0-r0 gosu=1.12.0-r0 --repository http://myartifactory.com:8081/artifactory/alpine-nl-remote/alpine/edge/testing你可以先通过
apk search --no-cache -v gosu在本地查到对应仓库的可用版本号。预先拉取固定的索引文件
如果仓库索引经常变化,你可以先把仓库索引文件下载到本地,通过ADD指令加到镜像里,再执行安装命令,避免每次构建拉取不同的索引:FROM alpine:3.9 ADD resources/repositories /etc/apk/repositories # 假设已下载好索引文件到本地resources目录 ADD resources/apk-index /var/cache/apk/ RUN apk --no-cache add curl gosu --repository http://myartifactory.com:8081/artifactory/alpine-nl-remote/alpine/edge/testing
调整后,每次构建的层SHA256就能完全一致,Artifactory也只会存储一份镜像层,所有构建都能复用这些层了。
内容的提问来源于stack exchange,提问作者Chanan Berler

