Docker build 时缓存命中改了的代码没打进镜像

举报
phantomxjc 发表于 2026/11/03 09:52:41 2026/11/03
【摘要】 上周改了个 Python 服务的 bug,本地 docker build t myapp . 重新打镜像,再 docker run 起来验证,结果跑出来的行为跟改之前一模一样——那个被修掉的报错还在。第一反应是改漏了文件,来回对比了好几遍,确认代码确实改了,镜像的构建时间也是新的,可运行的就是旧逻辑。这种"改动凭空消失"的感觉最让人抓狂,下面记录我是怎么定位的。 问题现象 本地改完源码,执行构建,

上周改了个 Python 服务的 bug,本地 docker build -t myapp . 重新打镜像,再 docker run 起来验证,结果跑出来的行为跟改之前一模一样——那个被修掉的报错还在。第一反应是改漏了文件,来回对比了好几遍,确认代码确实改了,镜像的构建时间也是新的,可运行的就是旧逻辑。这种"改动凭空消失"的感觉最让人抓狂,下面记录我是怎么定位的。

问题现象

本地改完源码,执行构建,构建日志一路走完没有报错,docker images 里镜像的 CREATED 时间也确实是刚才。但把这个镜像跑成容器后,业务表现和改动前完全一致,像是这次修改根本没进镜像。反复改、反复构建,现象稳定复现,像是改动被构建过程"吃"掉了。

排查过程

先看构建日志,发现 COPY 那一步有点不对劲:

Step 5/7 : COPY . /app
 ---> Using cache
 ---> 9a3c1f2b8e7d

我明明刚改了文件,COPY 却显示命中缓存。直觉上"内容变了缓存就该失效",于是怀疑是不是构建上下文没带上新文件。Docker 构建时是把当前目录打成 tar 传给 daemon 的,.dockerignore 会决定哪些文件进上下文。我翻出项目根目录的 .dockerignore,里面赫然写着:

__pycache__
*.pyc
.git
venv
src/legacy

而这次我改的,恰恰就是 src/legacy/ 下面的一个模块。也就是说,改动文件在构建开始之前就被 .dockerignore 排除出了上下文,Docker 拿到的"要复制的文件集合"根本没变,COPY 层的内容哈希自然也没变,缓存直接复用,旧代码原封不动留在镜像里。为了验证,我把那个文件临时移出被忽略目录再构建,镜像立刻就带上了新逻辑,实锤。

根因

Docker 的层缓存对 COPY/ADD 是按"被复制文件的内容校验和"来判定的。而"被复制的文件集合"由两件事决定:构建上下文(当前目录)和 .dockerignore 的排除规则。只要某次改动的文件落在 .dockerignore 的排除范围内,它就进不了上下文,COPY 层看到的输入没变化,于是跳过重建、复用旧缓存层——改动永远不会进镜像。这个问题在 CI 里更隐蔽,因为很多人为了加快构建,会往 .dockerignore 里一股脑加排除项,时间久了连自己都忘了里面有业务目录。

解决办法

  • 改完先强制全量验证一次:docker build --no-cache -t myapp .,绕过所有缓存,确认改动确实生效了,再正常构建。
  • 核对 .dockerignore:别把业务代码目录误伤进去;排除项越少越安全,实在要排除就写精确,不要拿宽泛的目录名去堵。
  • 用 docker history <镜像> 看每层:确认 COPY 那一层是不是真的重做了(没有 <missing> 或者 Using cache 标记),而不是靠"构建时间新"来自我安慰。
  • CI 慎用 --cache-from:从远端拉基础镜像复用缓存时,要确保你的源码层每次都能因内容变化而失效,否则一样会吃到旧代码。

小结

"改了代码镜像却没变"这类问题,第一嫌疑人永远是 .dockerignore + 构建上下文,而不是 Docker 缓存本身有 bug。COPY 缓存只看"进入上下文的文件内容哈希",被 ignore 的改动等于不存在。下次遇到,先 cat .dockerignore 再看缓存,能省下大把瞎猜的时间。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。