构建时“permission denied”或“operation not permitted”主因是WSL2 drvfs挂载限制与Docker构建缓存共同导致的权限幻觉:宿主机脚本无x位、UID/GID不匹配、COPY未显式赋权(如COPY --chmod=755)、或/mnt/c路径下chmod无效;应移至WSL2原生路径并用--no-cache验证。

构建时提示“permission denied”或“operation not permitted”,基本是宿主机挂载路径、Dockerfile中复制的文件、或构建上下文里的脚本缺少执行位或所有权不匹配——不是 Docker Desktop 本身的问题,而是 Linux 权限模型在 Windows/WSL2 环境下的投射失真。
检查宿主机挂载路径的 UID/GID 是否与容器内用户匹配
你在 Windows 上用 docker build 或 docker run -v $(pwd):/app,实际路径由 WSL2 内核解析,而 WSL2 默认把 Windows 用户映射为 UID 1000(但可能被覆盖)。若 Dockerfile 中指定了 USER 1001,而挂载进来的 start.sh 属主是 1000 且权限是 700,容器里 UID 1001 就无权执行。
- 在 WSL2 终端中运行
ls -ld .和ls -l start.sh,确认 UID 数字(不是用户名) - 检查 Dockerfile 中
USER指令是否显式设了 UID,比如USER 1001;没写则默认是 root(0),但 rootless 模式下会被重映射 - 临时验证:构建时加
--build-arg USER_ID=$(id -u),并在 Dockerfile 里用RUN useradd -u $USER_ID -m appuser && USER appuser
Dockerfile 中 COPY 的脚本没有执行权限
Windows 文件系统本身不存 x 位,COPY 进镜像后默认是 644。即使你在资源管理器里点了“属性→允许执行”,对 Linux 容器无效。
- 构建阶段必须显式赋权:
COPY --chmod=755 entrypoint.sh /usr/local/bin/entrypoint.sh(Docker ≥ 20.10) - 兼容旧版写法:
COPY entrypoint.sh /usr/local/bin/+RUN chmod +x /usr/local/bin/entrypoint.sh - 避免
RUN chmod 777:最小权限原则,755足够让组和其他人执行,又不开放写权限
WSL2 下 /mnt/c/... 挂载点导致的权限“假死”
如果你在 Docker Desktop 的 WSL2 后端里直接从 /mnt/c/Users/xxx/project 构建,该路径由 drvfs 驱动挂载,默认以 metadata,uid=1000,gid=1000 挂载,但 drvfs 不支持 chmod 或 chown。你执行 chmod +x 看似成功,实则无效,容器内仍报 permission denied。
- 解决方案:把项目移到 WSL2 原生文件系统,比如
~/project,再构建 - 验证方式:在 WSL2 终端运行
stat -c "%U %G %a" ./start.sh,若输出中权限数字(如644)不变,说明 drvfs 挂载点限制生效 - 绕过方法(仅调试):构建时不挂载,改用
COPY把脚本打进镜像,彻底脱离 drvfs
构建缓存污染导致权限“看似修复实则失效”
你改了 COPY --chmod 并重新构建,但 Docker 复用旧层缓存,权限指令根本没重跑——尤其当你只改了 Dockerfile 最后几行时。
- 强制跳过缓存验证:
docker build --no-cache -t test . - 更准确定位哪一层出问题:
docker history your-image,看COPY和RUN chmod对应的层是否显示或尺寸异常小 - 终极清理:
docker builder prune(注意会清空所有构建缓存)
真正卡住的地方往往不是“要不要加 chmod”,而是 WSL2 的 drvfs 挂载机制和 Docker 构建缓存共同制造的“权限幻觉”——改完 Dockerfile 却不生效,八成是缓存或挂载点在捣鬼。











