最有效防护是挂载时加:ro或read_only:true,由内核VFS拦截写操作;需结合路径判断、tmpfs供给和权限协同,对配置、证书、启动参数等三类目录默认只读,推荐长语法,避免漏写:ro、全局/etc只读及挂载敏感路径未设只读,并叠加tmpfs、最小权限与非root运行。

直接在挂载时加 :ro 或 read_only: true 是最有效、最轻量的防护手段——它由内核 VFS 层拦截写操作,哪怕容器内是 root 也无法覆盖、删除或重命名文件。但这不是“一加就完事”,必须结合路径判断、临时空间供给和权限协同,才能既防篡改又不崩服务。
哪些目录必须设为只读
这三类内容一旦被运行时修改,极易引发故障或成为攻击入口,应默认只读挂载:
- Nginx/Apache 主配置与站点配置(如 /etc/nginx/nginx.conf、/etc/httpd/conf.d/)
- 证书与私钥文件(如 /etc/tls/fullchain.pem、/etc/ssl/private/key.pem)
- 应用启动参数或环境模板(如 /app/config/app.yaml、/etc/default/myapp)
两种写法,推荐长语法
短语法简洁,但长语法更清晰、易审计、兼容性更好,生产环境首选:
- 短语法(适合快速验证): volumes: - ./conf:/etc/myapp:ro
- 长语法(明确语义,避免歧义): volumes: - type: bind source: ./conf target: /etc/myapp read_only: true
二者功能完全等价,:ro 就是 read_only: true 的简写,但长语法能避免与其他选项(如 SELinux 标签 :Z 或一致性策略 consistency)混淆。
必须避开的三个典型错误
- 漏写 :ro:Docker 所有 bind mount 默认都是可写(:rw),不写后缀即代表可写
- 对整个 /etc 目录做只读 bind mount:/etc 下部分路径(如 /etc/resolv.conf、/etc/mtab)需运行时生成或更新,强行只读会导致服务启动失败
- 挂载宿主机敏感路径且未设只读:例如 /root/.ssh 或 /proc/sys,一旦容器被入侵,攻击者可直接覆盖密钥或篡改内核参数
配合 tmpfs 和最小权限才真正落地
只读挂载只是第一道防线,必须叠加以下措施才能形成纵深防御:
- 为必需路径挂载 tmpfs:如 --tmpfs /tmp:rw,size=10M、--tmpfs /run:rw,size=5M,满足 PID、socket、锁等临时写入需求,数据驻留内存、退出即清
- 严格控制可写卷范围:仅对真正需要持久化的路径挂载,如 -v upload-data:/app/uploads:rw;证书/配置类路径务必用 :ro
- 非 root 用户运行容器:Dockerfile 中创建普通用户并执行 USER 1001,同时确保宿主机挂载目录属主匹配该 UID
- 丢弃非必要能力:启动时加 --cap-drop=ALL --cap-add=NET_BIND_SERVICE,禁用 CAP_SYS_ADMIN 等高危 capability


















