docker 路径不存在:挂载与 COPY 的 no such file or directory 速查
更新时间:2026-10-24。FAQ 速查页,面向
docker build报COPY failed: no such file or directory、或docker run -v挂载后容器里看不到文件的同学。docker 路径不存在的本质是一道边界问题:构建期的 COPY 只能看见「构建上下文」这一个目录树,运行期的-v挂载要求宿主机源路径真实存在——跨出边界的引用全部报「不存在」。病灶收敛在六根轴上:文件在上下文之外、相对路径基准搞错、.dockerignore把文件排除了、挂载源路径拼错或没建、多阶段构建里阶段名写错、符号链接指到上下文外。挂载能挂上但权限不对是另一种报错,看 docker 权限被拒速查。
本文要回答的问题
COPY failed: file not found in build context里的 build context 到底是哪个目录?- Dockerfile 里的相对路径是相对「Dockerfile 在哪」还是「构建命令在哪执行」?
- 明明文件就在目录里,为什么 COPY 还是说找不到?
docker run -v /proj/demo/data:/data不报错,容器里/data却是空的?- 多阶段构建
COPY --from=builder报阶段不存在怎么查?
一、报错原文与典型现象
路径类报错在构建期与运行期各有标准措辞(路径以 /proj/demo 占位):
# 构建期——文件不在构建上下文里:
$ docker build -t myapp /proj/demo
=> ERROR [3/4] COPY ../shared/config.yaml /app/config.yaml
failed to solve: COPY failed: forbidden path outside the build context: ../shared/config.yaml# 构建期——文件名拼错或被 .dockerignore 排除:
=> ERROR [2/4] COPY target/app.jar /app/app.jar
failed to solve: COPY failed: file not found in build context
or excluded by .dockerignore: stat target/app.jar: file does not exist# 运行期——挂载源不存在(老版本报错,新版本静默建空目录):
$ docker run -v /proj/demo/data:/data myapp
docker: Error response from daemon: invalid mount config:
source path does not exist: /proj/demo/data读报错抓两个信号:报文里直接给出完整路径(stat target/app.jar),照着这个路径去上下文根目录里核对是否存在;报文里出现 outside the build context 或 excluded by .dockerignore 字样时,问题不在「文件有没有」,而在「Docker 被规则挡在门外」——这是两类修法完全不同的病。
二、病因处置速查表
| 报错现象 / 场景 | 可能原因 | 快速验证 | 处置 |
|---|---|---|---|
| forbidden path outside the build context | COPY 引用了上下文外的文件(../) | 看报错给出的路径 | 把文件复制进上下文,或把构建根上移 |
| file not found in build context | 相对路径基准错:相对上下文根而非 Dockerfile 位置 | 在上下文根 ls 报错路径 | 改成相对上下文根的路径 |
| 文件明明存在却 not found | 被 .dockerignore 排除 | cat .dockerignore 对照 | 删排除规则或加 ! 例外 |
| 本地能 build、CI 不能 | CI 上下文目录与本地不同 | CI 日志看 build 命令末参数 | 统一 CI 的上下文路径约定 |
| -v 挂载后容器里是空目录 | 源路径不存在,新版本静默建了空目录 | 宿主机 ls 源路径 | 先建源目录再挂载,注意拼写 |
| COPY --from=builder 报错 | 阶段名拼错或阶段顺序在引用之后 | 对照 Dockerfile 的 AS 命名 | 修正阶段名,注意大小写敏感 |
| COPY 符号链接进容器失效 | 链接目标在上下文外,拷过去成死链 | ls -l 看链接指向 | 拷真实文件,不用跨上下文链接 |
| ADD 远程 URL 失败 | 网络或 URL 失效(不是本地路径问题) | 单独 curl 该 URL | 改用 COPY + 构建前置下载步骤 |
三、排查决策图
下面这张图是标准排查路线,颜色按角色区分:红是报错入口与命中的根因,蓝是排查动作,绿是通过分支,橙是修复动作,紫是防复发沉淀。
读这张图抓住排查主线:路径类报错先别急着找文件,先确认 Docker 的「视野范围」——构建期视野是 build 命令最后那个参数(构建上下文根),运行期视野是 -v 的宿主机源路径。所有「明明存在却报不存在」的灵异事件,九成是「文件在你的视野里、不在 Docker 的视野里」。
四、逐条排查展开
先钉死构建上下文是哪个目录。 docker build -t myapp /proj/demo 最后的 /proj/demo 就是上下文根——构建启动时 Docker 把这个目录整个打包发给 daemon,COPY 只能在这个包里找文件。Dockerfile 放在别处(-f /proj/demo/docker/Dockerfile)不改变上下文根,COPY 的相对路径永远相对上下文根,不相对 Dockerfile 所在目录。这是新人踩得最多的坑:Dockerfile 在 docker/ 子目录,写 COPY docker/app.conf /etc/ 才对,写 COPY app.conf 就 not found。
../ 与绝对路径一律出界。 COPY ../shared/config.yaml 与 COPY /etc/hostname 都会报 forbidden path outside the build context——这不是 bug,是安全设计:防止 Dockerfile 把宿主机任意文件打进镜像。处置两条路:把依赖文件复制/软链进上下文目录;或把构建根上移一层(docker build -f demo/Dockerfile /proj),让共享目录进入视野,代价是上下文变大、构建变慢,要配好 .dockerignore 裁剪。
.dockerignore 是「文件在却报不存在」的惯犯。 报错原文里 or excluded by .dockerignore 已经给了提示,但很多人不读完。典型场景:.dockerignore 写了 target/ 想忽略编译产物,结果 Dockerfile 偏偏要 COPY target/app.jar——在 CI 里产物是上一步刚编出来的,本地却靠旧文件「碰巧能 build」,于是出现「本地行 CI 不行」。处置:排除规则放宽(target/* 加 !target/app.jar 例外),或调整流水线让 COPY 的源不被排除。
运行期挂载的静默空目录。 老版本 daemon 对不存在的源路径直接报 source path does not exist;新版本默认静默创建空目录再挂载——不报错,但容器里 /data 是空的,应用写到里面的数据落在一个没人知道的宿主机空目录上。排查:
ls -ld /proj/demo/data # 宿主机确认源路径真实存在且有内容
docker inspect <容器> --format '{{json .Mounts}}' # 看实际挂载映射-v 路径拼写错误(多一个字母、大小写错了)在静默建目录的行为下毫无报错,数据「写入即丢失」的表现会把你引向应用层排查——先核对 Mounts 再怀疑应用。
多阶段构建的阶段名是另一条隐形路径。 COPY --from=builder /build/app.jar /app/ 里的 builder 必须与前文 FROM ... AS builder 严格一致(大小写敏感),且引用不能超前于定义。报 stage not found 时先数 Dockerfile 里有几个 AS。另外 --from 后面的路径相对那个阶段的文件系统根,与当前阶段的 WORKDIR 无关。
符号链接跨上下文必死。 上下文里的软链接指向 ../shared/lib.so,打包时 Docker 只带链接不带目标,容器里就是死链。ls -l 看链接指向,凡是指出上下文根的,换成真实文件再 build。
五、规范做法与预防
- 上下文根进文档:项目 README 写明「构建命令在仓库根执行、上下文是
.」,CI 与本地同约定。 - COPY 路径统一相对上下文根:Code review 看到
../直接打回。 .dockerignore与 Dockerfile 同审:改一边必须核对另一边,例外用!显式写出。- 挂载前先建源目录:部署脚本里
mkdir -p源路径,并对关键挂载在启动后ls自检。 - 阶段名见名知义:
AS builder/AS runtime固定命名,禁止AS b1这类短名。 - 构建冒烟测试:CI 里 build 完
docker run起容器ls关键路径,路径错在合并前炸出来。
这一篇在知识体系里的位置
本篇是 docker 排错速查簇的路径篇,定位「构建上下文边界与挂载源路径」:路径对了但权限不够看 docker 权限被拒速查;build 拉基底镜像失败看 docker 拉取限流速查 与 docker 镜像找不到速查;镜像构建出来进程崩溃看 docker 容器段错误速查;容器起来了但不响应看 docker 容器卡死与健康检查挂起速查。「先确认 Docker 的视野范围」这条心法,适用于一切路径类报错。
一句话总结
docker 路径不存在先分清构建期还是运行期:构建期认准「COPY 的视野只有构建上下文根这一个目录树」——../ 出界、相对路径基准错(相对上下文根而非 Dockerfile 位置)、.dockerignore 排除误伤是三大主因,报错原文给出的完整路径与 outside the build context / excluded by .dockerignore 字样直接指路;运行期 -v 挂载先 ls 宿主机源路径、再 inspect .Mounts 核对映射,新版 daemon 对不存在的源路径静默建空目录,「不报错但数据丢失」比报错更危险。上下文结构进文档、.dockerignore 与 Dockerfile 同审、挂载前建目录加自检,这类报错即可基本绝迹。