在 Docker Compose 中启用 read_only: true(服务顶层配置)可使容器根文件系统只读,有效防止后门写入;需配套挂载 tmpfs 到 /tmp、/run 等路径提供必要可写空间,并通过 mount 和 docker inspect 验证生效。

在 Docker Compose 中配置只读根文件系统,核心是启用容器级的 --read-only 行为,而非仅对某个挂载卷设为只读。很多用户误以为在 volumes 里加 read_only: true 就能保护整个容器,其实那只影响那个特定路径——根文件系统仍可写,后门仍可落盘到 /etc、/usr/bin 或 /lib 等关键位置。
用 read_only: true 启用容器根文件系统只读
这是最直接有效的防护动作,对应单容器命令中的 --read-only。必须在服务的 host_config 级别声明,Docker Compose v3.8+ 通过 read_only 字段支持:
- 在
docker-compose.yml的服务定义下添加read_only: true - 该设置会让整个容器根目录(
/)以只读方式挂载,包括/bin、/etc、/usr、/var等子路径 - 任何尝试向这些路径写入的行为(如下载恶意二进制、覆盖 SSH 配置、注入 cron 任务)都会立即失败,返回
Read-only file system
必须配套挂载 tmpfs 提供运行时可写空间
只设 read_only: true 后,绝大多数应用会启动失败或静默崩溃,因为它们默认依赖以下路径写临时数据:
-
/tmp:脚本解压、缓存生成、临时 socket -
/run和/var/run:存放 PID 文件、Unix socket、supervisord 运行时状态 -
/var/log(可选):若应用坚持本地日志,需单独放开;更推荐统一输出到 stdout/stderr
在 Compose 中用 tmpfs 声明内存卷即可:
volumes:
- type: tmpfs
target: /tmp
tmpfs:
size: 10M
mode: 1777
- type: tmpfs
target: /run
tmpfs:
size: 5M
- type: tmpfs
target: /var/run
tmpfs:
size: 5M
避免混淆:卷挂载的 read_only ≠ 容器根只读
很多人把这两者混用,导致防护失效:
-
volumes: - ./conf:/etc/nginx:ro或read_only: true在 volume 条目中 → 仅让/etc/nginx这个挂载点只读,不影响/etc/hosts、/etc/passwd等其他路径 -
read_only: true在服务顶层(与image、volumes同级)→ 整个根文件系统只读,这才是防后门的关键防线 - 两者可以共存:根只读 + 某些挂载点也只读(比如证书目录),形成叠加防护
验证是否真正生效
部署后务必检查,不能只看配置写了没写:
- 进容器执行:
mount | grep "on / type",输出应含ro,(注意逗号) - 尝试写根路径:
touch /test或echo 1 > /etc/hostname,应报错Read-only file system - 确认 tmpfs 可写:
touch /tmp/ok应成功,ls -ld /tmp应显示drwxrwxrwt - 用
docker inspect myapp -f '{{.HostConfig.ReadonlyRootfs}}'查返回值是否为true


















