
做 Linux 运维这些年/tmp 目录是个绕不开的话题。进程崩溃留下的 core 文件、解压到一半的压缩包、下载未完成的临时文件、各种软件运行时生成的缓存全都会堆在这个目录里。平时没人注意它可一旦磁盘被写满或者多用户机器上有人删不掉别人的临时文件大家才会想起来——原来 /tmp 也是要管的。这篇就来聊聊现代 Linux 系统管理临时文件的标准做法systemd-tmpfiles。它解决什么问题、配置规则怎么读懂、实战怎么调参、以及我踩过哪些坑一次说清楚。适合刚接触 Linux 系统管理的运维新人也适合想把手动 crontab 清理脚本替换掉的进阶用户。1. 为什么 /tmp 总是让人头疼1.1 /tmp 和 /var/tmp 的分工先从最基础的讲起。Linux 沿用了 Unix 的设计把临时文件分成两个区域/tmp 和 /var/tmp。/tmp 是短命临时文件的家系统重启后内容通常会被清空尤其在现在的 systemd 环境下很多发行版直接把 /tmp 挂成 tmpfs重启即丢/var/tmp 则留给那些跨重启还要保留的临时数据比如编辑器崩溃后的恢复文件、软件安装器的暂存目录。这个区别很重要因为不少新人会把东西随手丢进 /tmp结果一重启数据没了还以为是系统故障。/tmp 还有一个关键特点它是全局可写目录权限是 1777。这个 1 是 sticky bit粘滞位加了它之后任何用户都能在这个目录里创建文件但只有文件的所有者或者 root才能删除或重命名别人的文件。要是没有这个位公共目录就会变成垃圾场——A 用户能顺手删掉 B 用户的文件这在多用户机器上是完全不可接受的。那临时文件为什么会越积越多程序崩溃时的 core dump、包管理器解包残留、浏览器下载块、日志轮转产生的历史文件以及大量写完忘了删的进程临时文件都会长期留在 /tmp 里。磁盘本来是用来装正经数据的不是给这些一次性垃圾囤积的所以必须有一套机制定期清理。1.2 传统清理方案为什么不够用早年间大家怎么管 /tmp最常见的方案是 crontab 里挂一条 find 命令比如find /tmp -type f -atime 3 -exec rm -f {} \;这条命令的作用是把 /tmp 下 3 天没被访问过的普通文件删掉。用 atime访问时间而不是 mtime修改时间来判断理由是临时文件只要最近被读就算活着。这条命令看着简单实际坑不少。第一-exec rm -f {} \;这种方式对文件名里的空格、换行、单双引号非常敏感一旦有特殊字符很可能报错或者误删。虽然可以加上-print0配xargs -0来缓解但这条 crontab 会越来越长、越来越难读。第二atime 在现代文件系统上默认是延迟更新的relatime 挂载选项你拿到的 atime 未必是真实的最后访问时间。第三find 的-mtime 3和-mtime 3边界差一天稍微不注意就把还在用的文件删了。还有一类专门的工具叫 tmpwatchFedora/RHEL 系和 tmpreaperDebian/Ubuntu 系它们的思路本质上和 find 脚本没区别只是把参数包装得好用了一点。这类工具最大的问题不是功能而是它和系统的其他部分没有协同——它只管删不负责创建缺失的临时目录修正权限排除某些路径而且每个发行版行为还不一样换一台机器就得重新适应。真正让 /tmp 管理走上标准化轨道的是 systemd 时代。systemd 把临时文件该长什么样、该留多久、哪些路径要排除全部变成声明式的配置文件配合开机服务和定时器统一了各发行版的做法。这个机制就是本文的主角systemd-tmpfiles。2. systemd-tmpfiles 的核心设计2.1 声明式配置替代脚本systemd-tmpfiles 不是一个单独常驻的监控进程而是一个命令、一组配置文件和两个 systemd 单元的组合。命令叫systemd-tmpfiles配置放在 tmpfiles.d 目录下服务单元是systemd-tmpfiles-setup.service开机时执行创建类规则定时器是systemd-tmpfiles-clean.timer周期执行清理类规则。它最核心的设计思想是声明式管理你想让系统里存在怎样的临时文件布局直接在配置文件里写清楚而不是写一段如果...就...的 shell 脚本。配置文件是纯文本每一行格式非常规整类型 路径 权限 属主 属组 存活时间 参数每一行解决一件事。比如默认的 /usr/lib/tmpfiles.d/tmp.conf 里就有两行v /tmp 1777 root root 10d v /var/tmp 1777 root root 30d意思是/tmp 和 /var/tmp 这两个目录如果不存在就在启动时创建权限 1777属主 root里面的内容超过 10 天/tmp或 30 天/var/tmp会被清理。注意这两行包含了两套逻辑。v指令负责确保目录存在并且权限正确这个在开机时执行后面的10d和30d则作为清理时限在systemd-tmpfiles-clean定时器触发时使用。这种做法的好处很明显第一配置是纯文本能放 git 里做版本管理出问题可以 diff第二语法统一所有用 systemd 的发行版都认同一套规则跨发行版经验可以直接迁移第三权限和属主被固化在配置里不会因为某次手工创建目录给了错误权限而留下安全隐患。2.2 配置文件加载规则配置文件分布在一套标准的层级目录里优先级从高到低是/etc/tmpfiles.d/ —— 系统管理员自定义/run/tmpfiles.d/ —— 运行时临时配置重启失效/usr/lib/tmpfiles.d/ —— 发行版和软件包自带的默认规则systemd 会按这个顺序把配置合并优先级高的目录会覆盖优先级低的同名配置。比如发行版在 /usr/lib/tmpfiles.d/tmp.conf 里写了 /tmp 保留 10 天你想改成 3 天不要直接去改 /usr/lib 下的文件——系统升级时那个文件会被覆盖。正确做法是在 /etc/tmpfiles.d/ 下建一个文件把你想要覆盖的规则写进去。更稳妥的做法是换个文件名比如 /etc/tmpfiles.d/override-tmp.conf所有 .conf 文件会按字典序加载后者对同一路径、同类型的重复定义会覆盖前者。这里有一条重要经验规则的覆盖是按路径 类型来匹配的。如果你在 /etc 下对 /tmp 写了一条d规则它不会自动覆盖 /usr/lib 里同路径的v规则因为类型不同。d和v在执行时可能都会作用到 /tmp 上但清理语义不一样后面细说。所以覆盖规则时最好保持类型一致或者用x/X规则把默认规则排除掉再写自己的新规则。2.3 类型指令速查表systemd-tmpfiles 支持的类型很多实际管理 /tmp 主要会用到下面这些我按用途分了三组。创建和维护目录、文件的常用类型类型含义典型场景d创建目录不存在才创建已存在则修正权限/属主确保 /run/xxx 存在D创建目录并清空已有内容初始化运行时目录v创建或校验目录和 d 类似但只在启动时处理默认 tmp.conff / F创建普通文件F 会先清空再写内容生成默认配置文件w向文件写入内容不创建文件写 sysfs 参数清理和排除相关的类型类型含义典型场景e清空目录内内容但保留目录本身清理缓存目录内容q / Q类似 d / D但只在目录存在时处理不报错可选的运行时目录r / R递归删除文件/目录R 带子目录移除废弃的运行时文件x / X排除路径X 表示连目录内容一起排除防止 /tmp 子目录被误清其他类型还有 L创建符号链接、C复制文件树、a/z设置 ACL 和 SELinux 上下文等日常管理 /tmp 很少用到但要知道它们存在。这里专门提醒新手d和D一字之差后果差别很大。d只在目录不存在时创建存在就检查权限D则是不管目录里有什么执行时直接把内容清空重来。你如果在配置文件里把 /var/tmp 写成了 D那系统每次开机都会把 /var/tmp 清一遍跨重启保留临时文件的语义就全毁了。这种错误用systemd-tmpfiles --create一跑就能发现但后果已经造成了。3. 动手配置 /tmp 清理策略3.1 查看当前生效规则不少人的第一个问题是我机器上现在到底有哪些 tmpfiles 规则答案是systemd-tmpfiles --cat-config。这个命令会把三个目录里的配置合并展开打印出最终生效的完整清单。systemd-tmpfiles --cat-config输出内容很多建议先过滤一下跟 tmp 相关的部分systemd-tmpfiles --cat-config | grep -E ^[vdqQ] /(var/)?tmp|^[xX] /tmp在多数发行版上你会看到类似这样的输出v /tmp 1777 root root 10d v /var/tmp 1777 root root 30d X /tmp X /var/tmp如果想看某个具体目录被哪些规则管理可以用--list加上路径前缀。这个命令在新版本 systemd 里很好用systemd-tmpfiles --list /tmp它会列出所有作用在 /tmp 路径上的规则以及来源文件。排查为什么 /tmp 被清得那么快时这个命令比逐个翻文件快得多。3.2 自定义清理规则的关键参数假设我们的需求是/tmp 下除了系统默认的 10 天之外还要对几个特定场景单独管。比如 /tmp/build-cache 目录里的编译缓存最多保留 2 天/tmp/session 目录里的会话临时文件 1 小时没动过就删另外 /tmp 下有个 user-backup 目录是某用户临时导出的数据绝对不能自动删。针对这些需求新建一个 /etc/tmpfiles.d/user-tmp.conf# 编译缓存只留两天 d /tmp/build-cache 1777 root root 2d # 会话临时文件 1 小时清理 d /tmp/session 1777 root root 1h # 备份目录完全排除在自动清理之外 x /tmp/user-backup注意看前两条规则权限用了 1777原因和前面说的一样这是共享临时目录的标准权限。age 参数分别是2d和1h。age 的语法很简单数字 单位单位支持 s秒、m分钟、h小时、d天、w周、month月、y年还可以组合比如1h30m表示 90 分钟。x /tmp/user-backup这一行不加 age它的作用是告诉清理逻辑扫描 /tmp 时跳过这个路径。这是x和X的区别x排除的是路径本身如果 /tmp/user-backup 里面还有子目录清理程序仍然可能进入子目录去检查X才是连整个子树一起排除。如果你要保护的目录下面还有多层结构用X更保险X /tmp/user-backup为什么默认的 tmp.conf 里在v /tmp后面还带X /tmp因为它要防止另一种情况当系统里存在一个更上层的清理规则比如有人写了一条清理根目录的规则扫描根目录时会把 /tmp 当普通子目录递归进去。X /tmp就是给 /tmp 上了一道保险确保它只被自己的v规则管理不被别的规则误伤。这个设计细节很值得学习——你在写大型清理规则时也应该用X给那些特殊的挂载点或重要目录上保险。3.3 定时器与手动执行规则写好了系统是怎么定期执行清理的答案是systemd-tmpfiles-clean.timer。可以查一下它的状态systemctl cat systemd-tmpfiles-clean.timer默认配置是开机后 15 分钟触发第一次清理之后每隔一天执行一次OnBootSec15min OnUnitActiveSec1d对应的服务单元systemd-tmpfiles-clean.service会执行systemd-tmpfiles --clean--clean会遍历配置里带 age 参数的规则把过期的文件删掉。它和开机时执行的systemd-tmpfiles --create分工明确create 负责把目录和文件建出来clean 负责清干净。改完配置后先手动 create 一下让新目录建出来systemd-tmpfiles --create /etc/tmpfiles.d/user-tmp.conf想立即验证清理效果可以指定配置文件执行 cleansystemd-tmpfiles --clean /etc/tmpfiles.d/user-tmp.conf这条命令只处理你指定的规则文件不处理系统默认配置用来验证自己的规则非常合适。注意systemd-tmpfiles 没有专门的--dry-run参数但你可以先在测试目录里放几个旧文件跑一遍 clean 看结果效果等同演练。需要提醒的是--clean是按 age 判定过期它会根据文件的最后修改时间mtime和访问时间atime与当前时间做比较。如果文件恰好在阈值内比如你写 1h 而文件是 50 分钟前修改的它不会被删必须严格超过阈值才会清理。3.4 把 /tmp 挂成 tmpfs 的权衡很多现代发行版默认把 /tmp 挂为 tmpfs内存文件系统这在 systemd 环境里由 tmp.mount 单元控制。可以确认一下自己系统上 /tmp 到底是什么df -h /tmp systemctl status tmp.mount如果是 tmpfsdf输出的 Filesystem 一栏会是 tmpfs大小默认约等于物理内存的一半。用 tmpfs 的好处是读写速度极快而且重启自动清空完美契合短命临时文件的语义。坏处是它会占用内存一旦有程序往 /tmp 里写大文件比如解压一个大 tar 包可能把内存和 swap 吃干拖垮整个系统。如果你希望 /tmp 是 tmpfs 但限制大小可以在 /etc/fstab 里显式配置tmpfs /tmp tmpfs defaults,noatime,nosuid,nodev,size4G 0 0这里size4G把上限固定为 4GBnoatime减少元数据操作nosuid和nodev是安全加固禁止 setuid 程序和设备文件出现在 /tmp 里这是多用户环境的基本功。反过来如果应用要频繁往 /tmp 写大文件比如容器镜像构建、视频转码我建议还是把 /tmp 放到真实磁盘上同时保留 systemd-tmpfiles 的清理策略。判断标准很简单/tmp 里单个文件经常超过内存的十分之一就别用 tmpfs 了。无论 /tmp 是 tmpfs 还是磁盘目录systemd-tmpfiles 都能正常工作清理逻辑在文件系统之上运行不关心底层是什么介质。4. 常见问题与排查技巧实录4.1 清理没有按预期执行最常遇到的故障是我明明写了规则/tmp 就是不清。排查顺序推荐下面这套。先确认定时器是活着的systemctl list-timers systemd-tmpfiles-clean.timer如果定时器显示 inactive可能是被 mask 了或者服务单元执行失败。接着看服务日志journalctl -u systemd-tmpfiles-clean.service --since 1 hour ago日志里最常见的报错是Permission denied。原因通常是规则里写的路径和实际目录状态不一致。比如规则写d /tmp/session 1777但实际目录已经以 0700 存在且属于别的用户systemd-tmpfiles 想修正权限时没有足够权限可能整条规则会失败。注意systemd-tmpfiles 对规则的处理行为遇到错误时不一定继续执行后面的规则所以日志排查非常关键不要只盯着配置看。另一种情况是 age 单位写错了。有人写 age 为10没有单位systemd-tmpfiles 会直接拒绝加载这条规则日志里能看到Failed to parse age value这类报错。age 必须带单位数字和单位之间不能有空格。还有一种比较容易迷惑的场景规则存在、定时器正常但某个子目录里的文件始终没被删。这时去检查是不是有x/X规则把它排除了。用systemd-tmpfiles --cat-config和--list对着看比在配置文件里人肉搜索更快。4.2 误删与漏删怎么避免误删是临时文件管理里最可怕的事故。我在生产机器上见过一次因清理规则参数写错导致的事故有人把 /tmp 的规则 age 写成1h结果 /tmp 下超过 1 小时未修改的普通文件全被清掉了包括某个应用运行时必须读取的配置缓存应用直接崩溃工单堆了一屏。从那之后我的铁律是临时文件的清理规则只减不增。新上线的规则先把 age 写成默认值的 2 到 3 倍跑一周观察确认没有误删后再收紧。另外任何排除需求优先用X而不是x。宁可多排除不能漏排除漏排除了文件会被清掉多排除了最多是磁盘多占一点空间性质完全不同。漏删的情况通常和 age 的统计方式有关。默认清理会参考文件的时间戳组合有些文件 mtime 很久没变但 atime 不断更新比如被频繁读取的缓存它们就永远年轻不会被清掉。如果你想让这类文件也被清理得考虑把整个目录用e指令周期清空或者在应用层面控制缓存位置。写D之前一定要想清楚这相当于定时炸弹只在确认目录里没有任何有价值数据时才用。4.3 tmpfs 被占满的应急处理/tmp 是 tmpfs 时最典型的故障是内存被写满机器开始疯狂使用 swap甚至触发 OOM。遇到这种情况第一步是找出 /tmp 下的大文件du -sh /tmp/* | sort -rh | head -20第二步是确认这些大文件的属主和进程。用lsof看哪个进程打开了 /tmp 下的大文件对比之后再决定怎么处理千万别一言不合就 rm。很多时候是某个解压进程还没结束大文件正在被写入等它结束内存就释放了。如果确认是残留垃圾删除后执行sync然后观察内存是否回落。如果 tmpfs 经常被写满说明业务场景不适合 tmpfs按 3.4 节的方法改回磁盘 /tmp 或调大 size 限制同时把清理规则收紧。改完记得用mount -a验证 fstab 语法否则下次重启可能因为 fstab 错误进入 emergency mode那就更麻烦了。4.4 容器与安全模块的坑在容器环境里systemd-tmpfiles 的行为要特别留意。容器内如果跑的是精简版 systemd很多镜像根本没有 systemdtmpfiles 规则不会自动执行需要在镜像构建或容器启动脚本里手动调用systemd-tmpfiles --create。我见过不少基础镜像里的 /tmp 权限不对原因就是只 COPY 了配置文件没执行 create。SELinux 环境下还有个容易忽视的点tmpfiles.d 配置里可以带 SELinux 标签参数z类型如果规则里写的标签和系统 SELinux 策略不匹配创建出来的文件可能被拒访问。排查时看到Permission denied别只查文件权限用audit2why查一下 SELinux 事件能省不少弯路。5. 从实战中总结的几条经验最后分享几条我自己的操作习惯。第一每次写完 tmpfiles 配置先跑systemd-tmpfiles --cat-config确认规则被正确加载再跑一次--clean指定自己的文件在测试目录里验证最后才交给生产环境。这套流程多花五分钟能省掉后面几小时的排障。第二/tmp 的配置建议纳入版本管理。跟着项目的配置仓库一起走换机器、排查问题时规则从哪里来、谁改的、为什么改一查便知。靠记忆维护规则时间一长必定出偏差。第三系统管理这东西规则越简单越可靠。宁可让临时文件多活几天也别为了省那点磁盘空间误删正在使用的数据。/tmp 管得好不好不看你删得多快而看你删完之后系统稳不稳。