直接使用--read-only参数即可使容器根文件系统只读,它通过oci spec传递给runc在mount阶段将/以ro挂载;必须配套--tmpfs为/tmp、/run等路径提供可写空间,否则应用易失败。

直接用 --read-only 启动容器即可生效
容器根文件系统只读不是靠 runtime-args 配置的,而是 Docker CLI 原生命令行参数 --read-only 控制的。它会通过 OCI spec 传递给 runc,在 mount 阶段将 / 以 ro 方式挂载。无需修改 daemon.json 或调用 --runtime-args ——Docker 并不支持这个参数名,--runtime-args 是无效写法,实际可用的是 --runtime(指定运行时名称)或 daemon 级的 runtimes 配置。
验证是否生效:进容器执行 mount | grep "on / type",输出中应含 ro,;或运行 touch /test,报错 Read-only file system 即成功。
必须配套挂载 /tmp、/run 等路径为 tmpfs
只设 --read-only 后,/tmp、/run、/var/run、/var/log 全部继承只读属性,但 nginx、supervisord、systemd-init 类进程依赖这些路径写 PID、socket、锁或日志。不处理会导致启动失败或静默崩溃。
-
--tmpfs /tmp:rw,size=10M:通用临时目录,多数程序默认使用 -
--tmpfs /run:rw,size=5M和--tmpfs /var/run:rw,size=5M:存放 socket、PID 文件等,关键路径 -
--tmpfs /var/log:rw:仅当应用坚持写本地日志(非 stdout),否则应改用标准输出
tmpfs 不落盘、重启即清空,天然契合“临时性”,也规避了 volume 引入的权限扩大风险。
挂载可写卷必须显式声明路径和权限
只读根下,所有可写路径都必须显式挂载,未挂载的路径一律只读。不能依赖镜像内已有目录自动变可写。
- 上传目录:
-v upload-data:/app/uploads:rw(命名卷,推荐) - Redis AOF 数据:
-v redis-cache:/data:rw - 证书或静态资源:
-v cert-volume:/etc/tls:ro(务必加:ro显式禁止写入) - 禁用 bind mount 宿主机敏感路径(如
/etc、/root),尤其避免:z或:ZSELinux 标签,除非明确知晓其提权后果
真正需要 runtime-level 配置的场景极少
只有在全局强制所有容器默认启用只读根时,才需修改 /etc/docker/daemon.json,例如:
{
"default-runtime": "runc",
"runtimes": {
"runc": {
"path": "runc",
"runtimeArgs": ["--no-new-privileges"]
}
}
}
注意:--no-new-privileges 是 runc 的参数,用于禁止 setuid/setgid 提权,但它**不控制只读根**;只读根仍由 CLI 的 --read-only 决定。Docker 27+ 虽默认启用 no-new-privileges,但该行为与只读文件系统无关,两者需分别配置、协同生效。
容易忽略的一点是:即使启用了 --read-only,若容器内进程以 root 运行且未丢弃 capabilities,仍可能通过 mount --remount,rw / 尝试绕过——所以必须配合 --cap-drop=ALL 和 --user 使用,否则只读形同虚设。











