Docker 容器启用只读根文件系统后,临时写目录怎么挂载
来源:17golang原创
时间:2026-10-08 10:19:02 131浏览 收藏
Docker 容器启用只读根文件系统后,不是把整个容器变成“完全不能写”,而是把写权限收缩到明确挂载的目录。最实用的分法是:/tmp、/run、进程锁和短期缓存使用 tmpfs;必须跨容器保留的数据使用 Docker volume;只有宿主机确实需要直接读写文件时才考虑 bind mount。
官方文档:https://docs.docker.com/
推荐组合:--read-only 锁住镜像根文件系统,只为应用真实写目录增加 tmpfs 或 volume。不要为了让程序启动而把整个工作目录重新挂成可写。
步骤1:先盘点应用到底写哪些目录
先把目录分成两类。重启后可以丢失的 PID、Socket、临时文件、上传中间文件和可重建缓存属于临时数据;数据库、用户上传成品、任务结果和状态文件属于持久数据。常见候选如下:
| 目录示例 | 数据性质 | 推荐挂载 |
|---|---|---|
/tmp、/run | 进程退出后可丢失 | tmpfs |
/var/cache/myapp | 可重建缓存 | 优先 tmpfs,并限制大小 |
/var/lib/myapp | 业务状态或用户数据 | Docker volume |
/etc/myapp | 配置,运行时不应修改 | 保持只读;必要时只读 bind mount |
可见成功状态:每个写目录都被标记为“临时”或“持久”,没有把整个 /var、/app 之类的大目录笼统设为可写。
步骤2:先只启用只读根文件系统,暴露遗漏路径
先用最小配置启动一次,让应用报出真正缺少的写目录。下面的命令故意不添加写挂载:
# 先锁住根文件系统,用启动日志定位应用仍然尝试写入的路径 docker run --rm --read-only --name myapp-check myapp:latest
预期现象是应用正常启动,或明确报告某个目录为 Read-only file system。如果报错路径是日志目录,优先把日志改为标准输出;如果是 PID、Socket 或临时文件,再为那个具体目录配置 tmpfs。

可见成功状态:容器配置显示根文件系统为只读,错误信息只剩下具体写目录,而不是模糊的启动失败。
步骤3:用 tmpfs 挂载 /tmp 与 /run
tmpfs 的内容不会写入容器可写层,容器停止后数据消失,适合临时目录。下面同时限制大小和目录权限:
# 根文件系统保持只读,只开放两个内存临时目录 docker run --rm --read-only --name myapp \ --mount type=tmpfs,dst=/tmp,tmpfs-size=67108864,tmpfs-mode=1777 \ --mount type=tmpfs,dst=/run,tmpfs-size=16777216,tmpfs-mode=755 \ myapp:latest
tmpfs-size 使用字节数;示例分别约为 64 MiB 和 16 MiB。/tmp 常用 1777,但专用目录应尽量改为 0700 或 0770。tmpfs 会占用容器内存额度,并且在宿主机启用交换分区时存在被换出的可能,因此它不是“敏感数据绝不落盘”的绝对保证。
可见成功状态:应用能够创建临时文件,容器停止并重新创建后这些文件不再存在。
步骤4:需要保留的数据改用 volume
如果 /var/lib/myapp 中保存的是业务数据,就不能用 tmpfs。先创建命名卷,再把它挂到唯一需要持久化的路径:
# 创建由 Docker 管理的持久卷 docker volume create myapp-data # 临时目录使用 tmpfs,业务数据使用命名卷 docker run -d --read-only --name myapp \ --mount type=tmpfs,dst=/tmp,tmpfs-size=67108864,tmpfs-mode=1777 \ --mount type=tmpfs,dst=/run,tmpfs-size=16777216,tmpfs-mode=755 \ --mount type=volume,src=myapp-data,dst=/var/lib/myapp \ myapp:latest
volume 独立于容器生命周期,删除并重建容器后仍可重新挂载。若镜像在挂载点预置了文件,挂载会遮住该路径原有内容;上线前要确认初始化逻辑,不要把“看不到镜像内文件”误判为文件被删除。
可见成功状态:重建容器后,/var/lib/myapp 的业务数据仍然存在,而 /tmp 中的临时文件已经清空。
步骤5:在 Docker Compose 中固化配置
确认目录边界后,把配置写入 Compose,避免每次手工拼接启动参数:
services:
app:
image: myapp:latest
read_only: true # 根文件系统保持只读
tmpfs:
- /tmp:size=64m,mode=1777 # 通用临时文件
- /run:size=16m,mode=755 # PID、Socket 等运行时文件
volumes:
- app-data:/var/lib/myapp # 需要跨容器保留的业务数据
volumes:
app-data: {} # 使用 Docker 管理的命名卷
# 按 Compose 配置创建或更新服务 docker compose up -d
非 root 进程若仍提示 Permission denied,先核对容器用户的 UID、GID 和目录 mode。不要用 chmod 777 一把放开;应让目录所有者和应用用户匹配,或只赋予目标组写权限。

可见成功状态:服务详情同时显示“根文件系统:只读”、两个 tmpfs 挂载和一个 volume 挂载,容器健康状态正常。
步骤6:做一次正反向写入验证
最终验证要同时证明两件事:根文件系统不能写,显式挂载目录可以写。镜像包含 shell 时可执行:
# 查看实际挂载类型、目标路径和读写属性
docker inspect myapp --format '{{json .Mounts}}'
# /etc 写入应失败;/tmp、/run 与数据卷写入应成功
docker exec myapp sh -c '
touch /etc/should-fail && echo "异常:/etc 可写" || echo "正确:/etc 只读"
touch /tmp/tmp-ok && echo "正确:/tmp 可写"
touch /run/run-ok && echo "正确:/run 可写"
touch /var/lib/myapp/data-ok && echo "正确:数据卷可写"
'
精简镜像可能没有 shell,此时应通过应用健康检查、专用诊断子命令或测试接口验证,不要为了测试临时给生产镜像安装 shell。Docker inspect 的挂载列表应能区分 tmpfs 与 volume,根文件系统只读状态则由容器配置确认。

可见成功状态:/etc 的写入失败,三个显式挂载点写入成功;重建容器后临时文件消失、数据卷文件保留。
常见问题
tmpfs 和 volume 应该怎么选?
问自己“容器重建后这个数据必须保留吗”。答案为否时用 tmpfs;答案为是时用 volume。缓存虽然可以重建,但若体积较大或重建成本高,也可以选择 volume,并单独设计清理策略。
为什么挂了 tmpfs 仍然 Permission denied?
只读问题已经解决,但目录权限可能与应用用户不匹配。检查容器 UID、GID 和挂载 mode。多用户共享目录可用组权限,专用目录则优先收紧到应用用户。
可以把整个 /var 挂成可写吗?
不建议。大范围可写会削弱只读根文件系统的价值,还会隐藏镜像中的原始目录。应从错误日志和应用配置中找出最小写路径,一个目录一个目录开放。
tmpfs 会不会把容器内存占满?
有可能。为每个 tmpfs 设置与业务峰值相符的上限,并把它纳入容器内存预算。上传临时文件和缓存尤其需要限额与清理机制,否则应用会从“磁盘写满”变成“内存压力”。
-
329 收藏
-
253 收藏
-
236 收藏
-
497 收藏
-
科技周边 · 业界新闻 | 1天前 | 云原生 · kubernetes · 业界新闻 · Kubernetes 1.35 Pod重启 restartPolicy restartPolicyRules RestartAllContainers195 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习