Docker 构建(docker build)失败时如何调试?
调试构建失败五步走:读报错定位失败层、用 --progress=plain 看完整输出、--no-cache 排除缓存干扰、复用最后成功的层起临时容器手动执行、检查 .dockerignore 与上下文。本文详解每一步。
调试思路:构建失败本质是"某一层里的某条命令退出码非 0"。按顺序做:①仔细看报错中失败的指令与输出;②--progress=plain 拿完整日志;③--no-cache 排除缓存干扰;④利用缓存到失败点之前,起一个临时容器手动执行失败命令交互排查;⑤检查构建上下文与 .dockerignore。
第一步:读报错信息
报错末尾会写明失败的指令和退出码:
ERROR: process "/bin/sh -c apt-get install -y curl" did not complete successfully: exit code: 100
退出码上方那段输出才是真正的错误(如包不存在、网络超时)。
第二步:拿完整输出
BuildKit 默认的进度输出会折叠日志,加参数看全文:
docker build --progress=plain -t myapp .
第三步:排除缓存干扰
缓存层可能掩盖或引入问题:
docker build --no-cache --pull -t myapp .
--pull 同时刷新基础镜像。
第四步:进临时容器手动复现(杀手锏)
利用缓存——失败点之前的层都是现成的。找到最后成功层的镜像 ID,起个容器手动跑失败的命令:
# --progress=plain 输出里找最后成功层的 ID,如 a1b2c3d4
docker run --rm -it a1b2c3d4 /bin/sh
# 容器里手动执行失败的命令,交互式排查
apt-get install -y curl
BuildKit 下也可直接从报错摘要里复制层 ID。这样能改一点试一次,比每次全量构建快得多。
第五步:检查上下文与常见原因
| 常见原因 | 表现 | 处理 |
|---|---|---|
| COPY 的文件不在上下文 | not found |
确认文件在构建上下文内,查 .dockerignore 是否误排除 |
| 网络/源问题 | apt/pip 超时 | 换国内镜像源、配代理 |
| 架构不匹配 | exec format error | --platform linux/amd64 指定平台 |
| 指令语法错 | 公开资料未说明 instruction |
检查大小写、续行符 |
| 磁盘满 | no space left | docker system prune |
观测云对照
CI 构建失败也要可观测。 把 CI 流水线的构建日志、失败率、构建时长接入观测云,构建劣化趋势(越来越慢、特定阶段频发失败)在看板上一目了然。
常见问题(FAQ)
Q:本地能构建、CI 上失败?
A:多数是本地缓存掩盖(用 --no-cache 复现)、上下文不同(CI 的 checkout 少了文件)或架构不同(ARM Mac vs x86 CI)。
Q:多阶段构建里前面阶段失败怎么看?
A:--target 阶段名 只构建到该阶段,分段定位。
Q:如何验证 Dockerfile 语法但不构建?
A:用 docker build --check(BuildKit 提供的 lint),或 hadolint 工具静态检查。