绑定挂载权限问题是什么
绑定挂载把宿主目录原样映射进容器,容器内进程以某个 UID 运行时,写入该目录是否需要授权、写出来的文件属于谁,全部由宿主上的数字属主与权限位决定。容器与宿主看到的是同一份 inode 权限,因此「容器内写不进去」与「宿主上文件属主是 root」其实是同一个问题的两面。定位思路很直接:比对两侧的 uid/gid 与权限位。
基本信息
| 观察命令 | 宿主 ls -ln 目录(用 -n 看数字属主),容器内 id 看进程身份 |
|---|---|
| 常见成因 | 容器以 root 运行或容器用户 UID 与宿主目录属主不一致 |
| 运行时对齐 | --user $(id -u):$(id -g) 让容器用当前宿主用户身份 |
| 构建期对齐 | 镜像里创建固定 UID 并用 COPY --chown 授权 |
| SELinux 场景 | 绑定挂载加 :z 或 :Z 重标标签,否则读取被拒 |
| 替代方案 | 改用命名卷,让 Docker 管理属主关系 |
典型使用场景
- 开发环境把源码目录挂进容器,避免容器产出 root 属主文件影响宿主编辑
- 日志与上传目录挂载到宿主,供采集器读取
- 共享目录被多个容器读写,需要统一身份
- RHEL/CentOS 等启用 SELinux 的主机上挂载宿主目录
- 排查「容器启动正常但写文件失败」这类静默问题
对齐与验证
对齐与验证
# 方式一:让容器用宿主当前用户身份运行,产出文件属主与宿主一致
docker run --rm --user "$(id -u):$(id -g)" -v "$PWD/out:/out" alpine touch /out/test
# 方式二:默认 root 运行,观察宿主侧产出的属主差异
docker run --rm -v "$PWD/out:/out" alpine sh -c 'id; touch /out/test2'
# 用 -n 查看数字属主,判断到底是谁写的
ls -ln "$PWD/out"
# SELinux 主机上需要重标标签(:z 共享,:Z 独占)
docker run --rm -v /srv/data:/data:z alpine touch /data/probe现象与成因对照
| 现象 | 成因 | 处理方向 |
|---|---|---|
| 容器内 Permission denied | 容器 UID 与目录属主不一致 | 统一 UID 或运行前授权目录 |
| 宿主文件属主为 root | 容器以默认 root 运行 | 镜像内声明非 root 用户 |
| 宿主能改、容器不能写 | 宿主用户与容器用户不同号 | 按数字对齐,而不是按名字 |
| SELinux 报权限拒绝 | 标签不符 | 挂载加 z/Z 重标 |
| 首次启动正常、后续写入失败 | 日志或缓存目录未预先授权 | 构建期创建并授权目录 |
排查顺序建议:先在容器里执行 id 看身份,再在宿主用 ls -ln 看目标目录数字属主,两者一比就能定位是身份不一致还是权限位不足,不必反复改配置试错。
命名卷通常比绑定挂载少一类权限烦恼:卷首次使用时会把镜像里该目录的内容与属主复制进去,运行用户一般天然可写;代价是宿主上查看数据需要 root 权限。