为何基于同一Dockerfile构建时仅部分镜像被复用?
这个现象本质上和Docker镜像的层哈希生成机制有关——只有当镜像的每一层内容(包括构建上下文、执行命令的输出、元数据)完全一致时,才会生成相同的Image ID。结合你描述的场景(同一VM、相同二进制/Dockerfile、不同标签),具体成因可以分成这几个常见情况:
构建上下文的细微差异:
你提到大家用了相同的应用二进制和Dockerfile,但Docker build会打包整个构建上下文(当前目录下的所有文件,包括隐藏文件、临时文件)发送给Docker daemon。如果其中两个用户的上下文完全一致(比如没有生成编辑器临时文件、日志文件,甚至.git目录里的提交记录也没变动),而其他用户的上下文里有细微变化(比如不小心多了个.DS_Store、.swp临时文件,或者文件的权限/所有者不同),就会导致构建层的哈希变化,生成唯一的Image ID。构建时的动态参数/环境差异:
哪怕Dockerfile看起来一样,有人可能在执行docker build时加了不同的--build-arg参数(比如传递了不同的版本号、构建时间戳),或者VM上的环境变量有差异(比如不同用户的PATH、HOME变量不同,而Dockerfile里用到了这些变量),这些动态值会改变构建层的内容,进而生成不同的Image ID。而那两个用户刚好没有用任何动态参数,环境也完全一致,所以复用了相同的镜像层。Docker缓存的命中差异:
Docker build会优先复用已有的缓存层。如果其中两个用户的构建请求刚好在缓存有效期内触发(比如第一个用户构建完后,第二个用户立刻执行build,所有层都命中缓存),就会直接复用之前的Image ID。而其他用户的构建可能因为缓存被清理(比如有人执行了docker system prune)、或者上下文有过临时变动(哪怕之后改回去了,缓存已经失效),导致重新构建所有层,生成新的Image ID。依赖资源的动态变化:
如果Dockerfile里有拉取外部资源的命令(比如RUN apt-get update、RUN curl下载某个文件),哪怕命令本身没变,外部资源可能在不同时间点有更新(比如apt源的包索引更新了,或者下载的文件内容变了)。那两个用户的构建刚好在资源没有变动的窗口内执行,生成的层一致;其他用户的构建时间点刚好赶上资源更新,导致层内容变化。
内容的提问来源于stack exchange,提问作者user6317694

