systemd 教程 / 临时文件与 tmpfiles.d
临时文件与 tmpfiles.d
概述
tmpfiles.d 是 systemd 提供的临时文件和目录管理机制。通过配置文件,可以声明式地创建、清理和删除临时文件、运行时目录、设备节点等。系统启动时由 systemd-tmpfiles 处理这些配置,也可以通过定时器定期清理过期的临时文件。
配置文件路径
tmpfiles.d 配置文件按优先级从高到低读取(同名文件高优先级覆盖低优先级):
| 路径 | 说明 |
|---|---|
/etc/tmpfiles.d/*.conf | 管理员自定义配置(最高优先级) |
/run/tmpfiles.d/*.conf | 运行时生成的配置 |
/usr/lib/tmpfiles.d/*.conf | 软件包安装的默认配置(最低优先级) |
文件命名规范
/tmpfiles.d/<优先级>-<名称>.conf
示例:
/tmpfiles.d/10-example.conf
/tmpfiles.d/50-systemd.conf
/tmpfiles.d/99-custom.conf
💡 提示:数字前缀越小优先级越高。自定义配置建议使用 99- 前缀或放在 /etc/tmpfiles.d/ 目录下。
查看已有配置
# 查看所有 tmpfiles.d 配置
ls /usr/lib/tmpfiles.d/
ls /etc/tmpfiles.d/
ls /run/tmpfiles.d/
# 查看特定配置文件内容
cat /usr/lib/tmpfiles.d/systemd.conf
配置文件格式
每行一条规则,格式如下:
Type Path Mode Owner Group Age Argument
| 字段 | 说明 |
|---|---|
Type | 操作类型(创建/删除/清理等) |
Path | 文件或目录的绝对路径 |
Mode | 文件权限(八进制) |
Owner | 文件所有者(用户名或 UID) |
Group | 文件所属组(组名或 GID) |
Age | 清理时间阈期(过期时间) |
Argument | 附加参数(取决于 Type) |
示例
# 创建运行时目录,权限 0755,所有者 root
d /run/myapp 0755 root root -
# 创建临时目录,7 天后清理
d /tmp/myapp 1777 root root 7d
# 创建符号链接
L /tmp/link - - - - /target/path
# 创建配置文件
f /etc/myapp/config.conf 0644 root root - "default_content"
Type 类型详解
创建类
| Type | 说明 | 特点 |
|---|---|---|
f | 创建文件 | 文件不存在时创建,不覆盖已有内容 |
f+ | 创建或覆盖文件 | 如果文件存在则截断重写 |
w | 写入文件 | 写入内容到已有文件(不创建) |
w+ | 写入或创建文件 | 不存在则创建,存在则写入 |
d | 创建目录 | 不存在则创建,不清理内容 |
D | 创建或清空目录 | 不存在则创建,存在则清空 |
e | 创建目录(存在则调整权限) | 等同于 d,但会调整已有目录权限 |
v | 创建目录(subvolume) | 用于 Btrfs subvolume |
q | 创建目录(不调整已有权限) | 仅创建,不修改已有目录 |
Q | 创建目录(同 q,但忽略挂载点) | 类似 q |
p | 创建命名管道(FIFO) | 创建 FIFO 文件 |
L | 创建符号链接 | 创建或更新符号链接 |
c | 创建字符设备节点 | 创建字符设备文件 |
b | 创建块设备节点 | 创建块设备文件 |
清理类
| Type | 说明 | 配合 Age 使用 |
|---|---|---|
r | 删除文件或目录 | 不使用 |
R | 递归删除文件或目录 | 不使用 |
x | 排除路径(不删除) | 不使用 |
X | 排除路径(仅排除文件内容) | 配合 Age |
z | 调整文件权限 | 不使用 |
Z | 递归调整文件权限 | 不使用 |
类型前缀修饰符
| 前缀 | 说明 |
|---|---|
- | 忽略错误(文件不存在等) |
! | 仅在 --boot 模式下执行 |
!! | 仅在 --boot 模式下执行且忽略错误 |
# - 前缀:忽略错误
- /tmp/maybe-exist 0644 root root -
# ! 前缀:仅启动时执行
! /run/boot-time-only 0755 root root -
# !! 前缀:启动时执行,忽略错误
!! /run/optional-boot 0755 root root -
清理策略(Age / TTL)
Age 字段
Age 字段指定文件/目录的最大存活时间,超过后会被清理:
| 值 | 说明 |
|---|---|
- | 不自动清理 |
7d | 7 天 |
2h | 2 小时 |
30min | 30 分钟 |
1w | 1 周 |
3month | 3 个月 |
1year | 1 年 |
1y6month | 1 年 6 个月 |
时间单位:
| 单位 | 说明 |
|---|---|
s / sec | 秒 |
min | 分钟 |
h / hr | 小时 |
d / day | 天 |
w / week | 周 |
month | 月(30 天) |
y / year | 年(365 天) |
清理规则
清理由 systemd-tmpfiles --clean 执行,通常由定时器自动运行:
# 查看清理定时器
systemctl list-timers systemd-tmpfiles-clean.timer
# 手动执行清理
sudo systemd-tmpfiles --clean
# 仅清理特定配置
sudo systemd-tmpfiles --clean /etc/tmpfiles.d/myapp.conf
目录结构与 Age
对于目录,Age 的计算基于目录中文件的最后访问时间:
# 清理 7 天未访问的文件(但不删除目录本身)
d /tmp/myapp 1777 root root 7d
# 递归清理目录及其内容
e /tmp/myapp 1777 root root 7d
⚠️ 注意:d 类型在清理时只删除目录内的过期文件,不删除目录本身。D 类型会在清理时清空整个目录。
systemd-tmpfiles 命令
命令选项
# 创建所有配置中声明的文件和目录
sudo systemd-tmpfiles --create
# 清理过期的临时文件
sudo systemd-tmpfiles --clean
# 删除所有配置中声明的文件和目录
sudo systemd-tmpfiles --remove
# 仅处理特定配置文件
sudo systemd-tmpfiles --create /etc/tmpfiles.d/myapp.conf
# 验证配置文件语法
sudo systemd-tmpfiles --verify
# 显示将要执行的操作(不实际执行)
sudo systemd-tmpfiles --dry-run --create
systemd-tmpfiles-setup 服务
系统启动时自动执行:
# 查看启动时的 tmpfiles 服务
systemctl status systemd-tmpfiles-setup.service
systemctl status systemd-tmpfiles-clean.timer
# 查看日志
journalctl -u systemd-tmpfiles-setup.service
实际案例
案例 1:创建应用运行时目录
# /etc/tmpfiles.d/myapp.conf
# 创建运行时目录
d /run/myapp 0755 myapp myapp -
# 创建 PID 文件目录
d /run/myapp/pid 0755 myapp myapp -
# 创建 socket 目录
d /run/myapp/sock 0755 myapp myapp -
# 应用配置
sudo systemd-tmpfiles --create /etc/tmpfiles.d/myapp.conf
# 验证
ls -la /run/myapp/
案例 2:临时目录自动清理
# /etc/tmpfiles.d/app-temp.conf
# 临时目录,7 天后清理
d /tmp/myapp 1777 root root 7d
# 上传目录,30 天后清理
d /var/tmp/myapp-uploads 0755 www-data www-data 30d
# 缓存目录,14 天后清理
d /var/cache/myapp 0755 myapp myapp 14d
案例 3:权限修复
# /etc/tmpfiles.d/fix-perms.conf
# 确保日志目录权限正确
z /var/log/myapp 0750 myapp myapp -
# 递归修复
Z /var/log/myapp 0640 myapp myapp -
# 执行权限修复
sudo systemd-tmpfiles --create /etc/tmpfiles.d/fix-perms.conf
案例 4:创建符号链接
# /etc/tmpfiles.d/symlinks.conf
# 创建符号链接
L /tmp/current - - - - /opt/myapp/current
L /usr/local/bin/myapp - - - - /opt/myapp/bin/myapp
案例 5:创建 FIFO
# /etc/tmpfiles.d/fifo.conf
# 创建命名管道
p /run/myapp/input 0660 myapp myapp -
案例 6:排除路径
# /etc/tmpfiles.d/cleanup.conf
# 清理 /tmp/myapp,但排除子目录 data
d /tmp/myapp 1777 root root 7d
x /tmp/myapp/data
x /tmp/myapp/data/important
# 清理 /var/tmp,但排除特定目录
D /var/tmp 1777 root root 30d
x /var/tmp/preserved
案例 7:创建设备节点
# /etc/tmpfiles.d/devices.conf
# 创建字符设备
c /dev/mydevice 0660 root dialout 10 200
# 创建块设备
b /dev/myblock 0660 root disk 8 0
tmpfs 挂载
systemd 支持通过 tmpfiles.d 自动挂载 tmpfs:
# /etc/tmpfiles.d/tmpfs.conf
# 挂载 tmpfs
tmpfs /tmp/myapp-tmp tmpfs size=1G,mode=1777 0 0
系统默认 tmpfs 挂载
# 查看系统 tmpfs 挂载点
mount | grep tmpfs
# 常见 tmpfs 挂载点:
# /tmp — 临时文件
# /dev/shm — 共享内存
# /run — 运行时文件
⚠️ 注意:/tmp 在许多发行版上默认为 tmpfs,重启后清空。重要临时文件应放在 /var/tmp/。
与 tmpwatch/cronie 对比
传统方式:tmpwatch
tmpwatch 是传统的临时文件清理工具:
# 清理 7 天未访问的文件
tmpwatch 7d /tmp
# 清理 30 天未修改的文件
tmpwatch --mtime 30d /var/tmp
对比
| 对比项 | tmpfiles.d | tmpwatch |
|---|---|---|
| 管理方式 | 声明式配置 | 命令行参数 |
| 功能范围 | 创建 + 清理 + 权限 | 仅清理 |
| 集成度 | systemd 原生 | 独立工具 |
| 配置位置 | /etc/tmpfiles.d/ | /etc/cron.daily/ |
| 触发方式 | systemd 服务 + 定时器 | cron |
| 设备节点 | 支持 | 不支持 |
| 符号链接 | 支持 | 不支持 |
💡 提示:在 systemd 系统中,推荐使用 tmpfiles.d 替代 tmpwatch,功能更强大且配置更清晰。
调试 tmpfiles.d
验证配置文件
# 验证配置文件语法
sudo systemd-tmpfiles --verify
# 验证特定文件
sudo systemd-tmpfiles --verify /etc/tmpfiles.d/myapp.conf
# 模拟执行(dry-run)
sudo systemd-tmpfiles --dry-run --create /etc/tmpfiles.d/myapp.conf
查看执行日志
# 查看 tmpfiles 服务日志
journalctl -u systemd-tmpfiles-setup.service
# 查看清理定时器日志
journalctl -u systemd-tmpfiles-clean.service
# 实时监控
journalctl -fu systemd-tmpfiles-setup.service
常见问题排查
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 目录未创建 | 配置文件未被读取 | 检查文件路径和扩展名(必须 .conf) |
| 权限不正确 | Type 使用错误 | 使用 z 或 Z 调整权限 |
| 清理不生效 | Age 设置错误 | 检查时间格式,确保定时器运行 |
| 语法规则 | 配置文件格式错误 | 使用 --verify 检查 |
| 符号链接失败 | 目标不存在 | 确保目标路径正确 |
系统默认配置示例
systemd 默认配置
# 查看 systemd 默认 tmpfiles.d 配置
cat /usr/lib/tmpfiles.d/systemd.conf
典型的 systemd.conf 内容:
# /run 目录结构
d /run/lock 0755 root root -
d /run/log 0755 root root -
d /run/user 0755 root root 10d
# /tmp 和 /var/tmp
d /tmp 1777 root root 10d
d /var/tmp 1777 root root 30d
# systemd 相关目录
d /run/systemd 0755 root root -
d /run/systemd/seats 0755 root root -
d /run/systemd/sessions 0755 root root -
d /run/systemd/users 0755 root root -
最佳实践
配置文件组织
# 软件包提供的配置
/usr/lib/tmpfiles.d/mypackage.conf
# 管理员自定义覆盖
/etc/tmpfiles.d/mypackage.conf
# 运行时生成(通常由 systemd 服务生成)
/run/tmpfiles.d/mypackage.conf
命名规范
# 使用数字前缀控制顺序
/etc/tmpfiles.d/10-essential.conf
/etc/tmpfiles.d/50-application.conf
/etc/tmpfiles.d/99-cleanup.conf
权限设置建议
| 场景 | 权限 | 说明 |
|---|---|---|
| 公共临时目录 | 1777 | 带 sticky bit,用户只能删除自己的文件 |
| 应用运行目录 | 0755 | 所有者完全控制,其他只读 |
| 敏感数据目录 | 0700 | 仅所有者访问 |
| 日志目录 | 0750 | 应用用户和管理组访问 |
实用命令汇总
# 创建文件和目录
sudo systemd-tmpfiles --create
# 清理过期文件
sudo systemd-tmpfiles --clean
# 删除所有声明的文件
sudo systemd-tmpfiles --remove
# 验证配置
sudo systemd-tmpfiles --verify
# 仅处理特定配置
sudo systemd-tmpfiles --create /etc/tmpfiles.d/myapp.conf
# dry-run 模式
sudo systemd-tmpfiles --dry-run --create
# 查看定时器
systemctl list-timers systemd-tmpfiles-clean.timer
# 查看日志
journalctl -u systemd-tmpfiles-setup.service
journalctl -u systemd-tmpfiles-clean.service