PVE 虚拟机心跳检测并重启

折腾PVE,安装了ikuai+iStoreOS+黑裙,其中DMS安装了小雅alist超集,可能是小主机性能太差导致黑裙多次崩溃,后来就想着有没有什么办法监控VM的运行情况,经过搜索一番后有两种方案看门狗(watchdog)和脚本监控,其中看门狗(watchdog)要求硬件支持就没搞,参考文章后优化了下脚本实现

参考文章:PVE 虚拟机心跳检测并重启 - Lucien's Blog

问题1:save保存后,faile.txt文件的count数就是没有叠加

解决过程:定位问题后发现,是source的问题导致,使用 source. 命令执行文件时,source 的行为是在当前 shell 环境中执行命令,所以全局声明在这个情景下是不必要的,因为 source 执行后,变量已经是当前环境的一部分了。

解决方案:将 -A 替换为 -gA,可以直接使用 sed

完整代码

#!/bin/bash

# 脚本常量定义
QMPATH="/usr/sbin/qm"
MAX_FAILURES=3
RESET_AFTER_SUCCESS=2
FAILURE_FILE="/path/to/failure_file.txt"

# 关联数组,用于保存各虚拟机的失败次数
declare -gA failure_count

# 从文件中加载失败次数
load_failure_count() {
    if [[ -f "$FAILURE_FILE" ]]; then
        source "$FAILURE_FILE"
        echo "Loaded failure count from $FAILURE_FILE"
    else
        echo "$FAILURE_FILE does not exist, no saved failure counts to load."
    fi
}

# 将失败次数保存至文件
save_failure_count() {
    if declare -p failure_count &>/dev/null; then
        declare -p failure_count | sed 's/declare -A/declare -gA/' > "$FAILURE_FILE"
    else
        echo "Error: failure_count is not declared as an associative array." >&2
    fi
}

# 日志记录函数
log_event() {
    local message="$1"
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $message" >> /root/soft_shell/event.log
}

# 重启虚拟机函数
restart_vm() {
    local vm_id="$1"
    log_event "[重启] 由于连续失败,正在重启虚拟机ID $vm_id。"
    if "$QMPATH" restart "$vm_id"; then
        log_event "成功重启虚拟机ID $vm_id。"
    else
        log_event "重启虚拟机ID $vm_id 失败。"
    fi
}

# 处理虚拟机ping不通的情况
handle_failure() {
    local vm_id="$1"
    ((failure_count["$vm_id"]++))

    if [[ ${failure_count["$vm_id"]} -ge $MAX_FAILURES ]]; then
        restart_vm "$vm_id"
        failure_count["$vm_id"]=0
    fi
    save_failure_count  # 立即保存失败次数
}

# 处理虚拟机ping通的情况
handle_success() {
    local vm_id="$1"
    if [[ ${failure_count["$vm_id"]} -gt 0 ]]; then
        failure_count["$vm_id"]=0  # 成功后立即重置失败次数
    fi
    save_failure_count  # 立即保存失败次数
}

# 检查虚拟机是否可达,并根据结果处理
check_vm_status() {
    local vm_id="$1"
    local vm_ip="$2"

    if ! ping -c 1 "$vm_ip" &>/dev/null; then
        log_event "[失败] 虚拟机ID $vm_id (IP $vm_ip) 没有响应ping。"
        handle_failure "$vm_id"
    else
        log_event "[成功] 虚拟机ID $vm_id (IP $vm_ip) 响应了ping。"
        handle_success "$vm_id"
    fi
}

# 遍历所有虚拟机并检查它们的状态
check_all_vms() {
    local vm_list="$1"

    for vm_info in $vm_list; do
        local vm_id vm_ip
        vm_id=$(echo "$vm_info" | cut -d: -f1)
        vm_ip=$(echo "$vm_info" | cut -d: -f2)
        check_vm_status "$vm_id" "$vm_ip"
    done
}

# 脚本的主函数
main() {
    local vm_list="VM-ID:IP"

    load_failure_count
    check_all_vms "$vm_list"
    # save_failure_count 移动到 handle_failure 和 handle_success
}

# 执行脚本的主函数
main

linux设置定时任务

crontab -e,编辑定时任务

*/1 * * * * bash /root/check_and_restart/check_and_restart.sh >> /root/check_and_restart/log.txt

效果图

你可能感兴趣的:(实用工具,linux,PVE)