--read-only单独启用会导致容器启动失败或日志写入报错,因其使根文件系统全只读,而应用默认需向/tmp、/var/log、/run等路径写入;必须配合--tmpfs或-v显式挂载可写路径才能正常运行。

只读文件系统不能单独启用,必须配合可写路径的显式声明,否则容器大概率启动失败或日志写不进去。
为什么 --read-only 一加就报错 Permission denied
容器内应用默认会尝试往 /var/log、/tmp、/run 等路径写日志、pid 文件或临时数据。一旦整个根文件系统设为只读,这些操作立刻被内核拒绝,表现为:open /var/log/app.log: permission denied 或直接 crash。
- 不是所有路径都适合只读:像
/etc/ssl/certs、/usr/share/nginx/html这类纯静态内容可以安全只读;但/var/log、/tmp必须额外放开 - 只读 ≠ 完全锁死:Docker 的
--read-only控制的是挂载时的 rootfs 层,不影响--tmpfs或-v显式挂载的可写卷 - 镜像构建阶段的写入不受影响:只读限制只在容器运行时生效,Dockerfile 中的
RUN指令照常执行
如何正确组合 --read-only 和 tmpfs
最常用且稳定的方案是:根文件系统只读 + 内存临时文件系统支持必要写入。这样既防篡改,又不破坏应用行为。
使用 Python 脚本下载 Docker 镜像并打包为 tar 文件。用户说“下载镜像”“拉取镜像”“pull xxx”“帮我下载 nginx 镜像”等时触发。支持 SOCKS5 代理直连(推荐)和国内镜像站加速两种模式。
- 用
--tmpfs指定可写路径,例如:--tmpfs /tmp:rw,size=16m,mode=1777 - 常见必须放开的路径包括:
/tmp、/run、/var/run、/var/log(如果应用坚持写这里) - 不要对
/proc、/sys、/dev做 tmpfs —— 它们由 Docker 自动挂载,且需特殊权限 - 示例命令:
docker run --read-only --tmpfs /tmp --tmpfs /run --tmpfs /var/log nginx:alpine
Docker Compose 中 read_only 的两种写法区别
Compose 支持两个层级的只读控制,作用范围完全不同,混用容易出问题:
-
read_only: true(服务级):作用于整个容器的 rootfs,等效于docker run --read-only -
volumes: - ./conf:/etc/nginx:ro(卷级):仅该挂载点只读,rootfs 仍是可写的 - 若同时启用两者,
read_only: true优先级更高,整个文件系统只读,此时:ro卷挂载无实际意义 - 推荐策略:生产环境统一用
read_only: true+tmpfs,避免依赖主机路径的:ro挂载,减少宿主耦合
只读配置下证书和配置文件的正确挂载方式
很多用户想把 TLS 证书或 Nginx 配置以只读方式挂载,但直接 -v ./certs:/etc/ssl/certs:ro 存在隐患:
- 挂载点父目录(如
/etc/ssl)仍可写,攻击者可能创建新子目录绕过限制 更安全的做法是:先用 - 证书路径建议挂载到非标准位置,如
/run/secrets/tls.crt,再通过 entrypoint 软链接或环境变量注入应用 - 若使用 Kubernetes,优先走
Secret对象 +readOnly: true卷挂载,比 Docker 原生命令更可控
--read-only 锁死整个 rootfs,再用 -v 显式挂载证书目录,并确保挂载目标路径本身不存在于原始镜像中(避免覆盖冲突)真正麻烦的不是加 --read-only,而是确认应用所有隐式写入路径 —— 比如某些 Python 库会在 /usr/local/lib/python3.x/site-packages 下动态生成 .pyc 缓存,这种路径往往被忽略,直到容器反复重启才暴露。

















