从零构建高可用自动化诊断工具
在当前复杂多变的IT基础设施中,系统环境检测脚本已成为运维工程师、开发人员及SRE工程师的必备利器,无论是部署前的环境预检、故障排查时的快速诊断,还是CI/CD流水线中的合规校验,一套健壮的检测脚本能够有效降低人为操作失误,提升自动化运维效率,如何从需求分析到代码落地,实现一套既准确又灵活的系统环境检测脚本?本文将为您拆解完整路径,并提供可复用的代码范式。

📖 目录导读
- 理解核心需求:脚本应检测什么?
硬件资源、操作系统版本、依赖服务、网络连通性
- 检测脚本的设计原则
模块化、幂等性、可扩展性
- 关键技术实现:通用检测模块拆解
配置管理、执行引擎、结果输出
- 实战代码示例:基于Shell的通用检测框架
- 常见Q&A:优化与排坑技巧
- 进阶:集成告警与CI/CD流水线
检测脚本的核心检测维度
在编写脚本前,必须明确“检测什么”,综合多套成熟方案,建议覆盖以下四大类:
- 硬件与内核环境
- CPU核数、内存大小、磁盘使用率、系统负载(
uname -a、free -m、df -h)
- CPU核数、内存大小、磁盘使用率、系统负载(
- 操作系统与软件版本
- 系统发行版(
cat /etc/os-release)、内核版本、必备命令是否安装(command -v)
- 系统发行版(
- 关键服务与端口状态
- 数据库、Nginx、Redis等进程存活(
ps aux | grep);端口监听(ss -tlnp)
- 数据库、Nginx、Redis等进程存活(
- 网络连通性与DNS解析
- 外网连通性(
ping、curl)、DNS获取A记录、指定端口的TCP连通性(nc -zv)
- 外网连通性(
设计原则小提示:脚本不应破坏环境,应保持只读检测,新增的文件或临时安装包必须清理。
模块化设计原则
为保证脚本的可维护性与复用性,建议遵循以下原则:
- 配置分离:将检测阈值、主机列表、端口信息抽取至单独配置文件(如YAML或
.env)。 - 函数化封装:每个检测项成为独立函数,通过返回值或状态码判断通过/失败。
- 结果标准化:输出格式统一,推荐JSON或表格形式,便于后续程序解析。
- 幂等性:每次运行结果一致,不依赖之前的执行痕迹。
check_memory() {
local threshold=${1:-80} # 默认阈值80%
local usage=$(free | awk '/Mem:/ {printf "%.0f", $3/$2 * 100}')
if [ "$usage" -gt "$threshold" ]; then
echo "FAIL: Memory usage ${usage}% > ${threshold}%"
return 1
else
echo "PASS: Memory usage ${usage}%"
return 0
fi
}
关键技术实现拆解
一个完整的检测脚本包含三个核心执行阶段:
- 初始化阶段:加载配置、检查依赖命令是否存在。
- 执行阶段:依次运行所有检测函数,收集结果(可并行执行利用多核)。
- 报告阶段:汇总成功/失败/警告信息,输出汇总MD5校验或发送告警。
对于并行检测需求,使用xargs -P或wait &可实现加速;若需跨平台运行(Windows/Linux),则优先选择Python脚本中的platform模块。
实战代码示例:简明Shell检测框架
以下是一个可直接落地的检测框架,支持自定义配置和彩色输出:
#!/bin/bash
# 系统环境检测脚本 v2.0
set -euo pipefail
# 配置区
THRESHOLD_DISK=90
THRESHOLD_MEM=80
REQUIRED_CMD="curl nc awk free"
REQUIRED_SERVICE="sshd mysqld" # 改用实际服务名
# 初始化:检查关键命令
init_check() {
for cmd in $REQUIRED_CMD; do
if ! command -v $cmd &>/dev/null; then
echo "ERROR: $cmd not found. Abort."
exit 1
fi
done
}
# 检测函数:磁盘
check_disk() {
local usage=$(df / | awk 'NR==2 {print $5}' | sed 's/%//')
if [ "$usage" -gt "$THRESHOLD_DISK" ]; then echo "FAIL: Disk / ${usage}%"; return 1; else echo "PASS: Disk / ${usage}%"; fi
}
# 检测函数:CPU负载
check_cpu() {
local load=$(uptime | awk -F'load average:' '{print $2}' | cut -d, -f1 | sed 's/ //g')
if (( $(echo "$load > $(nproc)" | bc -l) )); then echo "FAIL: CPU load $load > cores"; else echo "PASS: CPU load $load"; fi
}
# 检测函数:服务端口
check_port() {
local port=3306
if nc -zv 127.0.0.1 "$port" &>/dev/null; then echo "PASS: Port $port open"; else echo "FAIL: Port $port not reachable"; fi
}
# 主执行
main() {
init_check
echo "========== 环境检测开始 =========="
check_disk
check_cpu
check_port
echo "========== 检测完成 =========="
}
main "$@"
常见Q&A:优化与排坑技巧
Q1:检测脚本在执行时卡住很久怎么办?
A1: 网络检测(如nc或curl)需设置超时,例如timeout 5 nc -zv host 80,并在脚本中捕获timeout返回码。
Q2:如何将脚本集成到Ansible或SaltStack?
A2: 脚本输出JSON格式结果,在配置管理工具中通过register变量读取(例如Ansible的shell模块并changed_when: false)。
Q3:生产环境中检测脚本可能泄露敏感端口信息吗?
A3: 建议使用日志分级(INFO、WARN、ERROR),禁止输出IP/端口至标准输出;敏感检测项仅在调试模式下打印。
Q4:检测脚本跨平台兼容(Linux与macOS)?
A4: macOS缺乏nc的-z参数,需用/dev/tcp重定向或改用Python的socket模块,推荐用uname -s做平台判断。
进阶:集成告警与CI/CD
- 与Prometheus集成:脚本输出Key-Value格式暴露为Prometheus文本,配合
node_exporter的textfile收集器。 - 与Jenkins/GitLab CI集成:在流水线中直接调用脚本,根据返回值判定继续或中止构建。
stages: - env_check environment_check: script: "./sys_check.sh" allow_failure: false
- 告警通知:失败项通过
mailx、Slack Webhook或钉钉机器人推送,实现无人值守。