容器能读不能写,大概率是Windows文件共享未启用、UID/GID不匹配、umask过严或SELinux标签缺失所致;须依次验证docker inspect中RW为true、Docker Desktop共享白名单、宿主机与容器UID/GID一致、umask设为0002及必要时添加:z/:Z挂载标签。

容器能读不能写,大概率不是挂载模式设成了 :ro,而是宿主机目录权限、UID/GID 匹配或 Windows 文件共享机制出了问题。先看 docker inspect 确认 RW 是 true,再往下排查。
确认挂载是否真为可写(别被默认值骗)
很多人以为不加后缀就是可写,但实际可能被父目录或 Docker Desktop 隐式限制。必须验证:
- 运行
docker inspect <container></container>,在Mounts数组里找对应路径,检查RW字段是否为true - Windows 下即使命令写了
:rw,若该路径未在 Docker Desktop Settings → Resources → File Sharing 中勾选,RW也会强制变成false,且不报错——只在 daemon 日志里留一条user declined directory sharing - Linux/macOS 上可通过
touch /host/path/test && ls -l /host/path/test在宿主机侧确认目录本身支持写入(排除 NFS/只读挂载等底层限制)
Windows Docker Desktop 必须检查文件共享白名单
这是 Windows 用户最常卡住的环节:报错不明确、命令无异常、docker run 成功但挂载失效。核心是 Docker Desktop 的访问控制独立于系统权限。
- 打开 Docker Desktop → Settings → Resources → File Sharing
- 确保你要挂载的路径所在盘符(如
D:\)或具体目录(如D:\myapp\data)已被勾选 - 点 Apply & Restart,**必须重启 Docker Desktop**,仅重启容器无效
- 若路径含中文、空格或特殊符号(如
C:\Users\张三\project),建议改用 WSL2 内部路径(如/home/user/project)或重定向到/c/Users/...格式并确保父级已共享
UID/GID 不匹配导致“能创建但 Permission denied”
现象是容器内 ls -l 能看到文件,echo "test" > file 却报错;或者日志里出现 Operation not permitted。Linux 权限看数字 ID,不是用户名。
- 查宿主机目录属主:
ls -ld /d/data(Windows WSL2 下)或ls -ld /mnt/d/data,记下 UID/GID(比如1001:1001) - 查容器内进程 UID:
docker run -v /d/data:/data -it --rm alpine id,看输出的uid=0(root)还是其他值 - 若不一致,两个办法二选一:
– 启动时用--user 1001:1001强制对齐
– 或在宿主机执行sudo chown -R 1001:1001 /d/data(WSL2 中需用wsl -u root切换) - 注意:Windows 原生路径(
C:\...)在 WSL2 中由 drvfs 挂载,默认 UID/GID 映射为0:0,无法直接 chown;此时只能用--user或改用 WSL2 原生路径
SELinux/AppArmor 或 umask 导致新文件不可写
即使目录本身可写,容器进程创建的新文件也可能因权限太严而被后续操作拒绝(比如 PHP 写日志失败、Nginx 生成临时文件失败)。
- 进容器执行
umask,若输出是0077或0027,说明新建文件默认只有所有者可写(600/640),组和其他用户无权写入 - 临时测试:运行
umask 0002 && touch test && ls -l test,看权限是否变成-rw-rw-r-- - 生产环境应在入口脚本开头加
umask 0002,而非依赖系统默认值 - SELinux 环境(如 WSL2 启用了 SELinux)下,即使 umask 和 UID 都对,仍需挂载时加
:z(多容器共享)或:Z(单容器私有),否则新文件继承不到正确上下文标签
真正难缠的不是某一个点,而是多个限制叠加:Windows 共享没开 + WSL2 drvfs UID 固定为 0 + 容器内进程用 www-data(UID 33)+ umask 0077。这种组合下,Permission denied 会反复出现,每次改一个参数都像在碰运气。务必按顺序验证:共享白名单 → RW 字段 → UID/GID → umask → SELinux 标签,跳步排查只会延长故障时间。


















