news 2026/10/16 19:10:05

docker build 跑了 92 分钟还是失败了

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
docker build 跑了 92 分钟还是失败了

docker compose build 跑了 92 分钟,最后死在一个 short read 上。

我没重试,而是用 7 个 md5 证明了旧镜像可以直接用。

打包阶段要重建三个业务镜像。镜像就是打包好的只读文件模板,容器是它跑起来的实例。

命令很简单。

docker compose 是 Docker 官方的多容器编排工具,一份 yaml 管好几个容器。

dockercompose build gin admin

然后它跑了起来,跑了一小时三十二分钟。结果一半成功,一半失败。

#17 DONE 5542.6s ← 拉一个层花了 92 分钟 #25 [admin 2/6] WORKDIR /app #25 ERROR: short read: expected 14450867 bytes but got 10679994: unexpected EOF target admin: failed to solve: failed to compute cache key

gin 成功了。admin 挂在了 WORKDIR /app 这一步。

挂掉的不是编译,也不是写代码。它死在第 2 步,连代码都还没开始拷。

报错原文里两个数是关键:expected 14450867 bytes but got 10679994。

它说的是,这一层该收到 14450867 字节,实际只收到 10679994 字节。

差了约 3.7MB,连接就断了。

这叫 short read,也就是下载被截断了。

原因是拉基础镜像 python:3.11-slim 的时候,本地镜像源极不稳定。

所以第一件事确定了:这次失败和代码一点关系都没有。

它在下载阶段就死了,压根没轮到源码出场。

看到构建失败,我当时的肌肉记忆是再跑一遍。但先算一下这笔账。

直接重试,代价是再来一次 92 分钟,而且可能再一次被截断。

成不成功,取决于镜像源的心情。

换成证明「这个镜像不需要重建」,代价只有几条命令、几分钟。

成不成功,取决于镜像里装的到底是不是当前代码。

第一条路的坏处不只是慢。更要命的是,92 分钟之后的那个结果,我没法提前知道。

它可能成功,也可能在第 80 分钟又断一次。

真正该想的问题不是「怎么让它成功」。

我一开始想的也是这个。

该想的是:这个镜像,真的需要重建吗?

如果镜像里装的代码就是当前代码,这次失败根本不用修,直接用现成的镜像就行。

那就先取证,再定结论。取证的顺序是先筛时间线,再逐个算 md5。

镜像的构建时间和源码的最后修改时间,都是可以查的。三个镜像挨个对一遍。

app-admin 的镜像构建时间是 2026-08-23 12:06。

源码最后修改是 2026-08-23 11:15,镜像比源码晚了 51 分钟。

app-gin 的镜像构建时间是 2026-09-21 20:05。源码最后修改是 2026-08-26 07:43,它已经重建过了。

app-h5 的镜像构建时间是 2026-08-23 12:06。

源码最后修改是 2026-08-26 08:31,镜像比源码旧,需要重建。

判据很简单。镜像比源码新,大概率包含了最新代码;镜像比源码旧,就一定漏了东西。

app-admin 落在第一种情况。但时间线只是旁证。

它能证明上次构建发生在最后一次改代码之后,却证明不了构建进去的就是这些文件。

万一当时构建的是另一个分支,万一改完之后文件被回滚过,时间线都看不出来。

所以真正做的,是把镜像里的文件算一遍 md5,和本地逐个对。

在容器里算,用镜像自带的 python,不依赖宿主机装任何东西。

dockerrun--rmapp-admin:latest python-c\"import hashlib;print(hashlib.md5(open(chr(47)+'app'+chr(47)+'config.py','rb').read()).hexdigest())"

在本地算。

python-c"import hashlib;print(hashlib.md5(open('config.py','rb').read()).hexdigest())"

两个值一比,就知道镜像里那份和本地这份是不是同一个字节序列。

七个文件跑下来。

√ config.py √ wsgi.py √ app.py √ models/admin.py √ routes/auth.py √ routes/admin_user.py √ templates/base.html 一致 7 / 不同 0

一致 7,不同 0。

结论直接落下来:app-admin:latest 里装的就是当前代码,复用,不重建。

这里顺带踩到一个环境坑。

上面那条命令里,为什么写 chr(47)+‘app’+chr(47),而不直接写 /app/config.py?

因为这是在 Windows 的 MSYS 环境里跑的。

MSYS 会自作主张,把命令行里的 /app/config.py 改写成 Windows 路径。

实测变成了 F:/app/install/Git/app/config.py。

容器里自然找不到这个文件,于是每一行都返回「取不到哈希」。

看起来就像镜像里的文件全都不对。

这个假象排查了两轮才定位到。绕法有两个。

# 绕法一:让命令行里不出现 /app 这个字面量python-c"import hashlib;print(hashlib.md5(open(chr(47)+'app'+chr(47)+'config.py','rb').read()).hexdigest())"# 绕法二:用双斜杠,MSYS 就不转换了dockerrun--rmapp-admin:latest md5sum //app/config.py

这类坑的共同特征是,它不会报错,只会给你一个看起来很有意义的错误答案。

「取不到哈希」和「哈希不一致」,是两种完全不同的结论,但输出长得差不多。

回头看那三行报错,信息量比想象中大。

#25 [admin 2/6] WORKDIR /app #25 ERROR: short read: expected 14450867 bytes but got 10679994: unexpected EOF target admin: failed to solve: failed to compute cache key

[admin 2/6] 说明整个 Dockerfile 一共 6 步,死在第 2 步。

short read 加 unexpected EOF 是网络层的症状。

failed to compute cache key 说的是前面没做成功、后面算不出缓存键。

它是结果,不是原因。

把网络失败和代码失败分开,是这一步唯一重要的事。

分开了,网络失败就去查源、查代理,或者干脆绕过去。

分不开,就会对着自己没问题的代码改上两个小时。

而「绕过去」的前提,是我手上有别的证据证明产物可用。

这就是那七个 md5 的价值。

三个镜像的处置落下来是这样。

app-gin 重建,镜像 ID 从 5090ee632c85 变成 f6f16e877dc6。

依据是源码 8-26 晚于镜像 8-23。

app-h5 也重建,从 f2ed0db556cd 到 c9f55183cb3f,耗时 1.1 秒。

依据是源码更新,加上静态产物今日重建。纯 COPY,所以极快。

app-admin 复用,镜像 ID 是 cab9af444506,依据是 md5 逐文件比对一致。

app-h5 那条 1.1 秒值得单独看一眼。

它的 Dockerfile 只有一句 COPY,把本地构建好的静态产物拷进 nginx 镜像。

没有编译,就没有编译时间。

以后再遇到这个情况,就按照今天这种方式来排查。

报错里带 short read、unexpected EOF,先把失败定位到网络层,先看它死在第几步。

[x/y] 里的 y 很小,就说明大概率还没碰到你的代码。

想判断旧镜像能不能复用,先比时间线,也就是镜像构建时间对源码最后修改时间。

镜像晚于源码,再进入下一步验证。

用镜像自带的运行时算 md5,和本地逐文件比对,全部一致就直接复用。

记下镜像 ID,跳过这次 build,后续打包直接 docker save 它。

在 Windows 或者 MSYS 下跑容器命令,避免命令行里出现 /app 这个字面量。

用 chr(47) 拼路径,或者写成 //app/…

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/16 19:10:05

论文引言叙事逻辑混乱,研究背景铺垫冗余问题分析

引言(绪论)承担交代研究背景、提出研究问题、阐述研究意义、说明研究思路的作用,是引导读者进入研究场景的开篇部分。研究生撰写绪论时极易走向两个极端:其一,研究背景无限延展,大量堆砌行业宏观新闻、政策…

作者头像 李华
网站建设 2026/10/16 19:10:06

仿生学智能监测系统:硬件设计与算法实现

1. 项目背景与核心思路"琏雾-仿采精灵"这个实验项目名称乍看有些抽象,但拆解后能发现其核心在于模拟自然界中某些特殊生物的信息采集机制。在实际操作中,这个项目主要尝试通过软硬件结合的方式,复现某些昆虫(如蜜蜂、蚂…

作者头像 李华
网站建设 2026/10/16 19:10:06

impeccable CLI:用PRODUCT.md和DESIGN.md实现文档与代码契约校验

1. 项目概述:一个被误读却极具价值的 CLI 工具生态“impeccable”这个词本身是英文形容词,意为“无可挑剔的、完美的、无瑕疵的”,常用于描述工艺、服务或设计品质。但最近在开发者社区里,它突然以小写字母形式高频出现在 npm 搜索…

作者头像 李华
网站建设 2026/10/16 19:10:07

创新实训第44节点:接口补充的完整思路与实操指南

1. 项目背景与接口补充的整体思路1.1 这个实训项目到底在做什么创新实训进行到第44个节点,核心任务落在了“相关接口的补充”上。做过完整项目的人都知道,一个系统在主体功能跑通之后,真正决定它能不能被别人用起来、能不能被其他模块调起来的…

作者头像 李华
网站建设 2026/10/16 18:31:10

ArduPilot飞控参数决策地图:按飞行模式精准调参

简介:本资源是一份面向飞控开发工程师与无人机调参实践者的Mission Planner飞行模式中文参数详解文档,聚焦ACRO、ADSB、AFS、AHRS等核心模式的参数功能、取值范围及工程配置要点,解决多模态飞行控制中参数理解难、调参无依据、失效保护逻辑不…

作者头像 李华
网站建设 2026/10/16 19:10:09

SURPAC三维矿体建模全流程:从钻孔数据库到资源量估算

简介:SURPAC是地质勘探、矿产资源评价与环境监测领域广泛应用的建模工具,这份Word文档系统梳理了SURPAC建模的核心知识点,适合初次接触SURPAC建模的工程师、地质技术人员及相关专业学生。内容涵盖项目数据在微机中的存贮组织、原始数据组织、…

作者头像 李华