Linux 自动化巡检脚本实现

1次阅读

优先选bash,因其轻量、无依赖、启动快,适合纯系统指标采集;python仅在需日志解析、api调用或生成html报告时使用。

Linux 自动化巡检脚本实现

巡检脚本该用 bash 还是 Python?

优先选 bash,除非你要做日志解析、API 调用或生成 HTML 报告。纯系统指标采集(CPU、内存、磁盘、进程、服务状态)用 bash 更轻量、无依赖、启动快。Python 虽然写起来顺手,但每次执行都要加载解释器,在低配服务器上可能拖慢巡检节奏,而且容易因环境缺失 psutilrequests 直接失败。

常见错误现象:/usr/bin/env: ‘python’: No such file or Directory —— 很多 centos 7+ 默认没装 python3,连软链接都未必有;而 bash 在所有 linux 发行版里都是稳的。

  • 简单指标采集(df -hfree -msystemctl is-active sshd)全用 bash 写,50 行内搞定
  • 需要正则提取日志关键字(比如从 /var/log/secure 找 failed login)再用 grep -E + awk,别急着上 Python
  • 真要调用外部 API(如钉钉机器人推送),用 curljson 就够了,不用引入 requests

怎么让脚本安全地获取 root 权限又不暴露密码?

别在脚本里写 sudo su -c 或硬编码密码。直接用 sudo 配置免密命令白名单最稳妥。运维账号本身不该有 root 密码,也不该用 ssh root@localhost 绕。

使用场景:脚本需执行 df -h(普通用户可运行)和 journalctl -n 20 --since "1 hour ago"(默认非 root 不可见)—— 后者必须提权。

  • 编辑 /etc/sudoers.d/healthcheck(用 visudo),加一行:monitor ALL=(root) NOPASSWD: /usr/bin/journalctl
  • 脚本里调用时写成 sudo journalctl -n 20 --since "1 hour ago" | grep -i 'failed|denied',不加 -S 或交互式输密码
  • 禁止写 ALL=(root) NOPASSWD: ALL,这是高危配置;只放开真正需要的二进制路径,且带参数限制(必要时用 sha256sum 校验命令完整性)

输出结果怎么存才方便后续分析?

别用纯文本追加到 /tmp/health.log。时间戳混乱、无结构、难 grep。直接输出为带字段的 TS SV(Tab-Separated Values),文件名带日期,保留最近 7 天即可。

性能影响:每天写一次大文件比每分钟追加小段快得多;用 date +%Y%m%d 命名,避免 find /var/log/health -mtime +7 -delete 误删。

  • 每行格式统一:$(date '+%Y-%m-%d %H:%M') $(hostname) $(df -h / | awk 'NR==2 {print $5}') $(systemctl is-active nginx)
  • 输出重定向用 > /var/log/health/$(date +%Y%m%d).tsv,不是 >>,避免跨天混写
  • 检查磁盘空间前先 df /var/log | awk '$5 > 90 {exit 1}',超阈值就跳过写入,防止巡检本身把磁盘打满

定时执行时为什么 cron 日志总为空?

cron 环境变量和你手动执行时完全不同:PATH 极简、没 ~/.bashrc$HOME 可能指向 /root。脚本里写的 python3jq,cron 找不到。

错误现象:CRON[1234]: (root) CMD (/opt/scripts/check.sh) 出现在 /var/log/cron,但脚本没输出、没发通知、也没报错文件。

  • 脚本开头固定写三行:#!/bin/bashexport PATH="/usr/local/bin:/usr/bin:/bin"cd /opt/scripts || exit 1
  • 所有命令用绝对路径:/bin/df/usr/bin/systemctl/usr/bin/journalctl,别信 $PATH
  • 重定向 stderr 到日志:/opt/scripts/check.sh >> /var/log/health/cron.log 2>&1,否则错误全丢进黑洞

最容易被忽略的是环境隔离——哪怕脚本本地测试全通,放进 cron 就静默失败。每次改完先手动跑 env -i /bin/bash -c '/opt/scripts/check.sh' 模拟 cron 环境,再扔进定时任务。

text=ZqhQzanResources