09 - 定时任务与自动化运维

一、cron 定时任务

cron 是 Linux 最常用的定时任务服务,可以按固定时间周期执行命令或脚本。

1.1 crontab 命令

# 编辑当前用户的定时任务
crontab -e

# 查看当前用户的定时任务
crontab -l

# 删除所有定时任务
crontab -r

# 编辑指定用户的定时任务(需要 root)
crontab -u alice -e
crontab -u alice -l

1.2 cron 表达式

*    *    *    *    *    要执行的命令
│    │    │    │    │
│    │    │    │    └── 星期 (0-7,0和7都是周日)
│    │    │    └────── 月份 (1-12)
│    │    └─────────── 日期 (1-31)
│    └────────────── 小时 (0-23)
└───────────────── 分钟 (0-59)

常用 cron 表达式

表达式 含义
*/5 * * * * 每 5 分钟
0 * * * * 每小时整点
0 2 * * * 每天凌晨 2 点
0 2 * * 1 每周一凌晨 2 点
0 0 1 * * 每月 1 号零点
0 2 * * 1-5 工作日凌晨 2 点
*/30 9-18 * * 1-5 工作时间每 30 分钟
0 0,12 * * * 每天零点和 12 点

特殊关键字

@reboot        # 系统启动时执行
@yearly        # 每年(0 0 1 1 *)
@monthly       # 每月(0 0 1 * *)
@weekly        # 每周(0 0 * * 0)
@daily         # 每天(0 0 * * *)
@hourly        # 每小时(0 * * * *)

1.3 crontab 示例

# 每天凌晨 2 点备份数据库
0 2 * * * /opt/scripts/backup_db.sh >> /var/log/backup_db.log 2>&1

# 每 5 分钟检查服务状态,挂了自动重启
*/5 * * * * /opt/scripts/check_service.sh

# 每周日凌晨 3 点清理日志
0 3 * * 0 find /var/log -name "*.log" -mtime +30 -delete

# 开机时启动自定义脚本
@reboot /opt/scripts/init_env.sh

1.4 cron 注意事项

# 1. cron 环境变量极少,脚本中需手动设置 PATH
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

# 2. cron 中的百分号 % 需要转义(或用在脚本中)
# 错误写法:
# 0 2 * * * date +%Y%m%d > /tmp/date.txt
# 正确写法:
0 2 * * * date +\%Y\%m\%d > /tmp/date.txt

# 3. 推荐将复杂逻辑放在脚本中,cron 只调用脚本
0 2 * * * /opt/scripts/daily_task.sh

# 4. 确保脚本有执行权限
chmod +x /opt/scripts/daily_task.sh

1.5 系统级定时任务

除了用户 crontab,还可以通过以下方式配置系统级定时任务:

# /etc/crontab - 系统主 crontab(多一个用户字段)
# 格式:分 时 日 月 周 用户 命令
0 2 * * * root /opt/scripts/system_backup.sh

# /etc/cron.d/ - 放置独立的定时任务文件
# 格式同 /etc/crontab
cat > /etc/cron.d/backup << 'EOF'
0 2 * * * root /opt/scripts/backup.sh
EOF

# /etc/cron.hourly/   - 每小时执行
# /etc/cron.daily/    - 每天执行
# /etc/cron.weekly/   - 每周执行
# /etc/cron.monthly/  - 每月执行
# 只需将脚本放入对应目录即可
cp backup.sh /etc/cron.daily/
chmod +x /etc/cron.daily/backup.sh

1.6 cron 日志

# 查看 cron 执行日志
# CentOS/RHEL
grep CRON /var/log/cron

# Ubuntu/Debian
grep CRON /var/log/syslog

# 查看 cron 服务状态
systemctl status crond       # CentOS
systemctl status cron        # Ubuntu

二、at 一次性任务

at 用于执行一次性定时任务(执行后自动删除)。

# 安装
yum install -y at            # CentOS
apt install -y at            # Ubuntu

# 启动服务
systemctl enable --now atd

# 今晚 23:00 执行
echo "shutdown -h now" | at 23:00

# 5 分钟后执行
echo "echo 'hello' > /tmp/test.txt" | at now + 5 minutes

# 明天早上 8 点执行
at 8:00 tomorrow
at> echo "Good morning"
at> <Ctrl+D>                 # 按 Ctrl+D 提交

# 查看待执行任务
atq
at -l

# 删除任务
atrm 1                       # 删除任务 ID 为 1 的任务

三、Ansible 自动化运维

3.1 Ansible 简介

Ansible 是基于 SSH 的自动化运维工具,无需在目标机器安装客户端。

特性 说明
无 Agent 通过 SSH 管理目标机器
幂等性 多次执行结果一致
YAML 语法 易读易写
模块化 丰富的内置模块

3.2 安装与配置

# 安装(控制端)
yum install -y ansible       # CentOS
apt install -y ansible       # Ubuntu
pip install ansible          # 通用

# 配置主机清单
cat > /etc/ansible/hosts << 'EOF'
[webservers]
192.168.1.10 ansible_ssh_user=root
192.168.1.11 ansible_ssh_user=root

[dbservers]
192.168.1.20 ansible_ssh_user=root

[all:vars]
ansible_ssh_private_key_file=~/.ssh/id_rsa
EOF

# 测试连通性
ansible all -m ping
ansible webservers -m ping

3.3 Ad-hoc 命令

# 执行命令
ansible all -a "uptime"
ansible webservers -a "df -h"

# 使用模块
# yum 模块 - 安装软件
ansible webservers -m yum -a "name=nginx state=present"

# service 模块 - 管理服务
ansible webservers -m service -a "name=nginx state=started enabled=yes"

# copy 模块 - 复制文件
ansible webservers -m copy -a "src=/etc/hosts dest=/etc/hosts"

# file 模块 - 创建目录
ansible webservers -m file -a "path=/data/app state=directory mode=0755"

# user 模块 - 创建用户
ansible all -m user -a "name=deploy shell=/bin/bash groups=wheel"

# setup 模块 - 获取主机信息
ansible webservers -m setup
ansible webservers -m setup -a "filter=ansible_memory_mb"

3.4 Playbook 示例

---
# deploy_nginx.yml - 部署 Nginx
- name: Deploy Nginx Web Server
  hosts: webservers
  become: yes              # 使用 sudo

  tasks:
    - name: Install Nginx
      yum:
        name: nginx
        state: present

    - name: Copy nginx config
      copy:
        src: files/nginx.conf
        dest: /etc/nginx/nginx.conf
        backup: yes
      notify: restart nginx

    - name: Create web root
      file:
        path: /var/www/html
        state: directory
        owner: nginx
        group: nginx
        mode: '0755'

    - name: Copy index page
      copy:
        src: files/index.html
        dest: /var/www/html/index.html

    - name: Start and enable Nginx
      service:
        name: nginx
        state: started
        enabled: yes

  handlers:
    - name: restart nginx
      service:
        name: nginx
        state: restarted
# 执行 playbook
ansible-playbook deploy_nginx.yml

# 检查语法
ansible-playbook --syntax-check deploy_nginx.yml

# 模拟执行(不实际修改)
ansible-playbook --check deploy_nginx.yml

# 查看执行步骤
ansible-playbook --list-tasks deploy_nginx.yml

四、其他自动化工具

4.1 工具对比

工具 特点 适用场景
Shell + cron 简单直接,无需额外安装 小规模、简单任务
Ansible 无 Agent,YAML 语法,学习成本低 中小规模批量管理
SaltStack 高性能,实时通信 大规模基础设施
Puppet 声明式,成熟稳定 大型企业
Terraform 基础设施即代码 云资源管理

4.2 自动化运维最佳实践

  1. 脚本版本管理:所有运维脚本纳入 Git 管理
  2. 幂等性设计:脚本可以安全地重复执行
  3. 日志记录:每次执行都有日志,便于追溯
  4. 错误通知:任务失败时发送告警(邮件/钉钉/微信)
  5. 测试环境验证:先在测试环境验证,再推到生产

五、实战场景

场景一:监控 + 自动恢复

#!/bin/bash
# /opt/scripts/monitor_service.sh
# 检查服务状态,自动重启并告警

SERVICE="nginx"
LOG="/var/log/service_monitor.log"
ALERT_EMAIL="ops@example.com"

if ! systemctl is-active --quiet $SERVICE; then
    echo "[$(date)] $SERVICE 已停止,尝试重启..." >> $LOG
    systemctl restart $SERVICE
    sleep 3

    if systemctl is-active --quiet $SERVICE; then
        echo "[$(date)] $SERVICE 重启成功" >> $LOG
        echo "$SERVICE$(date) 自动重启成功" | mail -s "服务恢复告警" $ALERT_EMAIL
    else
        echo "[$(date)] $SERVICE 重启失败!" >> $LOG
        echo "$SERVICE$(date) 重启失败,请紧急处理!" | mail -s "紧急故障告警" $ALERT_EMAIL
    fi
fi
# 加入 cron,每 2 分钟检查
*/2 * * * * /opt/scripts/monitor_service.sh

场景二:日志轮转

#!/bin/bash
# /opt/scripts/log_rotate.sh
# 按天切割日志,保留 30 天

LOG_DIR="/var/log/myapp"
KEEP_DAYS=30

# 切割日志
cd $LOG_DIR
for log_file in *.log; do
    [ -f "$log_file" ] || continue
    mv "$log_file" "${log_file}.$(date +%Y%m%d)"
    gzip "${log_file}.$(date +%Y%m%d)"
done

# 通知应用重新打开日志文件
# kill -USR1 $(pidof nginx)

# 清理旧日志
find $LOG_DIR -name "*.log.*.gz" -mtime +$KEEP_DAYS -delete

echo "[$(date)] 日志轮转完成" >> /var/log/log_rotate.log
# 每天凌晨执行
0 0 * * * /opt/scripts/log_rotate.sh

场景三:定时备份并同步到远程

#!/bin/bash
# /opt/scripts/backup_and_sync.sh
set -euo pipefail

SOURCE="/data/mysql"
LOCAL_BACKUP="/backup/mysql"
REMOTE_SERVER="backup@192.168.1.100:/backup/mysql/"
DATE=$(date +%Y%m%d)
KEEP=7

mkdir -p $LOCAL_BACKUP

# 1. 备份数据库
mysqldump -u root -p"$DB_PASS" --all-databases | gzip > "$LOCAL_BACKUP/db_${DATE}.sql.gz"

# 2. 同步到远程
rsync -az --progress "$LOCAL_BACKUP/db_${DATE}.sql.gz" "$REMOTE_SERVER"

# 3. 清理本地旧备份
find $LOCAL_BACKUP -name "db_*.sql.gz" -mtime +$KEEP -delete

echo "[$(date)] 备份并同步完成" >> /var/log/backup.log
# 每天凌晨 3 点执行
0 3 * * * /opt/scripts/backup_and_sync.sh >> /var/log/backup.log 2>&1

六、小结

本篇介绍了 cron 定时任务、at 一次性任务、Ansible 自动化运维以及实战自动化脚本。定时任务结合 Shell 脚本是运维自动化的第一层,Ansible 则适合大规模批量管理。核心原则是:能自动化的不要手动做。


上一篇08 - Shell 脚本编程入门
下一篇10 - 日志管理与故障排查

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐