read_only: true 作用于容器根文件系统(/),防止其内进程修改 /bin、/etc 等路径,但完全不影响宿主机根分区;真正保护宿主机需禁用 privileged、不挂载 / 或 /etc 等敏感路径,并启用 userns-remap。

在 docker-compose.yml 中无法直接通过 read_only: true 限制宿主机的根分区(即 /),这是常见误解。read_only: true 作用于容器内的文件系统挂载点,它让容器的根文件系统(/)以只读方式挂载,从而防止容器内进程意外或恶意修改自身系统文件(如 /bin、/etc、/usr 等),但它完全不影响宿主机的根分区 —— 宿主机文件系统是否可写,由 Docker daemon 的运行权限和挂载方式决定,与容器配置无关。
要真正保护宿主机根分区不被容器篡改,关键在于不挂载宿主机根目录进容器,并严格控制 volumes 和 privileged 权限。
以下是实际可行的防护策略:
✅ 正确使用 read_only: true(保护容器自身)
services:
app:
image: nginx:alpine
read_only: true
# 注意:启用 read_only 后,容器需能写入 /tmp、/proc、/sys、/dev 等伪文件系统
tmpfs:
- /tmp
- /run
- /var/run
# 若需日志或临时配置,显式挂载可写卷(非宿主机根路径!)
volumes:
- app-logs:/var/log/nginx:rw
volumes:
app-logs:⚠️ 注意:read_only: true 会禁用整个容器根层(包括 /etc/hostname、/etc/hosts),因此必须配合 tmpfs 或 volumes 提供必要可写路径,否则容器可能启动失败。
❌ 绝对禁止的行为(会导致宿主机根被篡改)
# 危险!不要这样做: volumes: - /:/host-root:rw # ← 允许容器直接读写宿主机 / # 或更隐蔽的: - /etc:/host-etc:rw # ← 可修改宿主机密码、服务配置等
只要没显式挂载宿主机根目录(/)或敏感路径(如 /etc, /usr/bin, /lib/systemd),容器就无法直接修改宿主机根分区 —— 这是 Linux 命名空间和挂载传播隔离的基本保障。
? 强化宿主机防护的关键配置
-
禁用
privileged: trueprivileged模式绕过几乎所有隔离机制,允许容器操作宿主机设备、挂载文件系统、修改内核参数,等同于赋予 root 权限。# 错误示例(除非绝对必要且受控): privileged: true # 推荐:按需授予特定能力 cap_add: - CAP_NET_BIND_SERVICE # 如需绑定 80 端口 # 避免 CAP_SYS_ADMIN(可挂载/卸载文件系统)
-
使用用户命名空间映射(userns_mode)
在dockerd配置中启用userns-remap,使容器内 root 映射为宿主机普通用户,即使容器逃逸也无法获得真实 root 权限。docker-compose.yml本身不配置此项,需在/etc/docker/daemon.json设置:{ "userns-remap": "default" } 限制挂载传播(mount propagation)
默认rprivate已足够安全;避免使用shared或slave,防止容器内mount影响宿主机挂载表。
? 验证是否有效
进入容器检查:
docker-compose exec app sh touch /etc/test # 应失败(read_only) touch /tmp/test # 应成功(tmpfs 可写) ls /host-root # 应不存在(未挂载则无此目录)
不复杂但容易忽略:容器安全的核心不是“让容器只读”,而是“不让它碰宿主机关键路径”。read_only: true 是加固容器内部的手段,而守住宿主机根的真正防线,是谨慎声明 volumes、禁用 privileged、并合理配置 Docker daemon。


















