用 systemd timer 替代 crontab:迁移时最容易踩的五个点

举报
yd_292915714 发表于 2026/11/08 00:30:21 2026/11/08
【摘要】 cron 失败没记录、关机漏跑、环境变量对不上。换成 systemd timer 后这些问题都有显式配置项,但时间字段、Persistent、环境、oneshot 重试和 enable 对象这五处最容易踩,附完整示例与验证命令。

用 systemd timer 替代 crontab:迁移时最容易踩的五个点

crontab -e 写一行就够了,为什么还要换成 systemd timer?因为 cron 有几个说不清的地方:任务失败没有记录、并发跑会叠在一起、机器关机错过的任务不会补、环境变量跟你登录 shell 完全不是一回事。systemd timer 把这些都变成了显式配置项。

但迁移过程里有五个细节,不注意会踩。

一、cron 的时间字段要换算

cron 的 30 8 * * * 在 timer 里是:

[Timer]
OnCalendar=*-*-* 08:30:00
Persistent=true

OnCalendar 的格式是 星期 年-月-日 时:分:秒,日常只用 *-*-* HH:MM:SS。想每 15 分钟跑一次,别写 *:0/15,要写 *:0/15:00——秒位不能省,否则解析失败。

验证表达式对不对,不用等时间到:

systemd-analyze calendar '*-*-* 08:30:00'
systemd-analyze calendar '*:0/15:00'

输出会给出下次触发时间,比猜可靠。

二、Persistent=true 是 cron 没有的能力

关机期间错过的任务,systemd 会在开机后补跑一次。这对每日备份、证书续期这类任务很关键。

要注意它只补一次,不会把错过的十次全补上。也不需要额外装 anacron。

三、环境变量不是你的 shell

cron 的经典坑是 PATH 只有 /usr/bin:/bin,systemd 更严格:默认几乎没有环境变量,HOME 可能都没有。

两个办法:

[Service]
Environment=PATH=/usr/local/bin:/usr/bin:/bin
Environment=HOME=/root

或者用一个 wrapper 脚本,在脚本里 source 环境文件。后者更好维护,尤其是需要读 .env 的场景。

调试时先跑一次手动触发,看环境对不对:

systemctl start mytask.service
journalctl -u mytask.service -n 50 --no-pager

四、Type=oneshot 与 RemainAfterExit

定时任务通常是 Type=oneshot:进程退出即结束,systemd 记录退出码。

如果你希望「跑完之后状态保持 active」,加 RemainAfterExit=yes。但对备份这类任务没必要,反而会让 systemctl status 显示得像是常驻服务。

失败重试不要用 Restart=always——oneshot 配合 always 会在失败后立刻无限重启。要重试就显式写:

Restart=on-failure
RestartSec=5min
StartLimitBurst=3

五、别把 timer 和 service 写成同一个文件

一个 timer 对应一个同名 service:

  • backup.timer 负责什么时候跑
  • backup.service 负责跑什么

启用的是 timer,不是 service:

systemctl enable --now backup.timer
systemctl list-timers --all

只 enable service 不会定时执行,这是迁移里最常见的「配了但不跑」。

一个完整的例子

# /etc/systemd/system/backup.service
[Unit]
Description=Daily backup
After=network-online.target

[Service]
Type=oneshot
User=root
Environment=PATH=/usr/local/bin:/usr/bin:/bin
ExecStart=/usr/local/bin/backup.sh
Nice=10
IOSchedulingClass=idle

[Install]
WantedBy=multi-user.target
# /etc/systemd/system/backup.timer
[Unit]
Description=Run backup daily at 03:20

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

[Install]
WantedBy=timers.target

RandomizedDelaySec 是另一个 cron 没有的好处:多台机器同一时间跑备份时,随机错开最多 5 分钟,避免同时打满存储。

什么时候不该换

如果任务很短、机器单一、你不关心失败记录,cron 完全够用。systemd timer 的价值在可观测性和可靠性:journalctl 能查每次运行的输出和退出码,systemctl list-timers 能看到下次和上次触发时间。

迁移的收益不是「更现代」,而是出问题时你能说清楚发生了什么。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。