bigywater.tech
Docker · 47

只读根文件系统:--read-only 配合 tmpfs 的写法

给容器加上 --read-only 之后,到底哪些地方还能写?为什么程序会因为找不到临时目录而启动失败?这篇逐个位置验证,并演示用 tmpfs 和 volume 开口子。

只剩 1 个
--read-only 下 10 个测试位置里仍可写的个数(/dev/shm)
EROFS
只读容器里写任何镜像路径得到的错误,包括 /etc/hosts
docker diff 为空
只读容器往 tmpfs 里写文件之后的 docker diff 输出

哪里还能写

实测 · 本机执行输出
  默认:
    /new-file=可写;  /tmp/x=可写;  /var/tmp/x=可写;  /dev/shm/x=可写;  /run/x=可写;  /etc/hosts=可写;  /etc/resolv.conf=可写;  /etc/hostname=可写;  /data/x=可写;  /usr/local/x=可写;  MOUNT_/ ['rw'];  tempfile=可用
  --read-only:
    /new-file=EROFS;  /tmp/x=EROFS;  /var/tmp/x=EROFS;  /dev/shm/x=可写;  /run/x=EROFS;  /etc/hosts=EROFS;  /etc/resolv.conf=EROFS;  /etc/hostname=EROFS;  /data/x=EROFS;  /usr/local/x=EROFS;  MOUNT_/ ['ro'];  tempfile=FileNotFoundError [Errno 2] No usable temporary directory found in ['/tmp', '/var/tmp', '/usr/tmp'

默认容器里到处可写;加 --read-only 后根文件系统是 ro,连 Docker 生成的 /etc/hosts、/etc/resolv.conf、/etc/hostname 也变成只读。/dev/shm 仍然可写。

常见的启动失败

实测 · 本机执行输出
  --read-only --tmpfs /tmp --tmpfs /run:
    /new-file=EROFS;  /tmp/x=可写;  /var/tmp/x=EROFS;  /dev/shm/x=可写;  /run/x=可写;  /etc/hosts=EROFS;  /etc/resolv.conf=EROFS;  /etc/hostname=EROFS;  /data/x=EROFS;  /usr/local/x=EROFS;  MOUNT_/ ['ro'];  tempfile=可用
  --read-only -v 命名卷:/data:
    /new-file=EROFS;  /tmp/x=EROFS;  /var/tmp/x=EROFS;  /dev/shm/x=可写;  /run/x=EROFS;  /etc/hosts=EROFS;  /etc/resolv.conf=EROFS;  /etc/hostname=EROFS;  /data/x=可写;  /usr/local/x=EROFS;  MOUNT_/ ['ro'];  tempfile=FileNotFoundError [Errno 2] No usable temporary directory found in ['/tmp', '/var/tmp', '/usr/tmp'
  --read-only -v 命名卷:/data:ro:
    /new-file=EROFS;  /tmp/x=EROFS;  /var/tmp/x=EROFS;  /dev/shm/x=可写;  /run/x=EROFS;  /etc/hosts=EROFS;  /etc/resolv.conf=EROFS;  /etc/hostname=EROFS;  /data/x=EROFS;  /usr/local/x=EROFS;  MOUNT_/ ['ro'];  tempfile=FileNotFoundError [Errno 2] No usable temporary directory found in ['/tmp', '/var/tmp', '/usr/tmp'

很多程序默认往 /tmp 写临时文件。只读容器里 Python 的 tempfile 直接报找不到可用的临时目录。给 --tmpfs /tmp 就能恢复(c24 讲了 tmpfs 的大小和内存占用)。要保存的数据放命名卷或 bind mount,加 :ro 则也变只读。

docker diff

实测 · 本机执行输出
  HostConfig.ReadonlyRootfs = true
  容器里往 /tmp(tmpfs)写了文件后,docker diff 输出:(空)
  往 /root 写 → 退出码 1;sh: can't create /root/a: Read-only file system
  对比:不带 --read-only 写 /root/a 和 /tmp/b 后,docker diff:C /tmp ; A /tmp/b ; C /root ; A /root/a

只读容器里没有可写层的改动,往 tmpfs 写的内容也不会出现在 docker diff;普通容器则会列出新增(A)和改动(C)。

分步演示

只读根文件系统
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / Docker Desktop(Engine 29.8.2,容器跑在 Docker Desktop 自带的 Linux 虚拟机里,内核与宿主机的 macOS 不同);镜像为 linux/arm64;需要看虚拟机内部时用特权容器 + nsenter;计时用 time / date +%s%N,数字每次运行会有小幅抖动。测试程序是 python:3.12-alpine 里的脚本,用 os.open 尝试创建或打开写;errno 取自异常;每种配置运行一次;实验后已删除容器、卷和镜像
    • 没有验证:真实应用(nginx、postgres)在只读下需要开放哪些路径、/proc 与 /sys 的只读性、--read-only 与 --tmpfs 选项(noexec 等)的组合、Compose 的 read_only: true、Kubernetes 的 readOnlyRootFilesystem
    京ICP备2026067502号-1京公网安备11010502063487号