一、功能概述

本脚本用于监控 Proxmox VE 中带有特定标签的虚拟机,实现以下核心功能:

  • 自动筛选:通过标签 checkstatus 定位需监控的虚拟机
  • IP连通性检测:解析 ip-xxx.xxx.xxx.xxx 格式的标签进行网络检查
  • 智能重启:对网络不可达且运行中的虚拟机执行安全重启
  • 分级日志:关键操作写入系统日志,常规信息记录本地文件

二、脚本代码

#!/bin/bash
# set -eo pipefail

# 自动获取并验证节点名称
NODE_NAME=$(hostname -s)
if [[ ! $NODE_NAME =~ ^[a-zA-Z0-9_-]+$ ]] || ! pvesh get /nodes/$NODE_NAME/status &>/dev/null; then
  log "info" "无法获取有效节点名称,当前值: $NODE_NAME"
  exit 1
fi

### 全局配置 ###
CHECK_TAG="checkstatus"                # 监控标签
IP_TAG_PREFIX="ip-"                    # IP标签前缀
LOG_IDENT="pve-monitor-check-status"   # 系统日志标识
SCRIPT_DIR=$(dirname "$(readlink -f "$0")")
LOG_FILE="${SCRIPT_DIR}/vm_monitor_check_status_$(date +%Y%m%d).log"

### 分级日志函数 ###
log() {
  local level="$1"
  local message="$2"
  local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
  local log_entry="[$timestamp] [${level^^}] $message"

  # 所有日志写入本地文件
  echo "$log_entry" | tee -a "$LOG_FILE"

  # 仅CRITICAL级别写入系统日志
  [[ "$level" == "critical" ]] && logger -t "$LOG_IDENT" "$log_entry"
}

### IP地址验证 ###
validate_ip() {
  local ip=$1
  [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]] || return 1
  
  IFS='.' read -ra octets <<< "$ip"
  for octet in "${octets[@]}"; do
    [[ $octet -lt 0 || $octet -gt 255 ]] && return 1
  done
  return 0
}

### 获取监控目标 ###
get_target_vms() {
  pvesh get "/nodes/$NODE_NAME/qemu" --output-format json |
    jq -r --arg tag "$CHECK_TAG" '
      .[] | 
      select(.tags? // "" | split(";") | index($tag)) |
      .vmid
    '
}

### 主监控流程 ###
main() {
  log "info" "===== 虚拟机监控任务启动 ====="

  # 获取目标虚拟机列表
  mapfile -t target_vms < <(get_target_vms)
  [[ ${#target_vms[@]} -eq 0 ]] && {
    log "info" "未找到带 $CHECK_TAG 标签的虚拟机"
    return 0
  }
  # 遍历处理虚拟机
  for vmid in "${target_vms[@]}"; do
    log "info" "正在检查 VM 【$vmid】 ..."
    
    # 获取虚拟机状态
    local vm_status
    vm_status=$(pvesh get "/nodes/$NODE_NAME/qemu/$vmid/status/current" --output-format json | jq -r '.status')
    
    # 提取有效IP标签
    local tags ips=()
    tags=$(pvesh get "/nodes/$NODE_NAME/qemu/$vmid/config" --output-format json | jq -r '.tags? // ""')
    while IFS= read -r tag; do
      [[ $tag == "${IP_TAG_PREFIX}"* ]] && {
        local potential_ip=${tag#"$IP_TAG_PREFIX"}
        validate_ip "$potential_ip" && ips+=("$potential_ip")
      }
    done < <(tr ';' '\n' <<< "$tags")

    # IP检测逻辑
    if [[ ${#ips[@]} -eq 0 ]]; then
      log "info" "VM 【$vmid】 未配置有效IP标签"
      continue
    fi

    # 运行状态检测
    if [[ $vm_status != "running" ]]; then
      log "info" "VM 【$vmid】 当前未运行(状态: $vm_status)"
      continue
    fi

    # 网络连通性检测
    local all_unreachable=true
    for ip in "${ips[@]}"; do
      if ping -c 3 -W 2 -i 0.2 "$ip" &>/dev/null; then
        log "info" "VM 【$vmid】 IP $ip 连通性检测正常"
        all_unreachable=false
        break
      fi
    done

    # 重启判定与执行
    if $all_unreachable; then
      log "critical" "VM 【$vmid】 所有IP检测失败,触发重启流程"
      
      # 安全关闭流程
      if timeout 120 qm shutdown "$vmid"; then
        log "critical" "VM 【$vmid】 已正常关闭"
      else
        log "critical" "VM 【$vmid】 执行强制关闭"
        qm stop "$vmid" --forceStop 1
      fi

      # 重启操作
      qm start "$vmid"
      sleep 10
      local new_status
      new_status=$(pvesh get "/nodes/$NODE_NAME/qemu/$vmid/status/current" --output-format json | jq -r '.status')
      log "critical" "VM 【$vmid】 重启完成,当前状态: $new_status"
    fi
  done

  log "info" "===== 虚拟机监控任务完成 ====="
}

### 执行入口 ###
main

三、部署指南

1. 环境准备

# 安装依赖
apt update && apt install -y jq

# 创建脚本目录
mkdir -p /root/tools/pve-monitor-check-status && cd /root/tools/pve-monitor-check-status

2. 配置调整

# 修改以下参数适应实际环境
vim pve-monitor-check-status.sh
NODE_NAME="Your_Node_Name"         # 修改为实际PVE节点名
CHECK_TAG="your_monitor_tag"       # 调整监控标签名称
IP_TAG_PREFIX="your_ip_prefix"     # 自定义IP标签前缀

3. 权限设置

chmod +x pve-monitor-check-status.sh

4. 定时任务配置

# 每5分钟执行监控
echo "*/5 * * * * root /root/tools/pve-monitor-check-status/pve-monitor-check-status.sh" > /etc/cron.d/pve-monitor-check-status

四、日志管理

1. 日志路径

日志类型存储位置
本地运行日志/root/tools/pve-monitor-check-status/vm_monitor_check_status_YYYYMMDD.log
系统操作日志/var/log/syslog

2. 日志示例

# 本地日志
[2023-08-21 14:35:02] [INFO] VM 101 IP 10.10.10.10 连通性检测正常

# 系统日志
Aug 21 14:35:05 pve-node pve-monitor-check-status: [2023-08-21 14:35:05] [CRITICAL] VM 102 所有IP检测失败,触发重启流程

3. 日志查看命令

# 实时监控本地日志
tail -f /root/tools/pve-monitor-check-status/vm_monitor_check_status_*.log

# 过滤关键系统日志
journalctl -t pve-monitor-check-status -S "10 min ago"

五、注意事项

1.权限要求

  • 需要使用 root 或具有 PVE管理员权限 的用户执行
  • 确保对 /etc/pve 目录有读取权限

2.标签规范

# 正确格式示例(分号分隔)
pvesh set /nodes/$NODE/qemu/101/config --tags "checkstatus;ip-192.168.1.100"

# 错误格式示例
pvesh set ... --tags "checkstatus,ip-192.168.1.100"  # 逗号分隔无效

3.测试建议

# 试运行模式(不执行实际操作)
DRY_RUN=1 ./pve-monitor-check-status.sh

# 指定测试单个虚拟机
TARGET_VMID=101 ./pve-monitor-check-status.sh

4.网络要求

  • 宿主机需能访问所有配置的检测IP
  • 建议配置至少2个检测IP(管理IP + 业务IP)

5.NODE_NAME

单节点环境

主机名: pve01
自动获取: NODE_NAME=pve01

集群环境

节点1主机名: pve-cluster-01
自动获取: NODE_NAME=pve-cluster-01

自定义主机名

已配置: hostnamectl set-hostname my-pve
自动获取: NODE_NAME=my-pve

注意事项

如果节点名称包含特殊字符(如空格),需要先规范化主机名:

sudo hostnamectl set-hostname "new-node-name"
  • 在Proxmox集群中,节点名称必须:

    • 在集群内唯一
    • 符合DNS域名标准(字母开头,包含字母数字和减号)

当需要手动覆盖时,可以通过环境变量传递:

NODE_NAME=custom-name ./pve-monitor-check-status.sh

六、故障排查

现象可能原因解决方案
无法获取虚拟机列表PVE节点名称错误检查 NODE_NAME 配置
IP检测误判防火墙阻止ICMP添加防火墙放行规则
强制关机失败QEMU进程卡死手动执行 kill -9 <qemu_pid>
定时任务未执行cron服务未运行重启服务 systemctl restart cron

点击下载完整脚本 | 查看更新日志

最后修改:2025 年 03 月 19 日
如果觉得我的文章对你有用,请随意赞赏