凌晨3点7分,电话响了。
我迷迷糊糊摸到手机,屏幕上显示“机房”。接起来那边就喊:“服务器CPU满了!”
挂了电话我坐起来揉眼睛,心里有点发慌。这已经是这个月第三次了。
SSH连上去一看,top命令显示某个Java进程吃掉了所有CPU资源。我赶紧kill掉进程,重启服务,看日志。等搞完已经快5点,天都亮了。
后来我想了个办法——写个脚本,每天凌晨自动巡检一次服务器,把关键指标记录下来。这样出问题之前就能发现,不用等报警电话炸醒。
为什么要自动化巡检
领导让我每天手动检查10台服务器。每台都要挨个敲命令:uptime、free、df、top...敲完一遍半小时。偶尔漏看一行,回头就出问题。
最烦的是人会有状态不好的时候。凌晨3点的脑子,判断力真的不行。你可能误杀进程,可能看错日志,可能在慌乱中操作失误。机器不会累,不会困,不会因为状态不好就跳过检查项。
还有就是规模问题。手头3台服务器还行,300台呢?靠脑子记,靠手动敲,就是在给自己挖坑。
我见过有人把巡检脚本搞得像艺术品,输出一堆花里胡哨的图表。其实最实用的就是简单:一行命令跑完,输出一个能看懂的报告,30秒内搞定。服务器都报警了,你的巡检脚本如果还要跑半天,就是在添乱。
一个好脚本应该什么样
我试过很多别人的脚本,有的只检查CPU不管内存,有的输出几千行让人头晕,有的运行一次要等5分钟卡在某个超时命令上。
真正好用的巡检脚本,我觉得就几个要求:
快。 30秒内完成所有检查。
准。 信息要准确,格式要清晰,不要输出没用的东西。
全。 CPU、内存、磁盘、网络、进程、服务、更新、日志,关键信息都有。
易用。 一行命令跑完,输出一个能看懂的报告,支持不同Linux版本。
完整的巡检脚本
这是我平时用的巡检脚本,基于Bash写的,支持CentOS/Ubuntu/Debian:
#!/bin/bash
# Linux系统巡检脚本
# 支持: CentOS 7/8, Ubuntu 18.04/20.04/22.04, Debian 9/10/11
set -e
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
REPORT_TIME=$(date +"%Y-%m-%d %H:%M:%S")
OUTPUT_FILE="/tmp/linux_check_${TIMESTAMP}.txt"
# 检测操作系统
if [ -f /etc/os-release ]; then
. /etc/os-release
OS=$ID
OS_VERSION=$VERSION_ID
else
echo "无法检测操作系统版本"
exit 1
fi
# 生成报告
{
echo "Linux系统巡检报告"
echo "===================="
echo "巡检时间: $REPORT_TIME"
echo ""
# 系统信息
echo "【系统信息】"
echo "主机名: $(hostname)"
echo "操作系统: $PRETTY_NAME"
echo "内核: $(uname -r)"
if systemd-detect-virt -q 2>/dev/null; then
echo "运行环境: 虚拟机 ($(systemd-detect-virt))"
else
echo "运行环境: 物理机"
fi
echo ""
# 运行时间
echo "【运行时间】"
UPTIME_SECONDS=$(cat /proc/uptime | awk '{print $1}' | cut -d. -f1)
UPTIME_DAYS=$((UPTIME_SECONDS / 86400))
UPTIME_HOURS=$(((UPTIME_SECONDS % 86400) / 3600))
echo "已运行: ${UPTIME_DAYS}天 ${UPTIME_HOURS}小时"
echo ""
# CPU信息
echo "【CPU信息】"
CPU_CORES=$(nproc)
CPU_USAGE=$(top -bn1 | grep "Cpu(s)" | sed "s/.*, *\([0-9.]*\)%* id.*/\1/" | awk '{print 100 - $1}')
echo "核心数: $CPU_CORES"
echo "当前使用率: ${CPU_USAGE}%"
echo ""
# 内存信息
echo "【内存信息】"
MEM_TOTAL=$(free -b | grep Mem | awk '{print $2}')
MEM_USED=$(free -b | grep Mem | awk '{print $3}')
MEM_USAGE_PERCENT=$(awk "BEGIN {printf \"%.1f\", ($MEM_USED / $MEM_TOTAL) * 100}")
echo "总内存: $(numfmt --to=iec $MEM_TOTAL)"
echo "已用: $(numfmt --to=iec $MEM_USED) (${MEM_USAGE_PERCENT}%)"
echo ""
# 磁盘信息
echo "【磁盘信息】"
df -h | grep -vE '^Filesystem|tmpfs|cdrom' | while read -r line; do
MOUNT=$(echo "$line" | awk '{print $6}')
USE_PERCENT=$(echo "$line" | awk '{print $5}' | sed 's/%//')
if [ "$USE_PERCENT" -gt 90 ]; then
echo "$MOUNT: 警告 (${USE_PERCENT}%)"
elif [ "$USE_PERCENT" -gt 80 ]; then
echo "$MOUNT: 注意 (${USE_PERCENT}%)"
else
echo "$MOUNT: 正常 (${USE_PERCENT}%)"
fi
done
echo ""
# 网络信息
echo "【网络信息】"
ip -4 addr show | grep -E "^[0-9]+:|inet " | while read -r line; do
if echo "$line" | grep -q "^[0-9]"; then
IFACE=$(echo "$line" | awk -F: '{print $2}' | xargs)
echo "$IFACE:"
elif echo "$line" | grep -q "inet "; then
IP=$(echo "$line" | awk '{print $2}' | cut -d/ -f1)
echo " $IP"
fi
done
echo ""
# 进程信息
echo "【进程信息】"
echo "内存占用Top 5:"
ps aux --sort=-%mem | head -6 | tail -5 | awk '{printf " %s: %.1f%%\n", $11, $4*100}'
echo ""
# 关键服务
echo "【关键服务】"
for service in sshd cron network; do
if systemctl is-active --quiet $service 2>/dev/null; then
echo "$service: 运行中"
fi
done
echo ""
# 更新检查
echo "【系统更新】"
if [ "$OS" = "ubuntu" ] || [ "$OS" = "debian" ]; then
UPDATES=$(apt list --upgradable 2>/dev/null | grep -v "^Listing" | wc -l)
echo "可更新包: $UPDATES 个"
elif [ "$OS" = "centos" ] || [ "$OS" = "rhel" ]; then
UPDATES=$(yum check-update --quiet 2>/dev/null | wc -l)
echo "可更新包: $UPDATES 个"
fi
echo ""
# 错误日志
echo "【错误日志】"
journalctl -p err -n 5 --no-pager 2>/dev/null | while read -r line; do
echo " $line"
done
echo ""
echo "报告完成"
} > "$OUTPUT_FILE"
cat "$OUTPUT_FILE"
这个脚本简单实用,你可以根据需要调整检查项,比如加上端口监听、数据库连接数检查之类的。如果你对编写这类脚本有更多想法,也可以在云栈社区的运维板块和其他人交流探讨。
怎么用
保存脚本,给执行权限,直接运行:
chmod +x linux_check.sh
sudo ./linux_check.sh
想自动化,加到crontab里:
crontab -e
# 每天凌晨2点执行
0 2 * * * /path/to/linux_check.sh >> /var/log/linux_check.log 2>&1
别等报警了再动
我现在每天早上到办公室第一件事,就是看巡检报告。磁盘到80%了就提前清理,内存占用高了就查原因,不用等系统出问题再救火。
巡检脚本给了你一双眼睛,让你看清服务器里的一切。当你真的了解自己的系统,凌晨3点的电话就不会那么吓人了。
因为你在问题出现之前就已经发现了。
对了,最后说个事。
上周有次巡检脚本报警,说某台服务器磁盘使用率超过90%。我查了一下,是个日志文件占了几百G,删掉之后搞定,已经提前解决了未来可能发生的问题。
如果没这个巡检,等磁盘爆满的时候可能已经挂了。