一、功能概述
本脚本用于监控 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 |