Docker tmpfs 已可写,非 root 进程仍报 Permission denied
核对临时挂载的实际 UID、GID 与权限,用 Compose tmpfs 选项匹配应用账户,并验证容器重建和重启后的状态。
容器的根文件系统保持只读,应用的临时目录也已经挂成可写 tmpfs,创建文件却仍报 Permission denied。如果目录归属 root:root、权限为 0755,而应用以普通 UID 运行,可写挂载仍然不允许这个用户在目录里创建文件。
以下针对 Linux Docker Engine 和 Docker Compose V2 的服务级 tmpfs 配置。它解决的是已确认的挂载目录所有者不匹配;若错误是 Read-only file system,或失败路径根本不在这个挂载下,要先修正挂载目标,不能靠改权限解决。
对照实际进程和挂载目录
先从应用配置确认运行用户,再检查失败容器。example-app 和 /run/example 都是占位值。下面的容器内检查要求镜像包含 id 和 ls:
docker inspect example-app --format '{{json .Config.User}}'
docker inspect example-app --format '{{json .HostConfig.Tmpfs}}'
docker exec example-app id
docker exec example-app ls -ldn /run/example
Config.User 反映创建配置;启动脚本还可能切换账户,因此要以实际写文件的应用进程身份为准。exec id 只显示该次 exec 的身份,不能证明后台应用没有自行降权。精简镜像没有这些工具时,使用已有的应用诊断能力,不必为检查而把应用改成 root。
例如,应用 UID 是 1000,目录却属于 UID 0,0755 只给所有者写权限,普通用户自然不能创建文件。若 UID、权限都正确,继续核对父目录的搜索权限、完整失败路径和实际挂载;不要把所有访问拒绝都认定为同一个原因。
在挂载时设置所有者
下面片段假设已确认应用使用 1000:1000,并且只把可丢弃的临时文件写入 /run/example。实际合并到现有服务时,保留镜像、端口、健康检查与其他配置,不要照抄用户编号覆盖镜像原有身份:
services:
app:
image: registry.example.com/team/app:tested
user: "1000:1000"
read_only: true
tmpfs:
- /run/example:uid=1000,gid=1000,mode=0700,size=16m
uid、gid 指挂载后的目录所有者,mode=0700 让该用户可以访问和写入。需要同组进程共享时,可在确认组身份后选用 0770;无须为了一个服务账户直接放宽为所有用户可写。
这里使用服务级 tmpfs 字符串形式。不要把 uid、gid 原样塞进 volumes 长语法的 tmpfs 对象:这两套字段结构不同。使用 docker run 时,对应的是 --tmpfs /run/example:uid=1000,gid=1000,mode=0700,size=16m;也不能把这些名字随意拼到 --mount 的参数里。
镜像构建阶段对原目录执行 chown,不等于控制了运行时挂载根目录的所有者。tmpfs 挂上来会遮住该位置的镜像内容。不要为修权限删除整个系统目录,也不要把包含必要配置的整个 /var 挂成空 tmpfs。
让新容器采用配置,再检查重启
保存修改前的 Compose 配置,在隔离环境验证合并结果。以下命令中的 app 是 Compose 服务名:
docker compose config
docker compose up -d --force-recreate app
重建会中断该服务并丢弃旧 tmpfs 中的内容。执行前必须确认目录没有需要保留的上传文件、数据库或业务状态;输出配置也可能包含环境变量,不要未经处理直接发到公开渠道。
新容器启动后,重新核对挂载选项、实际目录 UID/GID、权限和应用日志,用应用正常的临时文件操作确认原错误消失。仅看到容器 Running 不足以确认写入成功。随后按测试环境的正常方式重启服务,再做同样的核对:tmpfs 权限在某些情况下可能重启后恢复,临时 chmod 成功不能代替持久部署配置验证。
若新配置没有体现在运行容器中,先确认操作的是同一 Compose 项目、服务和 Docker 后端。若配置已正确传入,但实际属性仍不符合预期,保留版本、挂载与目录信息继续定位,不要循环加权限。
size=16m 只是容量示例,需要与应用的临时文件量和容器内存预算匹配。tmpfs 可能使用宿主交换空间,也不能视为保证秘密永不落盘的存储。回退时恢复保存的 Compose 配置并重建服务;旧 tmpfs 内容不会随配置回退而恢复。


