核心是理清“谁在写、写到哪、对方认不认你”三层关系:默认:rw仅控制挂载模式,真正决定能否写入的是宿主机与容器uid/gid是否匹配,以及selinux/apparmor等安全模块是否拦截。

Docker 绑定挂载(Bind Mount)的权限设置,核心不是“在 Docker 命令里加个参数就能一键搞定”,而是要理清谁在写、写到哪、对方认不认你这三层关系。默认 :rw 看似有写权限,但真正卡住你的,往往是宿主机目录的属主 UID/GID 和容器内进程 UID/GID 不匹配,或者 SELinux/AppArmor 拦了一道。
下面分几个关键场景说清楚怎么设:
明确挂载读写模式
这是最表层的控制,用 -v 后的冒号选项指定:
-
:rw(或省略)→ 容器可读可写(但能否成功取决于底层权限) -
:ro→ 强制只读,适合配置文件、证书、yum 源等不希望被修改的内容 - 注意:
:Z或:z是 SELinux 专用标记(仅限启用 SELinux 的系统),不是通用权限开关,别乱加
匹配 UID/GID 是写入成功的前提
容器内进程能不能往挂载目录里写,最终看 Linux 文件系统认不认它的 UID。常见做法有三种:
- 在宿主机上改目录属主,使其匹配容器内用户 ID:
sudo chown -R 1001:1001 /host/data
(假设容器应用以 UID 1001 运行)
- 启动容器时用
--user显式指定 UID/GID,让它和宿主机目录所有者一致:docker run -v /host/data:/app/data --user $(id -u):$(id -g) myimage
- 在 Dockerfile 里提前创建用户并设好 UID,让镜像自带一致性:
RUN groupadd -g 1001 app && useradd -u 1001 -g app app USER app
绕不开的安全模块要单独处理
如果你用的是 CentOS/RHEL(SELinux 默认开启)或 Ubuntu(AppArmor),即使 UID 对了、权限开了,也可能报 Operation not permitted。这时:
- 先确认是否是它在拦:
getenforce # 返回 Enforcing 表示 SELinux 生效
- 临时验证可用
:Z(私有卷)或:z(共享卷)挂载:docker run -v /host/data:/app/data:Z myimage
⚠️ 注意:
Z/z是为 SELinux 标签打标,生产环境建议配合策略调整,而非长期依赖
宿主机路径必须存在且权限合理
Docker 23.0+ 版本不会自动创建不存在的绑定挂载路径,所以:
- 务必手动创建宿主机目录,并设好基础权限:
mkdir -p /host/data chmod 755 /host/data # 或更宽松的 775,视团队协作需求而定
- 如果挂载的是单个文件(如
/etc/nginx/conf.d/app.conf),确保该文件存在,且容器用户有读权限(:ro更稳妥)
不复杂但容易忽略











