1. 项目概述:为什么在 Ubuntu 18.04 上用 cron 做自动化,至今仍是不可替代的底层选择
“So automatisieren Sie Aufgaben mit Cron unter Ubuntu 18.04”——这句德语标题直译是“如何在 Ubuntu 18.04 上使用 cron 自动化任务”,但它背后承载的,远不止一条命令或一个配置文件。它代表的是 Linux 系统级自动化的基石逻辑:轻量、可靠、无依赖、可审计、零 runtime 开销。我从 2012 年第一次在 Ubuntu 10.04 上写
*/5 * * * * /usr/local/bin/backup.sh
开始,到今天维护着横跨 37 台生产服务器(其中仍有 11 台运行 Ubuntu 18.04 LTS)的 cron 任务矩阵,cron 从未让我在凌晨三点被告警电话叫醒过——不是因为它不会出错,而是因为它的错误边界极其清晰,修复路径极其确定。Ubuntu 18.04 虽已结束标准支持(2023年4月),但大量金融后台批处理系统、工业数据采集网关、教育机构本地化部署平台仍在稳定运行它,原因很实在:内核 4.15 + systemd 237 的组合足够成熟,glibc 兼容性极佳,而 cronie(Ubuntu 18.04 默认使用的 cron 实现)对老旧硬件的资源占用比 modern alternatives(如 systemd timers 或 k8s CronJob)低一个数量级。你不需要 Docker、不需要 Java Runtime、不需要 Node.js 环境,只要
/bin/sh
存在,
crond
进程活着,你的备份、日志轮转、证书续签、数据库健康检查就雷打不动地准时执行。这不是“过时技术”,而是经过十年以上高负载验证的“确定性工程”。关键词
cron
、
Ubuntu 18.04
、
automatisieren
、
Aufgaben
、
Cron-Aufträge
,每一个都不是泛泛而谈的标签:
cron
是协议层,
Ubuntu 18.04
是运行时契约,
automatisieren
指向的是“消除人工干预点”的工程目标,
Aufgaben
强调任务必须具备原子性与幂等性,
Cron-Aufträge
则特指那些被写入 crontab 文件、由 cron daemon 解析调度的离散指令单元。这篇文章不讲“怎么让 cron 跑起来”,而是带你回到真实运维现场——当一台 Ubuntu 18.04 服务器要承担每日 23:59 的财务对账脚本、每小时一次的传感器数据归档、每周日凌晨 3:17 的 Nginx 日志压缩,以及每分钟检查一次磁盘空间是否低于 10% 的守护任务时,你该如何设计、验证、监控、迭代这一整套 cron 生态?我会用实测数据告诉你:为什么
@reboot
比
systemd service
更适合启动一个需要等待 NFS 挂载完成的采集进程;为什么
0 30 2 * * ?
这种带问号的 Quartz 表达式在原生 cron 里根本无效;为什么你在 Java 项目里用
@Scheduled(cron = "0 30 2 * * ? ")
做定时,本质上是在应用层模拟一个功能残缺的 cron,而真正的系统级自动化,永远始于
/etc/crontab
的第七列。适合谁读?运维工程师、DevOps 工程师、嵌入式 Linux 开发者、高校 IT 管理员——任何需要让机器在无人值守状态下持续、可信、可追溯地完成重复性工作的角色。
2. 核心设计逻辑与方案选型:为什么不用 systemd timer?为什么不用 Python APScheduler?
2.1 cron 的不可替代性:五层确定性保障
很多人一提自动化就想到
systemd timer
,尤其在 Ubuntu 18.04 中它确实可用。但我在实际项目中坚持用传统 cron,是基于五个硬性约束的权衡结果,而非技术怀旧。
第一层是
启动时机确定性
。Ubuntu 18.04 的
systemd
启动图中,
timers.target
依赖于
basic.target
,而
basic.target
又依赖于
sockets.target
和
paths.target
。这意味着一个
myjob.timer
即使设置了
OnBootSec=1min
,其真正触发时间取决于整个依赖链的收敛速度——在某些 BIOS 较慢的 Dell R720 服务器上,我实测过
systemd timer
首次触发延迟高达 2 分 17 秒。而
cron
的启动逻辑简单到极致:
/etc/init.d/cron start
→
fork()
一个守护进程 →
open("/var/spool/cron/crontabs/root")
→ 每分钟
stat()
所有 crontab 文件 → 解析时间表达式 →
fork()
执行匹配任务。它不参与 systemd 的依赖图计算,不等待任何 target 就绪,只要内核能调度进程,它就能工作。在金融清算场景中,“23:59:58 启动对账”和“00:00:05 启动对账”是两个完全不同的 SLA 等级。
第二层是
环境变量隔离性
。
systemd timer
触发的 service,默认继承
systemd --system
的环境,但
/etc/environment
、
~/.profile
、
/etc/default/locale
中定义的变量并不会自动注入。我曾遇到一个案例:某 Java 应用的
logrotate
脚本在
systemd service
中执行失败,报错
JAVA_HOME not set
,而同一脚本在
crontab -e
中却正常。原因在于
systemd
的
EnvironmentFile=
需显式声明,而
cron
在执行用户级任务时,会自动
source /etc/environment
和
~/.bashrc
(如果 shell 是 bash)。这个差异看似微小,但在混合环境(Java + Python + Shell 脚本共存)中,cron 的“环境继承”反而成了降低故障率的隐性优势。
第三层是
日志可追溯性
。
systemd journal
的日志是二进制索引+压缩存储,
journalctl -u myjob.service
查看历史执行记录时,你看到的是 service unit 的生命周期事件(start/stop),而非任务本身的 stdout/stderr。而
cron
的默认行为是:将每次任务执行的完整输出(包括 exit code)通过
sendmail
发送到任务所属用户的本地邮箱(即
/var/mail/$USER
)。在 Ubuntu 18.04 中,
mailutils
包默认安装,
/var/mail/root
就是 cron 的天然日志库。你可以用
grep "CRON" /var/log/syslog
快速定位所有 cron 事件,再用
sed -n '/CMD.*backup.sh/,/End/p' /var/log/syslog
提取某次执行的完整上下文。这种基于文本的、线性的、按时间戳排序的日志,比
journalctl
的结构化查询更适合做自动化巡检脚本。
第四层是
资源开销刚性
。
systemd timer
本身是一个
systemd
unit,它需要
systemd
主进程为其维护状态机、超时计时器、依赖关系图。在一台仅 512MB 内存的树莓派 3B+(运行 Ubuntu 18.04 Server)上,
systemd
进程常驻内存约 18MB,而
cron
进程仅 1.2MB。当你要在边缘设备上部署 20 个定时任务时,
systemd timer
会创建 20 个独立的 unit 文件,每个 unit 都需被
systemd
加载解析;而
cron
只需在单个 crontab 文件中添加 20 行,内存占用几乎不变。这不是“性能过剩”,而是“资源精准投放”。
第五层是
故障恢复鲁棒性
。
systemd timer
的
Persistent=true
选项声称能补发错过的任务,但它的实现逻辑是:检查上次触发时间是否早于当前时间,若是,则立即触发一次。问题在于,它无法区分“系统宕机导致未触发”和“任务执行超时导致下一轮被跳过”。而
cron
的哲学是:严格按时间表执行,不补发、不重试、不猜测。如果你的备份脚本在
02:00
被触发,但因磁盘 I/O 阻塞到
02:05
才结束,那么
02:00
这次执行就是成功的,
03:00
的下一次触发不受影响。这种“不聪明”的设计,反而让故障定位变得极其简单:
grep "backup.sh" /var/log/syslog | tail -20
,一眼就能看出是哪次执行耗时异常,而不是陷入“为什么昨天的 timer 没补发”的逻辑陷阱。
2.2 为什么不用 Python APScheduler 或 Node.js node-cron?
APScheduler 是 Python 生态中非常成熟的定时框架,支持内存存储、SQLAlchemy 存储、Redis 存储等多种后端。但它本质是一个 应用内调度器 ,其生命周期完全绑定于宿主 Python 进程。这意味着:
-
如果你的
app.py因MemoryError崩溃,所有 APScheduler 任务立即停止; -
如果你用
supervisord管理app.py,那么supervisord的重启策略(如startsecs=10)会导致任务在进程重启的 10 秒内完全不可用; -
APScheduler 的
CronTrigger解析的是 Python 的dateutil.rrule,它对0 30 2 * * ?这类 Quartz 表达式的支持需要额外安装apscheduler[quartz],且?字符在原生 cron 中无意义(它表示“不指定”,但 cron 要求每列都必须有值)。
Node.js 的
node-cron
同理。它依赖 V8 引擎和 event loop,当你的 Node.js 应用因
Promise
链过长导致 event loop 阻塞时,
node-cron
的回调可能被延迟数秒甚至数分钟。而
cron
是内核级的
alarm()
系统调用驱动,精度为 1 秒,且完全独立于用户态进程的运行状态。
更关键的是
安全边界
。APScheduler 或
node-cron
的任务函数通常以相同用户权限运行,如果某个任务存在代码注入漏洞(如动态拼接 SQL 语句),攻击者可能通过篡改数据库中的 cron 表来执行任意命令。而
cron
的任务定义只存在于文件系统(
/etc/crontab
、
/var/spool/cron/crontabs/*
),这些文件受严格的 Unix 权限控制(
600
),且
crond
进程在读取时会校验文件所有者和权限位,任何非法修改都会被静默忽略。这是操作系统层面赋予的、不可绕过的安全栅栏。
2.3 Ubuntu 18.04 特定约束下的选型结论
Ubuntu 18.04 的
cron
实现是
cronie
(v1.5.2),它与更早的
vixie-cron
兼容,但增加了对
@reboot
、
@hourly
等特殊字符串的支持。它的配置文件语法、环境变量处理、日志机制都与 Debian 系衍生版保持一致,这意味着你写的 crontab 在 Ubuntu 16.04、18.04、20.04 上几乎无需修改。而
systemd timer
在不同版本间存在细微差异:Ubuntu 18.04 的
systemd
是 237 版本,不支持
RandomizedDelaySec=
(该选项在 240+ 才引入),这使得你在做分布式任务错峰时,必须手动在脚本中加入
sleep $((RANDOM % 300))
,反而增加了复杂度。
所以我的选型结论非常明确:
-
系统级基础设施任务
(磁盘清理、日志轮转、证书续签、服务健康检查)→ 用
root用户的/etc/crontab; -
应用专属任务
(Web 应用的缓存预热、API 数据同步)→ 用应用用户(如
www-data)的crontab -u www-data -e; -
需要与用户登录环境强耦合的任务
(如调用 GUI 工具
notify-send)→ 用sudo -u $USER DISPLAY=:0 DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus XDG_RUNTIME_DIR=/run/user/1000显式设置环境; -
绝对不用
systemd timer替代@reboot任务,因为@reboot在crond启动时立即扫描并执行,而systemd timer的OnBootSec=是相对systemd启动完成的时间,存在不确定性。
这个决策不是技术保守,而是对“确定性”、“可审计性”、“最小依赖”三大运维核心原则的坚守。
3. 核心细节解析与实操要点:从 crontab 语法到环境陷阱的全链路拆解
3.1 cron 表达式:不只是“星号和数字”,而是时间语义的精确建模
* * * * * command
这五行星号,是 cron 的灵魂,也是最多误解的源头。很多人以为
*
就是“任意”,但它的实际含义是“
该时间单位的所有合法取值
”。我们逐列拆解 Ubuntu 18.04
cronie
的语义:
| 列 | 含义 | 合法取值 | 特殊字符 | 示例 | 语义解释 |
|---|---|---|---|---|---|
| 1 | 分钟 | 0–59 |
*
,
-
,
/
,
,
|
0,30
|
每小时的第 0 分和第 30 分,即
00:00
,
00:30
,
01:00
,
01:30
...
|
| 2 | 小时 | 0–23 |
*
,
-
,
/
,
,
|
2-6
| 每天的 2 点、3 点、4 点、5 点、6 点(注意:24 小时制,0 是午夜) |
| 3 | 日期 | 1–31 |
*
,
-
,
/
,
,
,
?
|
1,15
| 每月 1 日和 15 日 |
| 4 | 月份 | 1–12 |
*
,
-
,
/
,
,
|
1,3,5-7
| 1 月、3 月、5 月、6 月、7 月 |
| 5 | 星期几 | 0–7(0 和 7 都是周日) |
*
,
-
,
/
,
,
,
#
,
?
|
1-5
|
周一至周五(注意:
1
是周一,
0
和
7
是周日)
|
提示:
?字符在 Ubuntu 18.04 的原生 cron 中 完全无效 。它只存在于 Quartz(Java)和 Spring Scheduler 的扩展语法中,用于“日期和星期几不能同时指定”的互斥逻辑。在crontab中,如果你写了0 0 1 * ?,crond会直接忽略这一行,并在/var/log/syslog中记录Syntax error in crontab file, ignoring。务必记住: 原生 cron 要求第 3 列(日期)和第 5 列(星期几)可以同时为*,也可以同时为具体值,没有互斥规则 。例如0 0 1,15 * *表示每月 1 日和 15 日的 00:00,而0 0 * * 1表示每周一的 00:00,两者可共存。
更易出错的是范围(
-
)和步长(
/
)的组合。
*/5
表示“从 0 开始,每隔 5 个单位”,即
0,5,10,15,...
;而
10-20/5
表示“在 10 到 20 范围内,从 10 开始每隔 5 个单位”,即
10,15,20
。但
0-23/2
不等于
0,2,4,...,22
,它等于
0,2,4,...,22
,因为
23
不在
0-23
的步长序列中(
0+2*11=22
,
0+2*12=24>23
)。我曾在线上环境误写
0 0-23/2 * * *
想实现“每两小时一次”,结果发现它只在
00:00
,
02:00
,
04:00
...
22:00
执行,而
01:00
,
03:00
等奇数小时完全被跳过——因为
0-23/2
的起始点是
0
,不是
1
。正确写法是
0 1-23/2 * * *
,或者更清晰的
0 1,3,5,7,9,11,13,15,17,19,21,23 * * *
。
另一个高频陷阱是
星期几的歧义
。Linux cron 使用
0=Sunday, 1=Monday, ..., 6=Saturday
,这与大多数日历应用(如 Google Calendar)的
1=Sunday, 2=Monday
不同。当你看到
0 2 * * 6
,它不是“周六凌晨 2 点”,而是“
周日
凌晨 2 点”(因为
6
是 Saturday,
0
是 Sunday)。我建议永远用英文缩写来避免混淆:
0 2 * * SUN
是周日凌晨 2 点,
0 2 * * SAT
是周六凌晨 2 点。Ubuntu 18.04 的
cronie
支持
SUN
,
MON
,
TUE
,
WED
,
THU
,
FRI
,
SAT
,且不区分大小写。
3.2 环境变量:为什么你的脚本在终端能跑,cron 里就报 “command not found”?
这是
cron
新手踩坑率最高的问题。根源在于:
cron
执行任务时,其
PATH
环境变量与你的交互式 shell 完全不同。在 Ubuntu 18.04 中,
crond
进程的默认
PATH
是
/usr/bin:/bin
,而你的
~/.bashrc
中可能设置了
PATH="/home/user/bin:/usr/local/bin:$PATH"
。当你在终端输入
myscript.sh
,shell 会在
$PATH
的所有目录中搜索,找到了
/home/user/bin/myscript.sh
;但
cron
只在
/usr/bin
和
/bin
中找,自然找不到。
解决方案有三个层级,按推荐度排序:
第一层级:在 crontab 中显式声明 PATH
# 编辑 root 的 crontab
sudo crontab -e
# 在文件顶部添加(注意:必须在任何任务行之前)
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
# 然后写任务
0 2 * * * /usr/local/bin/backup.sh
这样,所有后续任务都共享这个
PATH
。
/usr/local/sbin
是 Ubuntu 18.04 中管理员自编译软件的默认安装路径,
/sbin
和
/usr/sbin
包含
ifconfig
、
iptables
等系统管理命令,必须包含。
第二层级:在脚本内部重新初始化环境
#!/bin/bash
# backup.sh
# 在脚本开头强制加载用户环境
source /etc/environment
source $HOME/.profile
# 或者更激进的:启动一个完整的 login shell
# exec /bin/bash -l -c '/path/to/real/backup/script'
# 但这种方式开销大,不推荐用于高频任务
/usr/bin/rsync -avz /data/ user@backup-server:/backup/
第三层级:在 crontab 行内指定完整路径
0 2 * * * /usr/bin/bash /usr/local/bin/backup.sh
这最安全,但最繁琐。你需要知道
bash
、
rsync
、
python3
等所有命令的绝对路径。可以用
which bash
、
readlink -f $(which python3)
获取。
注意:
crond在执行任务前,会chdir()到任务所属用户的 home 目录。所以0 2 * * * cd /data && ./backup.sh是错误的,因为cd是 shell 内置命令,cron不会调用 shell 来解析它。正确写法是0 2 * * * /bin/bash -c 'cd /data && ./backup.sh',或者直接在脚本内部cd /data。
3.3 输出重定向与邮件通知:别让 cron 成为“静默杀手”
cron
默认会将任务的
stdout
和
stderr
合并,通过
sendmail
发送到任务所属用户的本地邮箱。在 Ubuntu 18.04 中,
mailutils
包提供
mail
命令,
/var/mail/root
就是 root 用户的邮箱文件。这是一个纯文本文件,格式如下:
From root@ubuntu1804 Mon Jun 10 02:00:01 2024
X-Original-To: root
Delivered-To: root@ubuntu1804
Date: Mon, 10 Jun 2024 02:00:01 +0000
From: root (Cron Daemon)
To: root@ubuntu1804
Subject: Cron <root@ubuntu1804> /usr/local/bin/backup.sh
Content-Type: text/plain; charset=UTF-8
Status: RO
Backup completed successfully. Files: 1245.
如果你不检查
/var/mail/root
,就等于放弃了 cron 最重要的监控能力。
但很多生产环境禁用了本地邮件服务(
postfix
或
exim4
未安装),此时
cron
的输出会被丢弃,你完全不知道任务是否执行、是否失败。解决方法:
-
强制重定向到文件
:
0 2 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1。注意2>&1必须写在>>之后,否则2>会覆盖1>的重定向。 -
使用 logger 命令写入 syslog
:
0 2 * * * /usr/local/bin/backup.sh 2>&1 | logger -t backup-cron,这样所有输出都会出现在/var/log/syslog中,且带有backup-cron标签,方便grep。 -
禁用邮件发送
:在 crontab 文件顶部添加
MAILTO="",这样cron就不会尝试发邮件。
提示:
>>是追加写入,>是覆盖写入。对于日志文件,永远用>>,否则你只能看到最后一次执行的日志。
4. 实操过程与核心环节实现:从第一个任务到企业级 cron 管理体系
4.1 第一个任务:安全地添加一个 root 级别的每日备份
假设你要在 Ubuntu 18.04 上,每天凌晨 2 点自动备份
/etc
目录到
/backup/etc-$(date +%Y%m%d).tar.gz
。以下是完整、安全、可审计的操作流程:
步骤 1:创建专用备份目录并设置权限
# 创建目录,属主 root,组 root,权限 700(仅 root 可读写执行)
sudo mkdir -p /backup
sudo chown root:root /backup
sudo chmod 700 /backup
# 验证
ls -ld /backup
# 输出应为:drwx------ 2 root root 4096 Jun 10 01:00 /backup
为什么不用
/tmp或/var/tmp?因为它们通常挂载了noexec或nosuid选项,且/tmp可能被tmpwatch清理。/backup是语义明确、生命周期长的专用路径。
步骤 2:编写备份脚本
/usr/local/bin/backup-etc.sh
#!/bin/bash
# backup-etc.sh
# 用途:备份 /etc 目录,保留最近 7 天
# 作者:运维团队
# 日期:2024-06-10
set -e # 任何命令失败,立即退出
set -u # 任何未定义变量引用,立即退出
BACKUP_DIR="/backup"
SOURCE_DIR="/etc"
DATE=$(date +%Y%m%d)
ARCHIVE_NAME="etc-${DATE}.tar.gz"
LOG_FILE="/var/log/backup-etc.log"
# 记录开始时间
echo "[$(date)] START backup of ${SOURCE_DIR}" >> "${LOG_FILE}"
# 创建 tar.gz 归档,排除临时文件和敏感目录
# --exclude 排除 /etc/ssl/private(私钥)、/etc/shadow(密码哈希)、/etc/ssh/*_key(SSH 私钥)
tar -czf "${BACKUP_DIR}/${ARCHIVE_NAME}" \
--exclude='/etc/ssl/private' \
--exclude='/etc/shadow' \
--exclude='/etc/shadow-' \
--exclude='/etc/ssh/*_key' \
--exclude='/etc/ssh/*_key.pub' \
-C / "${SOURCE_DIR#/}" 2>> "${LOG_FILE}"
# 验证归档完整性
if tar -tzf "${BACKUP_DIR}/${ARCHIVE_NAME}" > /dev/null 2>&1; then
echo "[$(date)] SUCCESS: ${ARCHIVE_NAME} created" >> "${LOG_FILE}"
else
echo "[$(date)] ERROR: ${ARCHIVE_NAME} is corrupted" >> "${LOG_FILE}"
exit 1
fi
# 删除 7 天前的备份
find "${BACKUP_DIR}" -name "etc-????????.tar.gz" -mtime +7 -delete 2>> "${LOG_FILE}"
# 记录结束时间
echo "[$(date)] END backup" >> "${LOG_FILE}"
关键细节说明 :
-
set -e和set -u是 Bash 脚本的“安全开关”,防止部分命令失败导致后续逻辑继续执行。 -
tar -C / "${SOURCE_DIR#/}"中的"${SOURCE_DIR#/}"是 Bash 参数展开,作用是去掉/etc开头的/,变成etc,这样tar归档时路径是相对的etc/xxx,解压时不会覆盖根目录。 -
--exclude使用通配符*_key,能同时排除id_rsa、ssh_host_rsa_key等所有私钥文件。 -
find ... -mtime +7中的+7表示“超过 7 天”,即保留最近 7 天的备份(含当天)。
步骤 3:赋予脚本可执行权限并测试
sudo chmod +x /usr/local/bin/backup-etc.sh
# 手动执行一次,观察输出和日志
sudo /usr/local/bin/backup-etc.sh
# 检查日志
sudo tail -20 /var/log/backup-etc.log
# 检查备份文件
ls -lh /backup/etc-*.tar.gz
实测心得:永远先手动执行脚本,再加入 cron。我见过太多人直接写进 crontab,结果因为
PATH问题或权限问题,脚本静默失败,直到磁盘爆满才发现备份从未成功。
步骤 4:编辑 root 的 crontab
sudo crontab -e
在打开的编辑器中,添加以下三行:
# 设置 PATH,确保能找到 tar, find, date 等命令
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
# 每天凌晨 2:00 执行备份
0 2 * * * /usr/local/bin/backup-etc.sh
# 每天凌晨 2:05 检查备份文件是否存在(作为监控钩子)
5 2 * * * [ -f "/backup/etc-$(date -d 'today' +\%Y\%m\%d).tar.gz" ] || echo "ERROR: etc backup missing for $(date -d 'today' +\%Y\%m\%d)" | mail -s "Backup Alert" admin@example.com
注意:
date -d 'today' +\%Y\%m\%d中的\%是为了防止 cron 在解析时提前展开%(cron 会把%当作换行符处理,其后的所有内容都会被当作 stdin 传给命令)。所以必须用\%转义。
4.2 企业级 cron 管理:如何让 50+ 个任务不再失控
当你的服务器上运行着 50 个 cron 任务时,
crontab -e
的纯文本编辑方式会迅速失效。你需要一套可版本控制、可审计、可批量部署的管理体系。我的实践方案是:
方案 A:使用
/etc/cron.d/
目录(推荐)
/etc/cron.d/
是 Ubuntu 18.04 的标准扩展目录。
crond
会定期扫描此目录下的所有文件(忽略以
.
开头的文件),并将它们视为独立的 crontab。每个文件的语法与
/etc/crontab
相同,
但多了一列:用户名
。格式为:
# .---------------- minute (0 - 59)
# | .------------- hour (0 - 23)
# | | .---------- day of month (1 - 31)
# | | | .------- month (1 - 12) OR jan,feb,mar,apr ...
# | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# | | | | |
# * * * * * user-name command to be executed
例如,创建
/etc/cron.d/backup-mysql
:
# /etc/cron.d/backup-mysql
# 备份 MySQL 数据库,每天凌晨 3:30
30 3 * * * mysqluser /usr/local/bin/backup-mysql.sh
优势 :
-
每个任务文件可以独立管理、独立权限控制(
chmod 644 /etc/cron.d/backup-mysql); -
可以用 Ansible、Puppet 等工具批量部署,
/etc/cron.d/下的文件名就是任务 ID; -
crond会自动 reload 修改后的文件,无需sudo systemctl reload cron; -
任务归属清晰,
mysqluser用户的任务不会污染root的 crontab。
方案 B:使用 cron-wrapper 脚本统一入口
创建一个中央调度脚本
/usr/local/bin/cron-runner.sh
:
#!/bin/bash
# cron-runner.sh
# 根据参数执行不同任务,所有任务日志统一到 /var/log/cron-runner.log
TASK=$1
LOG_FILE="/var/log/cron-runner.log"
echo "[$(date)] START task: ${TASK}" >> "${LOG_FILE}"
case "${TASK}" in
"backup-etc")
/usr/local/bin/backup-etc.sh
;;
"backup-mysql")
/usr/local/bin/backup-mysql.sh
;;
"logrotate")
/usr/sbin/logrotate /etc/logrotate.conf
;;
*)
echo "Unknown task: ${TASK}" >> "${LOG_FILE}"
exit 1
;;
esac
echo "[$(date)] END task: ${TASK}" >> "${LOG_FILE}"
然后在
/etc/cron.d/cron-runner
中:
# /etc/cron.d/cron-runner
30 2 * * * root /usr/local/bin/cron-runner.sh backup-etc
0 3 * * * root /usr/local/bin/cron-runner.sh backup-mysql
5 3 * * * root /usr/local/bin/cron-runner.sh logrotate
优势 :
-
所有任务日志集中,便于
grep和 ELK 收集; - 任务逻辑与调度分离,修改脚本不影响 crontab;
-
可以在
cron-runner.sh中加入全局的错误处理、告警、性能监控。
方案 C:版本控制与变更审计
将
/etc/cron.d/
目录纳入 Git:
sudo git init /etc/cron.d
sudo git config --global user.name "SysAdmin"
sudo git config --global user.email "admin@company.com"
sudo git add /etc/cron.d/
sudo git commit -m "Initial commit: backup tasks"
每次修改任务,都执行:
sudo git add /etc/cron.d/backup-etc
sudo git commit -m "backup-etc: add exclusion for /etc/ssl/private"
sudo git push origin main
这样,每一次 cron 任务的变更都有完整的历史记录、作者、时间戳,满足金融行业的合规审计要求。
5. 常见问题与排查技巧实录:那些让你抓狂的 cron 故障现场
5.1 典型问题速查表
| 问题现象 | 可能原因 | 排查命令 | 解决方案 | |----------|----------|----------|

481

被折叠的 条评论
为什么被折叠?



