在Ubuntu系统运维中,systemd-tmpfiles是负责管理临时文件和目录生命周期的核心组件。它通过读取配置文件(/etc/tmpfiles.d/*.conf、/usr/lib/tmpfiles.d/*.conf、/run/tmpfiles.d/*.conf)来决定哪些临时目录需要定期清理、哪些需要创建、权限如何设置。很多运维人员发现/tmp目录下堆积了大量过期文件却不知道如何精准控制清理规则,或者想自定义清理策略却不清楚配置语法。这篇文章直接告诉你:systemd-tmpfiles的清理规则本质上就是通过配置文件中的类型(type)、路径(path)、模式(mode)、年龄(age)、参数(argument)这几个字段来定义的,掌握这套语法,你就能完全掌控系统临时目录的清理行为。

systemd-tmpfiles的工作原理和核心概念

systemd-tmpfiles是一个在系统启动时运行的服务(tmpfiles.service),它会扫描三个目录下的配置文件并执行对应操作。核心操作类型有四种:创建目录(d)、创建文件(f)、清理过期内容(x/X/r/R/z/Z)。其中清理类操作是运维最关心的部分。x表示只清理目录下的文件和子目录但保留目录本身;X表示清理目录下所有内容包括目录;r表示递归清理;z表示根据文件年龄清理。这些操作都可以配合age参数指定"超过多少天没被访问就清理"。

默认配置文件的位置和优先级

Ubuntu系统中tmpfiles的配置文件分布在三个位置,优先级从低到高依次是:/usr/lib/tmpfiles.d/(包安装自带,不建议修改)、/etc/tmpfiles.d/(管理员自定义,优先级最高)、/run/tmpfiles.d/(运行时临时配置,重启失效)。运维人员要自定义清理规则,应该在/etc/tmpfiles.d/目录下创建新的.conf文件,文件名建议用有意义的前缀如10-custom-cleanup.conf,数字前缀控制加载顺序。

清理规则的具体配置语法详解

每一行配置的基本格式是:类型 路径 模式 年龄 参数。下面逐一拆解。类型字段:d=创建目录,f=创建文件,x=清理目录内容,X=清理目录及内容,r=递归清理,z=按年龄清理。路径字段:写绝对路径如/tmp/myapp。模式字段:如0755、1777。年龄字段:如10d表示10天、1h表示1小时。参数字段:根据类型不同含义不同,比如z类型后面跟的是清理时保留的最小文件数。

# 示例:清理/tmp/myapp目录下超过7天未访问的文件
z /tmp/myapp 0755 - - 7d

# 示例:创建/var/log/myapp目录并设置权限
d /var/log/myapp 0755 root root -

# 示例:清理/tmp/session目录下所有内容(包括目录本身)
X /tmp/session 0700 root root -

# 示例:清理/var/cache/myapp下超过30天的文件
x /var/cache/myapp 0755 - - 30d

Ubuntu默认的tmpfiles清理规则分析

Ubuntu自带的清理规则主要在/usr/lib/tmpfiles.d/tmp.conf和/usr/lib/tmpfiles.d/var.conf中。tmp.conf定义了/tmp目录的清理策略,默认使用10天的age参数。var.conf定义了/var/tmp等目录的规则。值得注意的是,/tmp目录在较新版本的Ubuntu中实际上是tmpfs(内存文件系统),重启后自动清空,但/var/tmp是持久化存储,需要定期清理。运维人员要区分这两个目录的不同处理方式。

# Ubuntu默认/tmp清理规则(/usr/lib/tmpfiles.d/tmp.conf内容)
q /tmp 1777 root root 10d

# 默认/var/tmp清理规则(/usr/lib/tmpfiles.d/var.conf内容)
d /var/tmp 1777 root root 10d
x /var/tmp 1777 root root 10d

自定义清理规则的实战操作步骤

第一步,在/etc/tmpfiles.d/目录下创建配置文件。第二步,编写清理规则。第三步,用systemd-tmpfiles --cat命令预览所有规则(包括默认和自定义的合并结果)。第四步,用systemd-tmpfiles --clean --dry-run测试执行效果但不实际清理。第五步,确认无误后执行systemd-tmpfiles --clean正式清理。这个dry-run步骤非常关键,能避免误删重要文件。

# 查看所有tmpfiles规则(合并后的最终效果)
systemd-tmpfiles --cat

# 模拟清理(不实际执行,只显示会清理什么)
systemd-tmpfiles --clean --dry-run

# 实际执行清理
sudo systemd-tmpfiles --clean

# 只清理指定目录
sudo systemd-tmpfiles --clean /tmp/myapp

针对不同场景的清理策略建议

场景一:Web服务器的session文件清理。如果你的应用在/tmp/sessions下存储session文件,建议设置7天清理:z /tmp/sessions 1777 www-data www-data - 7d。场景二:数据库临时文件清理。MySQL的临时表可能在/var/tmp/mysql下,设置30天清理比较合理:x /var/tmp/mysql 0750 mysql mysql - 30d。场景三:CI/CD构建缓存清理。Jenkins或GitLab Runner的构建缓存可以设置3天清理:z /var/cache/jenkins 0755 jenkins jenkins - 3d。场景四:日志文件轮转配合。不建议用tmpfiles清理活跃日志,应该配合logrotate使用,tmpfiles更适合清理那些不受logrotate管理的临时文件。

age参数的精确控制和注意事项

age参数支持多种时间单位:s(秒)、m(分钟)、h(小时)、d(天)、w(周)、M(月)、y(年)。但要注意,age是基于文件的atime(访问时间)或mtime(修改时间)来判断的,具体取决于文件系统挂载选项。如果文件系统挂载时使用了noatime或relatime选项,那么atime不会更新,age判断可能不准确。建议在/etc/fstab中确认相关分区的挂载选项,或者使用mtime作为判断依据(某些版本的systemd支持通过参数指定)。

排除特定文件或目录不被清理的方法

systemd-tmpfiles本身不支持"排除"语法,但有几种变通方法。方法一:在清理规则的路径中使用更精确的路径,避免匹配到不想清理的内容。方法二:使用!前缀在某些场景下表示"不执行",但这在tmpfiles中支持有限。方法三:将需要保护的文件放在单独的子目录中,然后只对特定子目录设置清理规则。方法四:通过设置文件的immutable属性(chattr +i)来防止被清理,但这会影响所有删除操作不只是tmpfiles。最推荐的还是方法一和方法三,精准控制路径是最安全的。

# 精确路径控制:只清理/tmp/cache下的内容,不影响/tmp下其他文件
x /tmp/cache - - - 14d

# 使用chattr保护特定文件不被任何方式删除
sudo chattr +i /tmp/important-file.lock

tmpfiles与crontab清理脚本的对比和选择

很多运维人员习惯用crontab写shell脚本来清理临时文件,比如find /tmp -type f -mtime +7 -delete。这种方式灵活但有几个问题:一是需要自己处理权限、日志、错误处理;二是脚本本身可能出错导致误删;三是不如systemd-tmpfiles那样与系统启动流程深度集成。systemd-tmpfiles的优势在于:规则声明式配置、与systemd生命周期绑定、有dry-run验证机制、支持年龄自动计算。但它的劣势是语法相对固定,复杂逻辑(如按文件大小清理、按文件名模式清理)不如shell脚本灵活。建议简单的按时间清理用tmpfiles,复杂的按内容或大小清理用脚本配合。

排查tmpfiles清理问题的常用命令

当发现临时文件没有被清理或者被误清理时,排查步骤如下。首先用systemd-tmpfiles --cat查看当前生效的所有规则,确认你的配置是否被加载。其次检查配置文件语法是否正确,systemd对配置文件格式要求严格,多余的空格或错误的字段都会导致整行被忽略。然后查看journalctl -u systemd-tmpfiles-clean.service的日志,看执行时是否有报错。最后用stat命令检查目标文件的atime和mtime,确认age计算是否符合预期。

# 查看tmpfiles服务执行日志
journalctl -u systemd-tmpfiles-clean.service

# 检查配置文件语法(systemd会在启动时报错)
sudo systemd-analyze verify /etc/tmpfiles.d/10-custom-cleanup.conf

# 查看文件时间戳
stat /tmp/testfile

# 查看当前所有生效规则
systemd-tmpfiles --cat | grep -i "tmp\|var"

高级技巧:结合systemd-tmpfiles与timer实现定时清理

虽然systemd-tmpfiles默认在启动时执行,但你可以通过创建systemd timer来实现周期性清理。创建一个.timer文件和对应的.service文件,service文件执行systemd-tmpfiles --clean,timer文件定义执行频率。这样就能实现比如每天凌晨3点清理一次的效果,而不是只在开机时清理。这对于长时间运行的服务器特别有用,因为开机时清理一次可能不够。

# /etc/systemd/system/tmpfiles-clean-daily.service
[Unit]
Description=Daily tmpfiles cleanup

[Service]
Type=oneshot
ExecStart=/usr/bin/systemd-tmpfiles --clean

# /etc/systemd/system/tmpfiles-clean-daily.timer
[Unit]
Description=Daily tmpfiles cleanup timer

[Timer]
OnCalendar=*-*-* 03:00:00
Persistent=true

[Install]
WantedBy=timers.target

总结:构建可靠的临时目录清理体系

Ubuntu运维中的systemd-tmpfiles清理规则并不复杂,核心就是理解类型、路径、年龄这三个关键字段的组合。建议运维人员遵循以下原则:第一,永远先用--dry-run验证再执行;第二,自定义规则放在/etc/tmpfiles.d/并用数字前缀命名;第三,区分/tmp(tmpfs自动清空)和/var/tmp(需要主动清理)的不同策略;第四,复杂场景结合timer实现周期执行;第五,定期用systemd-tmpfiles --cat审计当前规则是否符合预期。掌握这些,你就能构建一个既安全又高效的临时目录清理体系,避免磁盘空间被无意义的临时文件占满,同时确保不会误删重要数据。