遇到 Docker 挂载卷 Permission denied 报错,核心原因是宿主机目录所有者与容器内运行用户的 UID/GID 不一致。解决思路是统一两端权限,通常通过调整宿主机权限或指定容器运行用户来修复。
先说结论:这是典型的 Linux 文件权限问题,容器进程没有宿主机的文件写入权限。
- 先确认:使用 stat 查看宿主机 UID/GID,使用 docker inspect 查看容器用户
- 先处理:使用 chown 修改宿主机目录归属或 docker run `--user` 指定用户
- 再验证:在容器内尝试创建文件确认写入是否成功
命令速用版
# 方法一:修改宿主机目录所有者(假设容器内是 root/UID 0)
sudo chown -R 0:0 /path/to/host/data
# 方法二:启动容器时指定用户(假设宿主机目录属于 1000:1000)
docker run -u 1000:1000 -v /path/to/host/data:/app/data image_name
为什么会这样
Docker 容器默认可能以 root 用户运行,但挂载的宿主机目录可能属于普通用户。Linux 内核在执行挂载卷操作时,会严格检查进程 UID/GID 与文件所有权的匹配关系。如果容器内进程 UID 与宿主机文件所有者 UID 不一致,且其他用户无写入权限,内核就会拒绝访问,报出 Permission denied。
分步处理
1. 检查宿主机目录权限
ls -ln /path/to/host/data
stat -c '%u:%g' /path/to/host/data
记录输出中的 UID 和 GID 数字。
2. 检查镜像默认用户
docker run `--rm` image_name id
如果镜像未指定用户,通常显示 uid=0(root)。
3. 检查已运行容器用户
docker inspect `--format`='{{.Config.User}}' <container_id>
如果输出为空,默认为 root。
4. 方案选择
如果希望容器适应宿主机权限,使用 docker run -u 指定 UID:GID。
如果希望宿主机适应容器,使用 sudo chown 修改目录归属。
5. 特殊情况 SELinux
在开启 SELinux 的系统(如 CentOS/RHEL),可能需要给卷添加 :z 或 :Z 后缀,或使用 chcon 修改上下文。
已运行容器的修正方案
容器启动后无法直接修改运行用户,需选择以下方案:
- 方案 A:修改宿主机权限匹配当前容器用户(推荐,无需重启)
- 方案 B:停止并删除容器,使用 -u 参数重新创建
怎么验证是否生效
docker exec -it container_id sh
touch /app/data/testfile
ls -l /app/data/testfile
如果没有报错且文件存在,说明权限已通。
常见坑与安全建议
- rootless Docker 模式下,用户命名空间映射会导致 UID 偏移,直接 chown 可能无效。
- 只修改了目录权限但忽略了父目录的执行权限(x 位)。
- 使用用户名而非数字 UID 进行映射,不同系统用户名可能不一致。
- 安全建议:生产环境尽量避免容器以 root 运行,优先使用 -u 指定非 root 用户。
参考来源
- Docker Official Documentation, "Manage data in Docker", https://docs.docker.com/storage/volumes/
- Docker Official Documentation, "Configure user namespace isolation", https://docs.docker.com/engine/security/userns-remap/