tmpfs本身不直接导致宿主机oom,但未设size的tmpfs配置会引发多容器内存争抢,挤占物理内存与swap,最终触发内核全局oom killer,杀掉高内存进程;残留子进程卡在d状态,造成容器“假死”——docker ps显示running却无法exec、无日志、无响应。
tmpfs本身不直接导致宿主机oom,但它的不当配置会成为触发宿主机级内存耗尽的关键推手——当多个容器挂载了未设size的tmpfs,且应用密集写入(如日志缓冲、图像转码、大文件解压),它们共同挤占物理内存和swap,最终使内核触发全局oom killer,杀掉高内存占用进程。此时你看到的“容器假死”,其实是主进程已被oomkilled,但残留的子进程或僵尸线程仍卡在d状态(不可中断睡眠),表现为docker ps显示running、却无法exec、logs无输出、http请求无响应。
确认是否为tmpfs引发的宿主机级OOM
先区分是单个容器OOM还是宿主机OOM:
– 查看系统级OOM日志:dmesg -T | grep -i "killed process",若出现多个不同进程(不止你的容器)被kill,说明是全局OOM;
– 检查tmpfs总体占用:df -h -t tmpfs,重点关注 /dev/shm、/tmp、/run 及容器挂载点,观察总用量是否接近宿主机内存;
– 统计Shmem内存使用:grep Shmem /proc/meminfo,该值包含所有tmpfs + POSIX共享内存,若接近总内存80%以上,风险极高;
– 运行 find /proc/*/mounts -exec grep -l "tmpfs.*size=" {} \; 2>/dev/null | wc -l,统计显式设size的tmpfs数量,若远少于实际挂载数,说明大量tmpfs处于默认50%隐式限制状态。
立即止血:释放tmpfs内存并恢复服务
不要重启容器——它可能刚启动就再次写爆tmpfs。
– 清空已挂载tmpfs中的非关键内容:docker exec -it
– 对运行中但卡住的容器,强制清理其tmpfs挂载点对应目录(需在宿主机操作):find /var/lib/docker/overlay2/*/merged/tmp -maxdepth 0 -type d -exec sh -c 'if mount | grep -q \"$(readlink -f $1)\"; then rm -rf $1/*; fi' _ {} \;;
– 若Shmem持续高位,临时降低tmpfs默认上限(需重启dockerd生效):echo 'OPTIONS="--default-ulimit memlock=-1:-1"' >> /etc/sysconfig/docker(仅缓解,非根治);
– 快速释放POSIX共享内存:rm -rf /dev/shm/*(glibc依赖此路径,谨慎执行,建议配合应用重启)。
长期防御:从配置、监控到应用层协同
单靠运维干预无法根治,需三层联动:
– 容器层强制约束:Docker一律用 --tmpfs /tmp:rw,noexec,nosuid,size=128m;Kubernetes中emptyDir必须设 medium: Memory + sizeLimit: 128Mi,禁止留空;
– 宿主机级兜底:启用CGroup v2,为docker.slice设置memory.max(如sudo mkdir -p /sys/fs/cgroup/docker.slice && echo "16G" > /sys/fs/cgroup/docker.slice/memory.max),防止容器集群吃光全部内存;
– 应用层适配:缓存类应用(如Redis客户端临时序列化、Java应用/tmp下jar解压)应主动检测statfs()返回的f_bavail,写入前预留20%余量;日志框架(Log4j2、Zap)禁用/tmp作为异步缓冲目录,改用ring-buffer内存队列;
– 监控告警项:采集node_memory_MemAvailable_bytes + node_memory_Shmemp_bytes + container_fs_usage_bytes{device=~".*tmpfs.*"},当Shmem > 总内存×40%且MemAvailable
特别注意:避免“伪安全”配置陷阱
以下做法看似合理,实则无效甚至加剧问题:
– 用size=50%替代具体数值:仍会随宿主机扩容而无限增长,失去控制意义;
– 在Kubernetes中只设resources.limits.memory却不设emptyDir.sizeLimit:前者管堆内存,后者管tmpfs,二者完全独立;
– 把/tmp挂载为tmpfs后,又让应用调用mktemp -d反复创建子目录:每个子目录本身不占内存,但其中写入的文件会叠加计入tmpfs总量,极易突破预期;
– 认为“swap开启就安全”:tmpfs可swap,但swap IO会拖垮整体性能,且OOM Killer仍可能优先杀应用进程而非swap守护进程。










