
接上回。试想一下,当你美滋滋地玩着游戏,突然给你来一个“你已断开连接”,是不是很恼火?

为什么会这样?
经过简单的排查,可以发现是由于Proxmox 节能面板导致的。

PVE 节能面板 的设计初衷是 降低电费成本 ——当没有玩家在线时,让游戏服务器所在的 VM 自动进入休眠,从而减少资源消耗。(此部分功能已经通过N8N实现。)
但这带来了一个新的问题:VM/CT 在休眠后重新启动时,虚拟机内部的系统时间不会立即与真实时间同步。
虽然此时玩家仍然可以正常连接到游戏服务端,但当虚拟机的时间同步服务稍后自动矫正时间时,服务器会检测到 “客户端时间与服务器时间不一致”,并因此强制中断所有会话,要求重新连接。
对于玩家来说,体验就变成了—— “你已断开连接”。
目录
今天的主角登场: QEMU Guest Agent。
什么是Qemu Guest Agent
我不得不佩服设计QGA的人,这简直是一个天才的设计!用职场黑话来说就是:
- 全面打通宿主机与虚拟机的协同链路,实现双端通信颗粒度高维对齐;
- 针对虚拟机在不同状态下的各类“痛点”提前处理,让系统运行更加稳定可控;
- 强化虚拟机的“肖像”数据,让状态更透明,最终实现从监控到运维的完整“闭环”。
说人话就是:
qemu-guest-agent 是一个辅助守护进程,安装在虚拟机中。它用于在主机和虚拟机之间交换信息,并在虚拟机中执行命令。
那么我的需求就是:当虚拟机从睡眠中恢复的时候,我们需要通过QGA更新虚拟机的时间。
安装和配置Qemu Guest Agent
我将以Windows系统为例进行安装介绍。
🟦1.下载VirtIO 驱动包
进入官网下载ISO包: https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/latest-virtio/
下载文件(例如):
virtio-win-0.1.xx.iso
并把 ISO 挂载到你的 Windows 虚拟机。
🟦2.安装QEMU Guest Agent
在 Windows 虚拟机内打开挂载好的 VirtIO ISO
进入目录:
guest-agent
找到:
qemu-guest-agent-x64.msi (64 位)
双击安装,按默认步骤即可。
安装完成后,Windows 会自动增加一个服务。
🟦3.启动并配置服务
打开 Windows 服务管理器:
Win + R → 输入 services.msc → 回车
找到 QEMU Guest Agent:
✔ 设置为自动启动
双击该服务
“启动类型” → 选择 Automatic(自动)
点击 Start(启动)
🟦4.在PVE中启用QGA
在 PVE(Proxmox)中,选中虚拟机:
- 点击 Options
- 找到 QEMU Guest Agent
- 设置为 Enabled(启用)
- 如果需要自动时间同步,还可以额外启用:
Use Qemu Guest Agent: Yes

🟦5.验证是否安装成功
在 PVE 后台(或宿主机)运行:
qm agent vmid ping
如果返回为空:
{}
代表 QGA 已正常通信。

更新节能面板逻辑
我们现在已经成功安装了Qemu Guest Agent,但是目前还不能实现我们的需求。因为现在只是宿主和虚拟机之间能够通信,还没有定义通信的内容。
所以我们修改启动虚拟机按钮的逻辑:
async function manageVM(vmId, action) {
const numericVmId = parseInt(vmId, 10);
const cleanedAction = action.trim();
// 1. 先执行原有 VM 操作,也就是恢复虚拟机
const response = await fetch(`${PVE_HOST}/api2/json/nodes/pve/qemu/${numericVmId}/status/${cleanedAction}`, {
method: 'POST',
headers: {
'Authorization': AUTH_HEADER
}
});
const data = await response.json();
// 2. 对指定的虚拟机执行时间同步
if (numericVmId === vmId && cleanedAction === 'resume') {
// 格式化本地时间为 "YYYY-MM-DD HH:mm:ss"
const pad = (n) => n.toString().padStart(2, '0');
const now = new Date();
const currentTime = `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())} ${pad(now.getHours())}:${pad(now.getMinutes())}:${pad(now.getSeconds())}`;
console.log(currentTime);
const execCommand = [
"powershell.exe",
"-Command",
`Set-Date -Date '${currentTime}'`
];
try {
const execRes = await fetch(
`${PVE_HOST}/api2/json/nodes/pve/qemu/${numericVmId}/agent/exec`,
{
method: 'POST',
headers: {
'Authorization': AUTH_HEADER,
'Content-Type': 'application/json'
},
body: JSON.stringify({ command: execCommand })
}
);
const execData = await execRes.json();
console.log("[TIME-SYNC] Set-Date exec response:", execData);
} catch (err) {
console.error("[TIME-SYNC] Error executing Set-Date:", err);
}
}
return true;
}关键的代码就是下面这段,通过PVE的API发送一段powershell脚本给到虚拟机,让它立即更新时间。
const execCommand = [
"powershell.exe",
"-Command",
`Set-Date -Date '${currentTime}'`
];
try {
const execRes = await fetch(
`${PVE_HOST}/api2/json/nodes/pve/qemu/${numericVmId}/agent/exec`,
{
method: 'POST',
headers: {
'Authorization': AUTH_HEADER,
'Content-Type': 'application/json'
},
body: JSON.stringify({ command: execCommand })
}
);💖后记
对齐协同链路颗粒度,
前置化解决痛点,
强化虚拟机肖像,
构建运维管理闭环。
