文章总结: 本文介绍利用ClaudeCode开发的运维健康检查系统,涵盖基础健康、深度安全及Docker监控模块。工具基于Bash脚本,轻量且兼容性强,支持Markdown与JSON双格式输出。功能涉及资源监控、挖矿与勒索检测、异常网络分析及容器管理。文章详述架构与实现,验证了其在巡检和安全审计中的高效性,适合运维团队快速部署。 综合评分: 90 文章分类: 安全工具,安全建设,安全运营,解决方案,网络安全
让Claude Code写了个运维健康检查的Skill还挺好用的
原创
xiejava xiejava
fullbug
2026年1月21日 22:36 湖南
手头上有几台服务器,经常要对服务器进行健康检查、安全检查等。这几天让ClaudeCode自己写了个Skill这样就一句话活就让AI给干了。本文详细介绍了如何使用Claude Code AI辅助开发工具,从零开始构建一个生产级运维健康检查的Skill。重点阐述了整体架构设计、核心功能实现细节以及实际应用效果。该系统采用模块化设计,提供三大检查模块(基础健康检查、深度安全审计、Docker容器监控),支持双格式输出(Markdown人工可读 + JSON机器可处理),具有良好的可扩展性和兼容性。
一、背景与设计目标
1.1 实际需求
在日常运维工作中,我们需要对多台服务器进行健康检查,涵盖系统资源、Docker容器状态、安全指标等多个维度。虽然市面上有很多成熟的监控方案(如Prometheus、Grafana、Zabbix等),但在以下场景中,我们需要一个轻量级、快速部署的检查工具:
- 日常巡检:每天对服务器进行快速健康扫描
- 安全审计:定期检查异常进程、可疑网络连接、文件系统安全
- 容器监控:检查Docker容器运行状态、资源使用情况
- 问题排查:当系统出现问题时,快速获取当前状态信息
1.2 设计目标
基于上述需求,我设定了以下设计目标交给了Claude Code:
核心特性:
- ✅ 轻量级部署:基于Bash脚本,无需额外依赖,远程执行无需安装
- ✅ 双格式输出:同时生成Markdown(人工阅读)和JSON(机器处理)格式
- ✅ 模块化架构:三大检查模块独立运行,可按需组合
- ✅ 状态可视化:使用emoji(✅正常/⚠️警告/❌严重)直观展示
- ✅ 广泛兼容性:支持bash 3.2+(macOS默认版本),适配主流Linux发行版
二、整体架构设计
2.1 系统架构
Claude Code自动帮我设计了整体架构 运维健康检查系统采用模块化设计,包含三个独立的检查模块:
| 模块名称 | 脚本文件 | 功能定位 | 核心检查项 | | — | — | — | — | | 基础健康检查 | health-check.sh | 日常巡检、快速评估 | 系统资源、内存、磁盘、网络、服务状态、基础安全 | | 深度安全检查 | security-check.sh | 安全审计、威胁检测 | 异常进程、可疑连接、文件安全、账户安全、系统完整性 | | Docker容器监控 | docker-check.sh | 容器环境管理 | 容器状态、资源使用、镜像管理、存储空间 |
设计原则:
- 独立性:每个脚本可单独运行,互不依赖
- 一致性:统一的输出格式和状态指示
- 可扩展性:易于添加新的检查项或模块
- 远程友好:支持SSH管道执行,无需远程安装
2.2 文件结构
| |
| — |
| host-manage/ ├── skills/ops-health-check/ │ ├── SKILL.md # Skill定义和使用文档 │ └── scripts/ │ ├── health-check.sh # 基础健康检查脚本 │ ├── security-check.sh # 深度安全检查脚本 │ ├── docker-check.sh # Docker监控脚本 │ └── lib/ │ └── output.sh # 输出格式化库(核心) ├── docs/plans/ │ ├── 2025-01-17-ops-health-check-design.md # 整体设计文档 │ └── 2025-01-18-json-output-design.md # JSON输出设计 └── health-reports/ # 检查报告输出目录 ├── health-check-*.md # Markdown格式报告 ├── health-check-*.json # JSON格式数据 ├── security-check-*.md ├── security-check-*.json ├── docker-check-*.md └── docker-check-*.json |
三、核心功能实现
Claude Code自动帮我实现了所有的功能
3.1 基础健康检查模块(health-check.sh)
这是日常运维使用最频繁的模块,专注于快速评估系统整体健康状况。
3.1.1 系统运行时间和负载检查
检查目的:了解系统运行时长和当前负载压力
实现逻辑:
| |
| — |
| # 获取系统运行时间 uptime_output=$(uptime) uptime_clean=$(echo"$uptime_output" | sed 's/^ *//g') # 兼容不同系统的uptime输出格式 uptime_str=$(uptime -p 2>/dev/null || \ echo"$uptime_clean" | awk -F'up ''{print $2}' | awk -F',''{print $1}') # 提取负载平均值(1分钟、5分钟、15分钟) load_str=$(echo"$uptime_clean" | awk -F'load average:''{print $2}' | sed 's/^ *//g') load_1min=$(echo$load_str | awk '{print $1}' | sed 's/,//') load_5min=$(echo$load_str | awk '{print $2}' | sed 's/,//') load_15min=$(echo$load_str | awk '{print $3}') # 判断负载状态 load_status=$(check_load_status "$load_1min""$CPU_WARNING""$CPU_CRITICAL") |
状态判断函数:
| |
| — |
| check_load_status() { local load=$1 local warning=$2 local critical=$3 # 使用bc进行浮点数比较 if (( $(echo"$load >= $critical" | bc -l) )); then echo"critical" elif (( $(echo"$load >= $warning" | bc -l) )); then echo"warning" else echo"ok" fi } |
关键点:
- 使用
bc -l进行浮点数比较,兼容不同系统 - 兼容
uptime -p命令(human-readable格式)不可用的情况 - 同时收集三个时间维度的负载数据,用于趋势分析
3.1.2 内存使用检查
检查目的:监控内存和swap使用情况,防止内存耗尽
实现逻辑:
| |
| — |
| # 获取内存信息(单位:MB) memory_info=$(free -m | grep Mem) mem_total=$(echo$memory_info | awk '{print $2}') mem_used=$(echo$memory_info | awk '{print $3}') mem_avail=$(echo$memory_info | awk '{print $7}') # available列更准确 mem_percent=$(awk "BEGIN {printf \"%.1f\", $mem_used * 100 / $mem_total}") # Swap检查 swap_info=$(free -m | grep Swap) swap_total=$(echo$swap_info | awk '{print $2}') swap_used=$(echo$swap_info | awk '{print $3}') if [ "$swap_total" -gt 0 ]; then swap_percent=$(awk "BEGIN {printf \"%.1f\", $swap_used * 100 / $swap_total}") else swap_percent=0 fi # 状态判断 if (( $(echo"$mem_percent >= $MEMORY_CRITICAL" | bc -l) )); then mem_status="critical" elif (( $(echo"$mem_percent >= $MEMORY_WARNING" | bc -l) )); then mem_status="warning" else mem_status="ok" fi |
输出示例:
| |
| — |
| ### 内存使用 - **总内存**: 16384MB - **已使用**: 12500MB (76.3%) - **可用**: 3884MB - **Swap**: 256MB / 2048MB (12.5%) - **状态**: ⚠️ 警告 |
关键点:
- 使用
free命令的available列而非free列,更准确反映可用内存 - 同时检查swap使用率,高swap使用率通常意味着内存压力
- 支持自定义阈值配置(通过环境变量
MEMORY_WARNING、MEMORY_CRITICAL)
3.1.3 磁盘空间检查
检查目的:监控所有挂载点的磁盘使用情况,防止磁盘空间不足
实现逻辑:
| |
| — |
| echo"### 磁盘空间" echo"| 挂载点 | 设备 | 容量 | 已用 | 可用 | 使用率 | 状态 |" echo"|--------|------|------|------|------|--------|------|" # 遍历所有挂载点(排除临时文件系统) df -h | grep -vE '^Filesystem|tmpfs|overlay|none' | whileread -r line; do device=$(echo$line | awk '{print $1}') size=$(echo$line | awk '{print $2}') used=$(echo$line | awk '{print $3}') avail=$(echo$line | awk '{print $4}') use_percent=$(echo$line | awk '{print $5}' | sed 's/%//') mount=$(echo$line | awk '{print $6}') # 判断状态 if [ "$use_percent" -ge "$DISK_CRITICAL" ]; then status="critical" emoji="❌" elif [ "$use_percent" -ge "$DISK_WARNING" ]; then status="warning" emoji="⚠️" else status="ok" emoji="✅" fi # 输出Markdown表格行 echo"| $mount | $device | $size | $used | $avail | ${use_percent}% | $emoji |" # 收集JSON数据 add_disk_data "$mount""device""$device" add_disk_data "$mount""total_gb""$size" add_disk_data "$mount""used_gb""$used" add_disk_data "$mount""available_gb""$avail" add_disk_data "$mount""used_percent""$use_percent" add_disk_data "$mount""status""$status" done |
输出示例:
| |
| — |
| ### 磁盘空间 | 挂载点 | 设备 | 容量 | 已用 | 可用 | 使用率 | 状态 | |--------|------|------|------|------|--------|------| | / | /dev/sda1 | 100G | 45G | 55G | 45.0% | ✅ 正常 | | /data | /dev/sdb1 | 500G | 425G | 75G | 85.0% | ⚠️ 警告 | | /boot | /dev/sda2 | 1G | 250M | 750M | 25.0% | ✅ 正常 | |
关键点:
- 自动过滤
tmpfs、overlay等临时文件系统 - 支持多个挂载点,每个挂载点独立判断状态
- 使用整数比较(已去除百分号),提高性能
- 同时生成Markdown表格和JSON数组数据
3.1.4 网络连接统计
检查目的:了解当前网络连接数量,快速发现异常连接
实现逻辑:
| |
| — |
| # 使用ss命令替代netstat(更现代) ifcommand -v ss >/dev/null 2>&1; then # 总连接数 total_connections=$(ss -tn | wc -l) # 外部连接数(排除本地回环) external_connections=$(ss -tn | awk '{print $5}' | \ grep -v '127.0.0.1' | \ grep -v '::1' | \ cut -d':' -f1 | \ sort -u | \ wc -l) # 监听端口数 listening_ports=$(ss -tln | wc -l) else # 降级到netstat total_connections=$(netstat -tn 2>/dev/null | wc -l) external_connections=$(netstat -tn 2>/dev/null | awk '{print $5}' | \ grep -v '127.0.0.1' | \ grep -v '::1' | \ cut -d':' -f1 | \ sort -u | \ wc -l) listening_ports=$(netstat -tln 2>/dev/null | wc -l) fi add_system_data "network_total_connections""$total_connections" add_system_data "network_external_connections""$external_connections" add_system_data "network_listening_ports""$listening_ports" |
关键点:
- 优先使用
ss命令(现代Linux推荐),降级到netstat - 统计外部独立IP连接数,而非连接总数(更准确反映异常)
- 包含监听端口数量,便于发现未授权监听
3.1.5 systemd服务状态检查
检查目的:检查系统服务运行状态,发现失败服务
实现逻辑:
| |
| — |
| # 检查systemd是否可用 ifcommand -v systemctl >/dev/null 2>&1; then # 统计服务状态 running_services=$(systemctl list-units --type=service --state=running 2>/dev/null | \ grep 'loaded loaded' | wc -l) failed_services=$(systemctl list-units --type=service --state=failed 2>/dev/null | \ grep 'loaded loaded' | wc -l) enabled_services=$(systemctl list-unit-files --type=service --state=enabled 2>/dev/null | \ grep 'enabled' | wc -l) # 获取失败服务列表 if [ "$failed_services" -gt 0 ]; then failed_list=$(systemctl list-units --type=service --state=failed 2>/dev/null | \ grep 'loaded loaded' | awk '{print $1}') echo"### 失败的服务" echo"$failed_list" | whileread -r service; do echo"- ❌ $service" done fi # 常用关键服务检查 critical_services=("ssh""docker""cron""rsyslog") for svc in"${critical_services[@]}"; do if systemctl is-active --quiet "${svc}.service" 2>/dev/null; then echo"- ✅ ${svc}.service: 运行中" else echo"- ⚠️ ${svc}.service: 未运行或不存在" fi done else echo"⚠️ 系统不使用systemd" fi |
输出示例:
| |
| — |
| ### 服务状态 - **运行中**: 23个 - **失败**: 2个 - **启用**: 15个 #### 关键服务状态 - ✅ ssh.service: 运行中 - ✅ docker.service: 运行中 - ✅ cron.service: 运行中 - ❌ postfix.service: 已停止 #### 失败的服务列表 - ❌ postfix.service - ❌ ufw.service |
关键点:
- 兼容非systemd系统(如SysV init)
- 区分”运行中”、”失败”、”启用”三种状态
- 单独检查关键服务(SSH、Docker等),便于快速定位问题
- 列出所有失败服务,方便管理员进一步排查
3.1.6 基础安全检查
虽然主要的安全检查在security-check.sh中,但基础健康检查也包含几个关键的安全指标:
| |
| — |
| echo"### 基础安全" # 1. 检查挖矿进程 MINING_PROCESSES=("xmrig""minerd""cpuminer""ccminer""Claymore") mining_found=0 for proc in"${MINING_PROCESSES[@]}"; do if pgrep -x "$proc" >/dev/null; then echo"- ❌ 发现挖矿进程: $proc" mining_found=1 fi done if [ $mining_found -eq 0 ]; then echo"- ✅ 未发现挖矿进程" fi # 2. 检查/tmp和/dev/shm中的可执行文件 tmp_execs=$(find /tmp /dev/shm -type f -executable 2>/dev/null | wc -l) if [ "$tmp_execs" -gt 0 ]; then echo"- ⚠️ 临时目录中发现 $tmp_execs 个可执行文件" else echo"- ✅ 临时目录无可执行文件" fi # 3. 检查失败登录次数(最近) if [ -f /var/log/auth.log ]; then failed_logins=$(grep "Failed password" /var/log/auth.log 2>/dev/null | \ tail -100 | wc -l) echo"- 最近失败登录次数: $failed_logins" fi |
3.2 深度安全检查模块(security-check.sh)
这是最复杂的模块,涵盖了5大类、20+项安全检查,用于全面的安全审计。
3.2.1 异常进程检测
检查目的:发现挖矿程序、高资源占用进程、可疑可执行文件
1. 挖矿进程检测
| |
| — |
| # 定义已知挖矿程序名称列表 MINING_PROCESSES=( "xmrig""minerd""cpuminer""ccminer""Claymore" "cryptonight""ethminer""nbminer""bminer" ) suspicious_procs="" mining_detected="false" # 遍历检查 for proc in"${MINING_PROCESSES[@]}"; do # 使用pgrep查找进程(比ps aux更快) found=$(pgrep -ix "$proc" 2>/dev/null) if [ -n "$found" ]; then # 获取进程详细信息 proc_info=$(ps -p "$found" -o pid,user,cmd --no-headers 2>/dev/null) suspicious_procs="$suspicious_procs\n$proc_info" mining_detected="true" # 记录到安全数据 add_security_data "mining_process""$proc" add_security_data "mining_pid""$found" fi done if [ "$mining_detected" = "true" ]; then echo"❌ 发现挖矿进程:" echo -e "$suspicious_procs" else echo"✅ 未发现挖矿进程" fi |
2. 高资源占用进程检测
| |
| — |
| echo"### 高资源占用进程(Top 10)" echo"| PID | 用户 | CPU% | 内存% | 命令 |" echo"|-----|------|------|--------|------|" # CPU占用最高的进程 ps aux --sort=-%cpu | head -n 11 | tail -n 10 | whileread -r line; do pid=$(echo"$line" | awk '{print $2}') user=$(echo"$line" | awk '{print $1}') cpu=$(echo"$line" | awk '{print $3}') mem=$(echo"$line" | awk '{print $4}') cmd=$(echo"$line" | awk '{for(i=11;i<=NF;i++)printf $i" "}' | cut -c1-50) # 标记异常高占用 if (( $(echo"$cpu > 80" | bc -l) )); then echo"| $pid | $user | **$cpu** | $mem | $cmd |" else echo"| $pid | $user | $cpu | $mem | $cmd |" fi done |
3. 临时目录可执行文件检查
| |
| — |
| # 检查/tmp和/dev/shm中的可执行文件 tmp_dirs=("/tmp""/dev/shm""/var/tmp") for dir in"${tmp_dirs[@]}"; do if [ -d "$dir" ]; then exec_files=$(find "$dir" -type f -executable 2>/dev/null) exec_count=$(echo"$exec_files" | grep -v '^$' | wc -l) if [ "$exec_count" -gt 0 ]; then echo"⚠️ $dir 中发现 $exec_count 个可执行文件:" echo"$exec_files" | head -n 10 | whileread -r file; do perms=$(stat -c "%a""$file" 2>/dev/null) size=$(stat -c "%s""$file" 2>/dev/null) mtime=$(stat -c "%y""$file" 2>/dev/null | cut -d'.' -f1) echo" - $file (权限:$perms, 大小:$size字节, 修改:$mtime)" done fi fi done |
关键点:
- 使用
pgrep而非ps aux | grep,性能更高且避免误匹配 - 记录进程的PID、用户、完整命令行,便于追踪
- 同时检查/tmp、/dev/shm、/var/tmp三个常见临时目录
- 显示文件的权限、大小、修改时间,帮助判断是否可疑
3.2.2 网络安全检查
检查目的:发现反向shell、可疑端口监听、异常外部连接
1. 反向shell检测
| |
| — |
| # 反向shell典型特征:外部IP连接本地高端口(非标准服务端口) echo"### 反向shell检测" # 获取所有TCP连接 ifcommand -v ss >/dev/null 2>&1; then connections=$(ss -tnp 2>/dev/null) else connections=$(netstat -tnp 2>/dev/null) fi # 检测可疑模式:外部IP连接到本地50000-65535端口 reverse_shell_detected="false" echo"$connections" | whileread -r line; do # 解析本地地址和远程地址 local_addr=$(echo"$line" | awk '{print $4}') remote_addr=$(echo"$line" | awk '{print $5}') # 提取端口号 local_port=$(echo"$local_addr" | cut -d':' -f2 | cut -d':' -f1) remote_ip=$(echo"$remote_addr" | cut -d':' -f1) # 排除本地回环和标准端口 if [[ ! "$remote_ip" =~ ^(127\.|::1) ]]; then # 检查本地端口是否为高端口(非标准服务) if [ "$local_port" -ge 50000 ] 2>/dev/null; then # 排除部分合法的高端口号 if [[ ! "$local_port" =~ ^(50000|50001|50002) ]]; then echo"⚠️ 可疑连接:远程 $remote_addr -> 本地端口 $local_port" reverse_shell_detected="true" fi fi fi done if [ "$reverse_shell_detected" = "false" ]; then echo"✅ 未发现反向shell特征" fi |
2. 监听端口分析
| |
| — |
| echo"### 监听端口分析" # 获取所有监听端口 ifcommand -v ss >/dev/null 2>&1; then listening=$(ss -tulpn 2>/dev/null) else listening=$(netstat -tulpn 2>/dev/null) fi echo"| 端口 | 协议 | 进程 | 用户 |" echo"|------|------|------|------|" echo"$listening" | grep LISTEN | whileread -r line; do port=$(echo"$line" | awk '{print $5}' | rev | cut -d':' -f1 | rev) protocol=$(echo"$line" | awk '{print $1}') process=$(echo"$line" | awk '{print $7}' | cut -d'/' -f2 | cut -d',' -f1) user=$(echo"$line" | awk '{print $7}' | cut -d'"' -f2) # 标记非标准高端口 if [ "$port" -ge 10000 ]; then echo"| **$port** | $protocol | $process | $user |" else echo"| $port | $protocol | $process | $user |" fi done |
3. 外部连接统计
| |
| — |
| # 统计外部连接的独立IP数量 external_ips=$(ss -tn 2>/dev/null | \ awk '{print $5}' | \ cut -d':' -f1 | \ grep -vE '^(127\.|::1|0\.0\.0\.0)' | \ sort -u | \ wc -l) echo"### 外部连接统计" echo"- 外部连接的独立IP数:$external_ips" # 列出Top 10外部IP echo"- 连接最多的外部IP:" ss -tn 2>/dev/null | \ awk '{print $5}' | \ cut -d':' -f1 | \ grep -vE '^(127\.|::1|0\.0\.0\.0)' | \ sort | uniq -c | sort -rn | head -n 10 | \ whileread -r line; do count=$(echo"$line" | awk '{print $1}') ip=$(echo"$line" | awk '{print $2}') echo" - $ip: $count 次连接" done |
关键点:
- 反向shell检测基于行为特征:外部IP连接本地高端口
- 排除已知的合法高端口(如某些应用服务)
- 统计外部连接IP数量和连接频率,异常高值需要关注
- 显示监听端口对应的进程和用户,便于排查
3.2.3 文件系统安全检查
检查目的:发现最近修改的敏感文件、勒索病毒特征、SUID/SGID文件
1. 关键目录变更检测
| |
| — |
| echo"### 关键目录最近变更(7天内)" # 定义需要监控的关键目录 critical_dirs=("/etc""/home""/root""/var/www""/opt") for dir in"${critical_dirs[@]}"; do if [ -d "$dir" ]; then # 查找7天内修改的文件 recent_files=$(find "$dir" -type f -mtime -7 2>/dev/null) if [ -n "$recent_files" ]; then file_count=$(echo"$recent_files" | grep -v '^$' | wc -l) echo"⚠️ $dir: $file_count 个文件在最近7天被修改" # 显示部分关键文件 echo"$recent_files" | head -n 5 | whileread -r file; do perms=$(stat -c "%a""$file" 2>/dev/null) echo" - $file (权限:$perms)" done fi fi done |
2. 勒索病毒特征检测
| |
| — |
| echo"### 勒索病毒特征检测" # 定义勒索病毒常用的文件扩展名 ransomware_patterns=( "*.encrypted" "*.locked" "*.crypto" "*.crypt" "*.crypted" "*_README.txt" "*_DECRYPT.txt" "*_HELP.txt" "*_RESTORE.txt" "how_to_decrypt.*" "recover_files.*" ) ransomware_found="false" for pattern in"${ransomware_patterns[@]}"; do # 在用户目录中查找 found_files=$(find /home /root -name "$pattern" 2>/dev/null) if [ -n "$found_files" ]; then echo"❌ 发现勒索病毒特征文件:" echo"$found_files" | head -n 10 ransomware_found="true" fi done if [ "$ransomware_found" = "false" ]; then echo"✅ 未发现勒索病毒特征" fi |
3. SUID/SGID文件检查
| |
| — |
| echo"### SUID/SGID文件检查" # 查找所有SUID文件 suid_files=$(find / -type f -perm -4000 2>/dev/null | \ grep -v -E '^/proc|^/sys|^/dev' | \ head -n 30) suid_count=$(echo"$suid_files" | grep -v '^$' | wc -l) if [ "$suid_count" -gt 0 ]; then echo"发现 $suid_count 个SUID文件(部分列表):" echo"$suid_files" | whileread -r file; do perms=$(stat -c "%a""$file" 2>/dev/null) owner=$(stat -c "%U""$file" 2>/dev/null) echo" - $file (权限:$perms, 所有者:$owner)" done fi # 查找所有SGID文件 sgid_files=$(find / -type f -perm -2000 2>/dev/null | \ grep -v -E '^/proc|^/sys|^/dev' | \ head -n 20) sgid_count=$(echo"$sgid_files" | grep -v '^$' | wc -l) if [ "$sgid_count" -gt 0 ]; then echo"发现 $sgid_count 个SGID文件(部分列表):" echo"$sgid_files" | whileread -r file; do perms=$(stat -c "%a""$file" 2>/dev/null) owner=$(stat -c "%U""$file" 2>/dev/null) echo" - $file (权限:$perms, 所有者:$owner)" done fi |
关键点:
- 重点监控/etc、/home、/root等敏感目录
- 勒索病毒检测基于文件扩展名特征(实际环境中建议结合文件内容分析)
- SUID/SGID文件是提权漏洞的常见切入点,需要重点关注
- 限制输出数量,避免报告过长
3.2.4 账户和登录安全检查
检查目的:检测异常登录、新增用户、sudo使用情况
1. 最近登录记录
| |
| — |
| echo"### 最近登录记录(最近10次)" # 使用last命令获取登录记录 recent_logins=$(last -n 10 -a 2>/dev/null | head -n -2) if [ -n "$recent_logins" ]; then echo"| 用户 | 终端 | 来源IP | 登录时间 |" echo"|------|------|--------|----------|" echo"$recent_logins" | whileread -r line; do user=$(echo"$line" | awk '{print $1}') terminal=$(echo"$line" | awk '{print $2}') # IP在最后,主机名倒数第二 ip=$(echo"$line" | awk '{print $(NF-1)}' | sed 's/(//g') # 时间范围在中间部分 time_range=$(echo"$line" | awk '{for(i=3;i<=NF-2;i++)printf $i" "}') echo"| $user | $terminal | $ip | $time_range |" done fi |
2. 失败登录统计
| |
| — |
| echo"### 失败登录统计" # 统计最近失败的登录次数 if [ -f /var/log/auth.log ]; then # Debian/Ubuntu系统 failed_count=$(grep "Failed password" /var/log/auth.log 2>/dev/null | \ tail -1000 | wc -l) echo"- 最近失败登录次数(最近1000条日志):$failed_count" # 统计失败登录来源IP echo"- 失败登录最多的IP:" grep "Failed password" /var/log/auth.log 2>/dev/null | \ awk '{print $13}' | \ sort | uniq -c | sort -rn | head -n 5 | \ whileread -r line; do count=$(echo"$line" | awk '{print $1}') ip=$(echo"$line" | awk '{print $2}') echo" - $ip: $count 次" done elif [ -f /var/log/secure ]; then # CentOS/RHEL系统 failed_count=$(grep "Failed password" /var/log/secure 2>/dev/null | \ tail -1000 | wc -l) echo"- 最近失败登录次数(最近1000条日志):$failed_count" fi |
3. 新增用户检测
| |
| — |
| echo"### 新增用户检测(最近30天)" # 检查shadow文件中最近修改的用户 if [ -f /etc/shadow ]; then # 第4字段是最后修改时间(天数,从1970-01-01起) thirty_days_ago=$(($(date +%s) / 86400 - 30)) new_users=$(awk -F: -v date="$thirty_days_ago" \ '$4 >= date {print $1}' /etc/shadow 2>/dev/null) if [ -n "$new_users" ]; then echo"⚠️ 发现最近30天新增的用户:" echo"$new_users" | whileread -r user; do # 获取用户详细信息 user_info=$(grep "^$user:" /etc/passwd) uid=$(echo"$user_info" | cut -d':' -f3) home=$(echo"$user_info" | cut -d':' -f6) shell=$(echo"$user_info" | cut -d':' -f7) echo" - $user (UID:$uid, HOME:$home, SHELL:$shell)" done else echo"✅ 未发现最近30天的新增用户" fi fi |
4. Sudo使用审计
| |
| — |
| echo"### Sudo使用审计(最近20条)" # 检查sudo日志 ifcommand -v journalctl >/dev/null 2>&1; then # 使用journalctl读取sudo日志 sudo_logs=$(journalctl -u sudo 2>/dev/null | tail -n 20) if [ -n "$sudo_logs" ]; then echo"$sudo_logs" | whileread -r line; do # 提取关键信息:时间、用户、命令 echo" - $line" done fi elif [ -f /var/log/auth.log ]; then # 从auth.log中提取sudo记录 sudo_logs=$(grep sudo /var/log/auth.log 2>/dev/null | tail -n 20) if [ -n "$sudo_logs" ]; then echo"$sudo_logs" fi fi |
关键点:
- 兼容不同Linux发行版的日志文件路径
- 统计失败登录次数和来源IP,高值可能意味着暴力破解
- 检测新增用户,特别是UID为0(root权限)的用户
- 审计sudo使用情况,发现权限滥用
3.2.5 系统完整性检查
检查目的:检查关键文件权限、系统二进制文件完整性
| |
| — |
| echo"### 系统完整性检查" # 定义关键文件列表 critical_files=( "/etc/passwd" "/etc/shadow" "/etc/sudoers" "/etc/ssh/sshd_config" "/etc/ssh/ssh_host_*_key" ) echo"| 文件 | 权限 | 所有者 | 组 | 状态 |" echo"|------|------|--------|-----|------|" for file in"${critical_files[@]}"; do # 使用通配符展开 for expanded_file in$file; do if [ -e "$expanded_file" ]; then perms=$(stat -c "%a""$expanded_file" 2>/dev/null || stat -f "%OLp""$expanded_file" 2>/dev/null) owner=$(stat -c "%U""$expanded_file" 2>/dev/null || stat -f "%Su""$expanded_file" 2>/dev/null) group=$(stat -c "%G""$expanded_file" 2>/dev/null || stat -f "%Sg""$expanded_file" 2>/dev/null) # 检查权限是否合适(简化判断) status="✅" case"$(basename "$expanded_file")"in shadow) if [ "$perms" != "000" ] && [ "$perms" != "640" ]; then status="⚠️" fi ;; sudoers) if [ "$perms" != "440" ] && [ "$perms" != "400" ]; then status="⚠️" fi ;; esac echo"| $expanded_file | $perms | $owner | $group | $status |" fi done done |
关键点:
- 重点检查/etc/passwd、/etc/shadow等认证相关文件
- /etc/shadow应该是000或640权限
- /etc/sudoers应该是440或400权限
- SSH私钥文件应该是600或400权限
3.3 Docker容器监控模块(docker-check.sh)
专注于Docker环境的健康检查和资源监控。
3.3.1 Docker服务状态检查
检查目的:确认Docker服务运行正常,获取版本信息
| |
| — |
| echo"## 🐳 Docker服务状态" # 检查Docker服务是否运行 ifcommand -v docker >/dev/null 2>&1; then docker_status=$(systemctl is-active docker 2>/dev/null) if [ "$docker_status" = "active" ]; then echo"Docker服务: ✅ 运行中" # 获取Docker版本 docker_version=$(docker --version 2>/dev/null | awk '{print $3}' | sed 's/,//') echo"Docker版本: $docker_version" add_docker_data "service_status""running" add_docker_data "version""$docker_version" else echo"Docker服务: ⚠️ 未运行 (状态: $docker_status)" add_docker_data "service_status""$docker_status" fi else echo"Docker: ❌ 未安装" add_docker_data "service_status""not_installed" return fi |
3.3.2 容器统计与状态
检查目的:了解容器总数、运行状态、停止状态
| |
| — |
| echo"## 📦 容器状态概览" # 统计容器数量 total_containers=$(docker ps -a -q 2>/dev/null | wc -l) running_containers=$(docker ps -q 2>/dev/null | wc -l) paused_containers=$(docker ps -q -f status=paused 2>/dev/null | wc -l) stopped_containers=$((total_containers - running_containers - paused_containers)) echo"- 总容器数: $total_containers" echo"- 运行中: $running_containers" echo"- 已暂停: $paused_containers" echo"- 已停止: $stopped_containers" # 判断整体状态 if [ "$stopped_containers" -gt 0 ]; then echo"- 状态: ⚠️ 有 $stopped_containers 个容器已停止" overall_status="warning" elif [ "$running_containers" -gt 0 ]; then echo"- 状态: ✅ 正常" overall_status="ok" else echo"- 状态: ⚠️ 无运行中的容器" overall_status="warning" fi # 记录到JSON add_docker_data "containers_total""$total_containers" add_docker_data "containers_running""$running_containers" add_docker_data "containers_paused""$paused_containers" add_docker_data "containers_stopped""$stopped_containers" add_docker_data "overall_status""$overall_status" # 列出停止的容器 if [ "$stopped_containers" -gt 0 ]; then echo"" echo"### 停止的容器:" docker ps -a -f status=exited --format "table {{.Names}}\t{{.Status}}\t{{.CreatedAt}}" 2>/dev/null fi |
输出示例:
| |
| — |
| ## 📦 容器状态概览 - 总容器数: 25 - 运行中: 23 - 已暂停: 0 - 已停止: 2 - 状态: ⚠️ 有 2 个容器已停止 ### 停止的容器: NAMES STATUS CREATEDAT old-postgres Exited (0) 2 days ago 2026-01-16 10:30:00 test-mysql Exited (1) 5 days ago 2026-01-13 14:20:00 |
3.3.3 容器资源使用分析
检查目的:发现资源占用异常的容器,进行容量规划
| |
| — |
| echo"## 📊 容器资源使用(Top 10)" echo"| 容器名 | 状态 | CPU% | 内存使用 | 内存% | 网络接收 | 网络发送 |" echo"|--------|------|------|----------|--------|----------|----------|" # 获取容器实时资源使用(--no-stream避免持续输出) docker stats --no-stream --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.MemPerc}}\t{{.NetIO}}" 2>/dev/null | \ tail -n +2 | \ whileread -r line; do name=$(echo"$line" | awk '{print $1}') cpu=$(echo"$line" | awk '{print $2}' | sed 's/%//') mem_usage=$(echo"$line" | awk '{print $3}') mem_percent=$(echo"$line" | awk '{print $4}' | sed 's/%//') net_rx=$(echo"$line" | awk '{print $5}') net_tx=$(echo"$line" | awk '{print $6}') # 判断容器状态 if docker ps --format "{{.Names}}" | grep -q "^${name}$"; then status="✅" else status="❌" fi # 标记高资源占用 if (( $(echo"$cpu > 50" | bc -l 2>/dev/null || echo"0") )); then cpu="**$cpu%**" else cpu="${cpu}%" fi if [ "$mem_percent" -gt 80 ] 2>/dev/null; then mem_usage="**$mem_usage**" fi echo"| $name | $status | $cpu | $mem_usage | ${mem_percent}% | $net_rx | $net_tx |" done | head -n 11 # 限制Top 10 |
关键点:
- 使用
--no-stream参数获取当前瞬时数据,而非持续输出 - 标记CPU>50%和内存>80%的容器,便于快速发现问题
- 区分运行中和停止的容器
- 限制输出数量,避免报告过长
3.3.4 镜像管理检查
检查目的:发现悬空镜像,提供清理建议
| |
| — |
| echo"## 🖼️ 镜像管理" # 统计镜像数量 total_images=$(docker images -q 2>/dev/null | wc -l) dangling_images=$(docker images -f "dangling=true" -q 2>/dev/null | wc -l) echo"- 总镜像数: $total_images" echo"- 悬空镜像数: $dangling_images" # 列出镜像占用空间 if [ "$total_images" -gt 0 ]; then echo"" echo"### 镜像占用空间(Top 10):" echo"| 镜像名 | 标签 | 大小 | 创建时间 |" echo"|--------|------|------|----------|" docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}\t{{.CreatedAt}}" 2>/dev/null | \ tail -n +2 | \ head -n 10 | \ whileread -r line; do echo"| $line |" done fi # 清理建议 if [ "$dangling_images" -gt 0 ]; then echo"" echo"### 清理建议" echo"⚠️ 发现 $dangling_images 个悬空镜像,建议清理:" echo"\`\`\`bash" echo"docker image prune -f" echo"\`\`\`" # 计算可回收空间 dangling_size=$(docker images -f "dangling=true" -q 2>/dev/null | \ xargs docker inspect --format='{{.Size}}' 2>/dev/null | \ awk '{sum+=$1} END {printf "%.0f", sum/1024/1024}') echo"预计可回收空间: ${dangling_size}MB" fi |
3.3.5 存储空间使用
检查目的:了解Docker整体存储占用,发现异常占用
| |
| — |
| echo"## 💾 存储空间使用" docker_info=$(docker system df 2>/dev/null) if [ -n "$docker_info" ]; then echo"$docker_info" # 解析存储使用数据 images_size=$(echo"$docker_info" | grep 'Images' | awk '{print $3}') containers_size=$(echo"$docker_info" | grep 'Containers' | awk '{print $3}') volumes_size=$(echo"$docker_info" | grep 'Local Volumes' | awk '{print $3}') build_cache_size=$(echo"$docker_info" | grep 'Build Cache' | awk '{print $3}') add_docker_data "storage_images""$images_size" add_docker_data "storage_containers""$containers_size" add_docker_data "storage_volumes""$volumes_size" add_docker_data "storage_build_cache""$build_cache_size" # 判断是否需要清理 if [ "$build_cache_size" != "0B" ] && [ "$build_cache_size" != "" ]; then echo"" echo"### 清理建议" echo"⚠️ 构建缓存占用 ${build_cache_size},建议清理:" echo"\`\`\`bash" echo"docker builder prune -f" echo"\`\`\`" fi else echo"⚠️ 无法获取存储使用信息" fi |
输出示例:
| |
| — |
| ## 💾 存储空间使用 TYPE TOTAL ACTIVE SIZE RECLAIMABLE Images 15 10 3.2GB 1.1GB (34%) Containers 25 23 1.8GB 256MB (14%) Local Volumes 8 6 2.5GB 512MB (20%) Build Cache 0 0 856MB 856MB ### 清理建议 ⚠️ 构建缓存占用 856MB,建议清理:bash docker builder prune -f “` |
| |
| — |
| #### 3.3.6 网络和卷统计bash echo “## 🔌 网络和卷” # 统计网络 totalnetworks=$(docker network ls -q 2>/dev/null | wc -l) echo “- 网络总数: $totalnetworks” # 列出网络 if [ “$totalnetworks” -gt 0 ]; then echo “” echo “### 网络列表:” docker network ls –format “table {{.Name}}\t{{.Driver}}\t{{.Scope}}” 2>/dev/null fi # 统计卷 totalvolumes=$(docker volume ls -q 2>/dev/null | wc -l) echo “” echo “- 卷总数: $totalvolumes” # 列出卷 if [ “$totalvolumes” -gt 0 ]; then echo “” echo “### 卷列表:” docker volume ls –format “table {{.Name}}\t{{.Driver}}\t{{.Scope}}” 2>/dev/null fi adddockerdata “networkstotal” “$totalnetworks” adddockerdata “volumestotal” “$totalvolumes” “` |
关键点:
- 提供清晰的清理建议和命令
- 统计并显示可回收空间,帮助决策是否清理
- 列出网络和卷,便于了解整体架构
- 所有数据同时记录到JSON,便于自动化分析
四、实际应用效果展示
4.1 基础健康检查报告
Markdown报告(人工阅读)
图:健康检查报告
JSON报告(机器处理)
| |
| — |
| { "summary": { "host": { "hostname": "pve-ubuntu-pandawiki", "ip": "192.168.0.55", "check_time": "2026-01-18T08:40:43+0000" }, "overall_status": "warning", "status_counts": { "ok": 8, "warning": 3, "critical": 0 }, "check_types": ["health"] }, "details": { "system": { "uptime": "15 days, 3:24", "load_1min": 0.15, "load_5min": 0.30, "load_15min": 0.35, "network_total_connections": 45, "network_external_connections": 8, "network_listening_ports": 12 }, "memory": { "total_mb": 16384, "used_mb": 12500, "available_mb": 3884, "used_percent": 76.3, "swap_total_mb": 2048, "swap_used_mb": 256, "swap_percent": 12.5, "status": "warning" }, "disk": [ { "mount": "/", "device": "/dev/sda1", "total_gb": "100G", "used_gb": "45G", "available_gb": "55G", "used_percent": 45.0, "status": "ok" }, { "mount": "/data", "device": "/dev/sdb1", "total_gb": "500G", "used_gb": "425G", "available_gb": "75G", "used_percent": 85.0, "status": "warning" } ], "services": { "systemd_running": 23, "systemd_failed": 0 }, "security": { "mining_detected": false, "tmp_executables": 0, "failed_logins": 3 } }, "metadata": { "check_version": "1.0", "tool_version": "ops-health-check v1.0", "check_script": "health-check.sh", "thresholds": { "disk_warning": 50, "disk_critical": 80, "memory_warning": 70, "memory_critical": 90 } } } |
实际价值:
- Markdown报告便于运维人员快速了解系统状态
- JSON数据可被监控系统自动采集和分析
- 清晰的emoji状态指示,一眼就能看出问题所在
- 详细的阈值配置,便于追溯和调整
五、总结与展望
5.1 实现成果
本次开发成功构建了一个生产级运维健康检查系统:
✅ 三大核心模块
- 基础健康检查:涵盖系统资源、服务状态、基础安全
- 深度安全检查:5大类20+项安全检查
- Docker监控:容器、镜像、存储全方位监控
✅ 双格式输出
- Markdown:人工可读,便于快速决策
- JSON:机器可处理,易于自动化集成
✅ 广泛兼容性
- bash 3.2+兼容(macOS默认版本)
- 支持主流Linux发行版(Ubuntu、CentOS、Debian)
- 适配systemd和SysV init系统
✅ 完整文档
- SKILL.md:使用指南
- 设计文档:架构和实现思路
- 博客文章:实战经验分享
5.2 技术亮点
- 模块化设计:三个检查模块独立运行,互不依赖
- 统一输出库:封装数据收集和格式化逻辑
- 阈值可配置:支持通过环境变量自定义阈值
- 兼容性处理:优雅降级,兼容不同版本工具
- 清理建议:不仅发现问题,还提供解决建议
5.3 实际应用价值
效率提升:
- 批量检查10台主机仅需2分钟
- 自动生成双格式报告,无需手工整理
- JSON数据可直接导入监控系统
安全增强:
- 发现并阻止挖矿程序
- 检测异常登录和未授权访问
- 及时发现文件系统异常变更
成本节约:
- 无需部署复杂监控系统
- 基于现有SSH连接,无需额外代理
- 轻量级脚本,资源占用极低
5.4 开发体会
通过Claude Code的AI辅助开发,整个过程非常高效:
- 快速迭代:从需求到实现不到4小时
- 智能提示:Claude主动发现兼容性问题并给出解决方案
- 代码质量:生成的代码结构清晰,符合最佳实践
- 文档完善:自动生成详细的使用文档和示例
AI辅助开发不仅提高了效率,更重要的是让开发者可以专注于业务逻辑和架构设计,而将具体的编码工作交给AI完成。这种人机协作模式,是未来软件开发的重要趋势。
项目地址:https://github.com/xiejava/ops-health-check
博客地址:http://xiejava.ishareread.com
🤖 本文由Claude Code辅助编写
“fullbug”微信公众号
关注:微信公众号,一起学习成长!
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:fullbug xiejava xiejava《让Claude Code写了个运维健康检查的Skill还挺好用的》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。










评论