在运维工作中,有一句流传很广的话:”能交给机器做的,就不要让人重复做。”定时任务与自动化,正是这句话最直接的落地方式。无论是每天凌晨自动备份数据库、定期清理日志,还是按需重启服务、批量巡检服务器,都离不开 Ubuntu 上的任务调度机制。Ubuntu 作为一款成熟的 Linux 发行版,提供了两种主流的定时调度方案:传统而经典的 cron,以及功能更强大、与现代 systemd 生态深度整合的 systemd timer。今天我们就围绕”定时任务与自动化”这条主线,系统讲解两者的原理、配置方式与实战技巧,并穿插脚本化运维的常用套路,帮你把重复劳动真正解放出来。
核心概念:cron 与 systemd timer 的定位
cron 是 Unix/Linux 世界历史悠久的守护进程,通过读取 crontab 文件,在特定时间点触发命令或脚本。它的配置简单直观,语法经过几十年的验证,几乎每一台 Linux 服务器上都有它的身影。cron 的最小调度粒度是”分钟”,对绝大多数定时需求已经足够。它适合轻量、独立、与登录会话无关的后台任务。
systemd timer 则是 systemd 引入的替代方案。它以.timer单元文件的形式存在,配合对应的.service单元共同工作。相比 cron,systemd timer 的优势在于:支持更丰富的时间表达式(如单调时间、日历事件)、可以记录每次触发的日志、具备依赖关系与资源控制能力、支持OnBootSec这类”开机后多久执行”的语义,还能方便地用systemctl统一管理启停与查看状态。
简单来说:如果你是快速写一条临时定时任务,cron 更顺手;如果你要构建一套可维护、可观测、可随服务一起交付的自动化体系,systemd timer 更值得优先考虑。
实战步骤
1. 使用 crontab 配置定时任务
先查看当前用户的定时任务列表:
crontab-l编辑当前用户的 crontab(首次运行会提示选择编辑器):
crontab-ecrontab 每一行的格式为:分 时 日 月 周 命令。下面是一个典型示例,表示每天凌晨 2 点执行数据库备份脚本:
# 每天 02:00 执行备份脚本,并将输出追加到日志02* * * /usr/local/bin/backup.sh>>/var/log/backup.log2>&1# 每 30 分钟执行一次磁盘空间检查*/30 * * * * /usr/local/bin/check_disk.sh# 每周一凌晨 3 点清理临时文件03* *1find/tmp-typef-mtime+7-delete保存后 cron 会自动加载。可以通过以下命令确认服务运行状态:
sudosystemctl statuscron2. 编写可复用的自动化脚本
脚本化运维的核心是”参数化 + 日志 + 幂等”。下面是一个带日志输出的数据库备份脚本示例:
#!/usr/bin/env bashset-euopipefail# 数据库备份脚本 backup.shBACKUP_DIR="/data/backup/mysql"LOG_FILE="/var/log/backup.log"DB_NAME="appdb"log(){echo"[$(date'+%Y-%m-%d %H:%M:%S')]$*"|tee-a"$LOG_FILE"}mkdir-p"$BACKUP_DIR"log"开始备份数据库${DB_NAME}"mysqldump --single-transaction"$DB_NAME"|gzip>"${BACKUP_DIR}/${DB_NAME}-$(date'+%Y%m%d%H%M').sql.gz"# 只保留最近 7 天的备份find"$BACKUP_DIR"-name'*.sql.gz'-mtime+7-deletelog"备份完成,保留最近 7 天文件"赋予执行权限后再交给 cron 调用:
chmod+x /usr/local/bin/backup.sh3. 使用 systemd timer 实现定时任务
systemd timer 需要两个文件:一个定义”做什么”的.service,一个定义”何时做”的.timer。先创建服务单元:
sudotee/etc/systemd/system/backup.service>/dev/null<<'EOF' [Unit] Description=Daily MySQL backup service [Service] Type=oneshot ExecStart=/usr/local/bin/backup.sh User=root [Install] WantedBy=multi-user.target EOF再创建对应的 timer 单元,实现每天凌晨 2 点触发,并允许开机后 5 分钟内补跑一次:
sudotee/etc/systemd/system/backup.timer>/dev/null<<'EOF' [Unit] Description=Run backup daily at 02:00 [Timer] OnCalendar=*-*-* 02:00:00 Persistent=true RandomizedDelaySec=60 [Install] WantedBy=timers.target EOF启用并启动 timer,然后查看状态与下次触发时间:
sudosystemctl daemon-reloadsudosystemctlenable--nowbackup.timer# 查看 timer 列表与下次执行时间systemctl list-timers--all|grepbackup每次触发都会产生日志,方便排查问题:
journalctl-ubackup.service-n20--no-pager常见问题
Q1:cron 任务没有执行,怎么办?
先确认 cron 服务是否在运行:systemctl status cron。再检查/var/log/syslog中是否出现CRON相关记录。最常见的原因是脚本路径或环境变量问题——cron 执行的环境和登录 shell 不同,脚本里最好使用绝对路径,必要时在脚本开头显式设置PATH。
Q2:crontab 和/etc/crontab有什么区别?crontab -e编辑的是当前用户的个人 crontab;而/etc/crontab是系统级 crontab,格式上多了一个”执行用户”字段,由系统管理员维护。系统级任务还可以放到/etc/cron.d/目录,规则格式与/etc/crontab一致。
Q3:systemd timer 和 cron 可以同时使用吗?
可以,但要避免同一个任务被重复调度。建议一个任务只选择一种调度方式,避免出现重复执行导致的数据覆盖或并发冲突。
Q4:如何测试定时任务而不等到触发时间?
cron 任务可以直接在 shell 里手动运行命令验证;systemd timer 则可以用sudo systemctl start backup.service手动触发一次服务,观察日志确认行为是否符合预期。
总结
定时任务与自动化是运维工程师的”效率放大器”。cron 以其简单直接、无处不在的特点,仍然是处理轻量定时任务的首选;而 systemd timer 凭借更强大的时间语义、日志能力与 systemctl 的统一管理接口,正在成为现代 Ubuntu 运维体系中更规范、更可观测的选择。掌握了这两套机制,再配合参数化、幂等、带日志的脚本化思路,你就能把备份、巡检、清理、发布等重复性工作逐步交给系统自动完成,把精力聚焦在更有价值的架构与排障上。
下期预告:第 15 天,我们将进入《Shell 脚本编程——从基础语法到运维自动化脚本》,带你系统掌握变量、分支、循环、函数等核心语法,并动手写出真正可用的运维自动化脚本,敬请期待。
No matter what label is thrown your way, only you can define your self.
不管你被贴上什么标签,只有你才能定义你自己