5.6.2 systemd 定时器与服务管理
systemd 提供统一的服务管理与定时调度能力,通过 unit 文件描述服务与定时器,并由 systemd 负责生命周期管理。相比 cron,systemd 定时器具备依赖关系、失败重试、触发历史追踪和日志统一等优势,适合与服务强绑定的自动化任务。
原理与架构草图
安装/环境准备
- 大多数发行版默认包含 systemd。确认版本与运行状态:
uname -a
systemctl --version
systemctl is-system-running
- 目录约定:自定义 unit 建议放在
/etc/systemd/system/,避免被包管理覆盖。
核心概念与关键字段
- Unit 类型:service、timer、target 等;*.timer 触发 *.service
- 触发时间:OnCalendar(类 cron)、OnBootSec/OnUnitActiveSec(相对时间)
- 持久化执行:Persistent=true 可在错过执行时补偿运行
- 依赖关系:After/Requires/Wants 控制启动顺序与依赖
- 服务类型:Type=oneshot(一次性任务)、simple/notify(常驻服务)
完整示例:备份任务(service + timer)
1)准备脚本(包含日志与退出码):
cat >/usr/local/bin/backup.sh <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
ts=$(date +%F_%H%M%S)
dest=/data/backup
mkdir -p "$dest"
tar -czf "$dest/etc_$ts.tgz" /etc
echo "backup ok: $dest/etc_$ts.tgz"
EOF
chmod +x /usr/local/bin/backup.sh
2)创建服务单元 /etc/systemd/system/backup.service:
[Unit]
Description=Daily backup of /etc
After=network-online.target
[Service]
Type=oneshot
User=backup
Group=backup
ExecStart=/usr/local/bin/backup.sh
Environment="TZ=Asia/Shanghai"
StandardOutput=journal
StandardError=journal
TimeoutStartSec=300
3)创建定时器 /etc/systemd/system/backup.timer:
[Unit]
Description=Run backup daily at 02:30
[Timer]
OnCalendar=*-*-* 02:30:00
Persistent=true
Unit=backup.service
[Install]
WantedBy=timers.target
4)创建运行用户与目录权限:
useradd -r -s /sbin/nologin backup || true
mkdir -p /data/backup
chown -R backup:backup /data/backup
5)加载并启用:
systemctl daemon-reload
systemctl enable --now backup.timer
systemctl list-timers --all | grep backup
命令解释与预期效果
- systemctl daemon-reload:重新加载 unit 文件,必要步骤
- systemctl enable --now backup.timer:开机自启并立即启动定时器
- systemctl list-timers --all:查看下次触发时间与上次执行时间
常用管理与排错
# 查看状态与最近日志
systemctl status backup.service
journalctl -u backup.service -n 50 --no-pager
# 手动触发一次执行
systemctl start backup.service
# 查看失败单元
systemctl --failed
# 验证 OnCalendar 表达式
systemd-analyze calendar "Mon *-*-* 02:30:00"
典型故障与处理
- 脚本无执行权限:chmod +x /usr/local/bin/backup.sh
- 用户无权限访问目录:chown -R backup:backup /data/backup
- 定时器未触发:确认 backup.timer 已启用并检查 list-timers
- 执行报错不明显:使用 journalctl -u backup.service 查看详细输出
- 错过执行:设置 Persistent=true 并确认系统时间正确
与 cron 的选型建议
- 与系统服务紧密关联、需依赖管理与审计的任务优先用 systemd timer
- 简单周期性脚本可保留 cron,但建议统一纳管与日志策略
安全与稳定性要点(示例)
# 追加到 [Service] 中
NoNewPrivileges=true
ProtectSystem=full
PrivateTmp=true
CPUQuota=30%
MemoryMax=200M
Restart=on-failure
RestartSec=10
练习
1. 改写示例,使其每 10 分钟执行一次,并写入 /var/log/backup.log。
2. 增加 OnFailure= 指向一个告警服务单元,失败时发送邮件或写入告警日志。
3. 将脚本执行时间超过 5 分钟时强制终止,验证 TimeoutStartSec 的效果。