【Proxmox VE】PVE 首页显示 CPU、主板、NVME、硬盘 温度等信息

网上各种版本的 PVE 首页温度 DIY 脚本,但萝卜青菜各有所爱,总是难得遇到钟情的那一款
自行 DIY 的话,正则 + js 入门确实需要点门槛
所以这里提供另一种实现方式 json,清晰明了,便于阅读,修改简单
无论是 温度、风扇转速、硬盘温度、硬盘信息都可以轻松搞定



出错原因及处理方式

  1. 首页转圈,只显示一部分数据
    一般都是由于参数值读取错误造成的
    假设代码片段中有如下参数
    var temperature = value['temperature']['current'].toFixed(1);
    但硬盘 smartctl 返回值中没有温度值、或键值名称不一致,就会造成参数读取错误,首页转圈
  2. 首页转圈,所有自定义数据都不能显示
    检查 CPU 温度代码段,是否有代码错误(参照第一条)
    如修改了 Nodes.pm 文件,需要使用 systemctl restart pveproxy 命令重载 PVE 界面
    仅修改 js 文件的情况下,无需重载 PVE 界面,浏览器强制刷新就能看到修改后的结果
  3. 首页白屏,什么都不显示
    一般都是代码有误引起的,请还原文件重新操作,或检查代码是否缺少相对应的 {} , () 等符号
  4. 中文乱码
    请不要将文件拖到本地使用 记事本 操作,直接在 WinSCP 中操作,或在本地使用 Notepad 等软件进行编辑
    如操作无误依然乱码,请检查终端软件及 WinSCP 的编码设置,并在 PVE 终端中输入
    export LC_ALL=en_US.UTF-8
  5. 无报错,但显示不全
    参考文末,修改显示范围

前置命令

# 更新软件包列表:

1
apt-get update

# 安装lm-sensors:

1
apt-get install lm-sensors patch

# 初始化 sensors (一路yes,回车):

1
sensors-detect

# 给予 smartctl 权限 (如不需要硬盘信息可以忽略):

1
chmod +s /usr/sbin/smartctl

# 设置 PVE 编码为 UTF-8 (如 PVE 安装时正确选择了 china 地区可以忽略):

1
export LC_ALL=en_US.UTF-8

# 获取温度信息,查看可以设置的数据:

1
sensors

# 这个时候是没有风扇等信息的,需要重启 (如不需要风扇转速信息可以忽略):

1
reboot

备份原文件

如命令未错误输入,文件备份在原文件相同目录下
如 : /usr/share/perl5/PVE/API2/Nodes.pm 备份为 /usr/share/perl5/PVE/API2/Nodes.pmbak

1
2
3
4
5
6
proxmoxlib_js="/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js"
Nodes_pm="/usr/share/perl5/PVE/API2/Nodes.pm"
pvemanagerlib_js="/usr/share/pve-manager/js/pvemanagerlib.js"
cp ${proxmoxlib_js} ${proxmoxlib_js}bak
cp ${Nodes_pm} ${Nodes_pm}bak
cp ${pvemanagerlib_js} ${pvemanagerlib_js}bak

懒人补丁法(若未修改过原文件,已包含高度修改、去除订阅提示,宽度未更改)

将补丁文件放到 /tmp/ 文件夹
大版本升级可能依然需要手动修改部分代码,补丁失败的文件及代码行数会在 patch 返回值中显示,请留意
如遇页面显示错误,参照上文
不保证可用性

2022/06/16
为每一个参数加入了判断语句,应该不会再出错了,但是大概可能会拖慢读取速度 0.xx 秒:
强迫症、完美主义者、需要自行添加数据等,自行参照注释版本添加修改
M.2 为系统盘,无法休眠调试,代码未处理,需要自行添加
PVE_7.2_temperatures.zip
PVE_8.0_temperatures.zip

1
2
3
4
5
6
# 应用补丁(请确认已经备份原文件)
patch ${proxmoxlib_js} < /tmp/proxmoxlib_js.patch
patch ${Nodes_pm} < /tmp/Nodes_pm.patch
patch ${pvemanagerlib_js} < /tmp/pvemanagerlib_js.patch
# 重载 PVE 界面
systemctl restart pveproxy

自行制作补丁

可以在重装或升级后快速修改文件(大版本升级可能需要手动修改部分代码)
生成的补丁文件在 /tmp/ 文件夹:

1
2
3
4
5
6
proxmoxlib_js="/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js"
Nodes_pm="/usr/share/perl5/PVE/API2/Nodes.pm"
pvemanagerlib_js="/usr/share/pve-manager/js/pvemanagerlib.js"
diff -uN ${proxmoxlib_js}bak ${proxmoxlib_js} > /tmp/proxmoxlib_js.patch
diff -uN ${Nodes_pm}bak ${Nodes_pm} > /tmp/Nodes_pm.patch
diff -uN ${pvemanagerlib_js}bak ${pvemanagerlib_js} > /tmp/pvemanagerlib_js.patch

自行修改文件

修改 Nodes.pm 文件
/usr/share/perl5/PVE/API2/Nodes.pm
搜索:$res->{pveversion} = PVE::pvecfg::package()
下方添加

1
2
3
4
5
$res->{sensors_json} = `sensors -j`; # 获取 CPU 、主板温度及风扇转速
$res->{smartctl_nvme_json} = `smartctl -a -j /dev/nvme?`; # 读取 nvme 硬盘 S.M.A.R.T. 值,获取硬盘寿命、容量、温度等
$res->{smartctl_sda_json} = `smartctl -i -n standby /dev/sda|grep "STANDBY" || smartctl -i -n standby /dev/sda|grep "No such device" || smartctl -a -j /dev/sda`; #先检测硬盘是否为休眠状态,若否,则检查磁盘是否存在,若否,则返回 S.M.A.R.T. 值
$res->{smartctl_sdb_json} = `smartctl -i -n standby /dev/sdb|grep "STANDBY" || smartctl -i -n standby /dev/sdb|grep "No such device" || smartctl -a -j /dev/sdb`; #先检测硬盘是否为休眠状态,若否,则检查磁盘是否存在,若否,则返回 S.M.A.R.T. 值
$res->{cpusensors} = `lscpu | grep MHz`; # 读取 CPU 频率

关于获取硬盘名称

1
lsblk | awk '$NF=="disk" {print $1}' | sort -u

终端输入 sensors -j 命令,我们可以得到类似下面的结果(以下为 CPU 温度值截取)
先眼熟一下 JSON 格式的返回值,等下会用到

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
"coretemp-isa-0000":{
"Adapter": "ISA adapter",
"Package id 0":{
"temp1_input": 38.000,
"temp1_max": 84.000,
"temp1_crit": 100.000,
"temp1_crit_alarm": 0.000
},
"Core 0":{
"temp2_input": 34.000,
"temp2_max": 84.000,
"temp2_crit": 100.000,
"temp2_crit_alarm": 0.000
},
"Core 1":{
"temp3_input": 38.000,
"temp3_max": 84.000,
"temp3_crit": 100.000,
"temp3_crit_alarm": 0.000
}

修改 pvemanagerlib.js 文件
/usr/share/pve-manager/js/pvemanagerlib.js
搜索 PVE Manager Version
下方添加

原始版本及注释

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
itemId: 'thermal', // thermal 代表了这一段代码的 id ,随便改一下不要重复就行了
colspan: 2,
printBar: false,
title: gettext('温度'), // 这里表示你想在页面中显示的左侧标题名
textField: 'sensors_json', // 这里需要填写 Nodes.pm 文件中对应的命令,也就是从哪一个返回值中获取数据
renderer: function(value) {
value = JSON.parse(value); // 使用 JavaScript 内置函数 JSON.parse() 将字符串转换为 JavaScript 对象
const cpu0 = value['coretemp-isa-0000']['Package id 0']['temp1_input'].toFixed(1); // 这里表示读取 CPU 温度,对应 sensors -j 输出的 JSON 格式数据,toFixed(1) 表示将数字转换为字符,只保留 (1) 位小数
const PECI0 = value['nct6798-isa-0290']['PECI Agent 0']['temp7_input'].toFixed(1); // 同上,自行修改
const pch = value['pch_cometlake-virtual-0']['temp1']['temp1_input'].toFixed(1); // 同上,自行修改
return `CPU: ${cpu0}°C || 南桥: ${pch} ℃ | 网卡: ${PECI0} ℃`; // return 表示输出值,也就是最后显示在 WEB 页面中的值,{}中填入上几行中定义的变量,格式自行调整
}
},

加一点细节

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
{
itemId: 'thermal',
colspan: 2,
printBar: false,
title: gettext('温度'),
textField: 'sensors_json',
renderer: function(value) {
value = value.replace(/temp([0-9]{1,})_input/g,'input');
// Intel
if (value.indexOf("coretemp-isa") != -1 ) {
value = value.replace(/coretemp-isa-(.{4})/g,'coretemp-isa');
value = value.replace(/nct6798-isa-(.{4})/g,'nct6798-isa');
value = JSON.parse(value);
try {var cpu_Intel = 'CPU: ' + value['coretemp-isa']['Package id 0']['input'].toFixed(1) + '°C';} catch(e) {var cpu_Intel = '';}
try {var acpi = ' || 主板: ' + value['acpitz-acpi-0']['temp1']['input'].toFixed(1) + '°C';} catch(e) {var acpi = '';}
try {var pch = ' || 南桥: ' + value['pch_cometlake-virtual-0']['temp1']['input'].toFixed(1) + '°C';} catch(e) {var pch = '';}
try {var pci0 = ' || 网卡: ' + value['nct6798-isa']['PECI Agent 0']['input'].toFixed(1) + '°C';} catch(e) {var pci0 = '';}
// 如果存在主板、PCI网卡温度,优先显示
if (cpu_Intel.length > 0 && pch.length + acpi.length + pci0.length > 0) {
return `${cpu_Intel}${acpi}${pch}${pci0}`;
// 如果不存在,显示 CPU 全核温度,最高支持 8 核心
} else if (cpu_Intel.length > 0) {
try {var cpu0 = ' || 核心 0 : ' + value['coretemp-isa']['Core 0']['input'].toFixed(1) + '°C';} catch(e) {var cpu0 = '';}
try {var cpu1 = ' | 核心 1 : ' + value['coretemp-isa']['Core 1']['input'].toFixed(1) + '°C';} catch(e) {var cpu1 = '';}
try {var cpu2 = ' | 核心 2 : ' + value['coretemp-isa']['Core 2']['input'].toFixed(1) + '°C';} catch(e) {var cpu2 = '';}
try {var cpu3 = ' | 核心 3 : ' + value['coretemp-isa']['Core 3']['input'].toFixed(1) + '°C';} catch(e) {var cpu3 = '';}
try {var cpu4 = ' | 核心 4 : ' + value['coretemp-isa']['Core 4']['input'].toFixed(1) + '°C';} catch(e) {var cpu4 = '';}
try {var cpu5 = ' | 核心 5 : ' + value['coretemp-isa']['Core 5']['input'].toFixed(1) + '°C';} catch(e) {var cpu5 = '';}
try {var cpu6 = ' | 核心 6 : ' + value['coretemp-isa']['Core 6']['input'].toFixed(1) + '°C';} catch(e) {var cpu6 = '';}
try {var cpu7 = ' | 核心 7 : ' + value['coretemp-isa']['Core 7']['input'].toFixed(1) + '°C';} catch(e) {var cpu7 = '';}
return `${cpu_Intel}${cpu0}${cpu1}${cpu2}${cpu3}${cpu4}${cpu5}${cpu6}${cpu7}`;
}
// AMD
} else if (value.indexOf("amdgpu-pci") != -1 ) {
value = value.replace(/k10temp-pci-(.{4})/g,'k10temp-pci');
value = value.replace(/zenpower-pci-(.{4})/g,'zenpower-pci');
value = value.replace(/amdgpu-pci-(.{4})/g,'amdgpu-pci');
value = JSON.parse(value);
try {var cpu_amd_k10 = 'CPU: ' + value['k10temp-pci']['Tctl']['input'].toFixed(1) + '°C';} catch(e) {var cpu_amd_k10 = '';}
try {var cpu_amd_zen = 'CPU: ' + value['zenpower-pci']['Tctl']['input'].toFixed(1) + '°C';} catch(e) {var cpu_amd_zen = '';}
try {var amdgpu = ' | GPU: ' + value['amdgpu-pci']['edge']['input'].toFixed(1) + '°C';} catch(e) {var amdgpu = '';}
return `${cpu_amd_k10}${cpu_amd_zen}${amdgpu}`;
} else {
return `提示: CPU 及 主板 温度读取异常`;
}
}
},
{
itemId: 'nvme_ssd',
colspan: 2,
printBar: false,
title: gettext('NVME'),
textField: 'smartctl_nvme_json',
renderer: function(value) {
value = JSON.parse(value);
if (value['model_name']) {
try {var model_name = value['model_name'];} catch(e) {var model_name = '';}
try {var percentage_used = ' | 使用寿命: ' + value['nvme_smart_health_information_log']['percentage_used'].toFixed(0) + '% ';} catch(e) {var percentage_used = '';}
try {var data_units_read = value['nvme_smart_health_information_log']['data_units_read']*512/1024/1024/1024;var data_units_read = '(读: ' + data_units_read.toFixed(2) + 'TB, ';} catch(e) {var data_units_read = '';}
try {var data_units_written = value['nvme_smart_health_information_log']['data_units_written']*512/1024/1024/1024;var data_units_written = '写: ' + data_units_written.toFixed(2) + 'TB)';} catch(e) {var data_units_written = '';}
try {var power_on_time = ' | 通电: ' + value['power_on_time']['hours'].toFixed(0) + '小时';} catch(e) {var power_on_time = '';}
try {var temperature = ' | 温度: ' + value['temperature']['current'].toFixed(1) + '°C';} catch(e) {var temperature = '';}
return `${model_name}${percentage_used}${data_units_read}${data_units_written}${power_on_time}${temperature}`;
} else {
return `提示: 未安装硬盘或已直通硬盘控制器`;
}
}
},
{
itemId: 'SATA_sda',
colspan: 2,
printBar: false,
title: gettext('SATA_sda'),
textField: 'smartctl_sda_json',
renderer: function(value) {
if (value.indexOf("Device is in STANDBY mode") != -1 ) {
return `提示: 磁盘休眠中`;
} else if (value.indexOf("No such device") != -1 ) {
return `提示: 未安装硬盘或已直通硬盘控制器`;
} else {
value = JSON.parse(value);
try {var model_name = value['model_name'];} catch(e) {var model_name = '';}
try {var user_capacity = value['user_capacity']['bytes']/1024/1024/1024;var user_capacity = ' | 容量: ' + user_capacity.toFixed(2) + ' GB';} catch(e) {var user_capacity = '';}
try {var power_on_time = ' | 已通电: ' + value['power_on_time']['hours'].toFixed(0) + ' 小时';} catch(e) {var power_on_time = '';}
try {var error_count = value['ata_smart_error_log']['summary']['count'].toFixed(0);if (error_count != 0){error_count = ' | 磁盘错误: ' + error_count;} else {var error_count = '';} } catch(e) {var error_count = '';}
try {var self_count = value['ata_smart_self_test_log']['standard']['error_count_total'].toFixed(0);if (self_count != 0){self_count = ' | 自检错误: ' + self_count;} else {var self_count = '';} } catch(e) {var self_count = '';}
try {var temperature = ' | 温度: ' + value['temperature']['current'].toFixed(1) + '°C';} catch(e) {var temperature = '';}
return `${model_name}${user_capacity}${power_on_time}${error_count}${self_count}${temperature}`;
}
}
},
{
itemId: 'SATA_sdb',
colspan: 2,
printBar: false,
title: gettext('SATA_sdb'),
textField: 'smartctl_sdb_json',
renderer: function(value) {
if (value.indexOf("Device is in STANDBY mode") != -1 ) {
return `提示: 磁盘休眠中`;
} else if (value.indexOf("No such device") != -1 ) {
return `提示: 未安装硬盘或已直通硬盘控制器`;
} else {
value = JSON.parse(value);
try {var model_name = value['model_name'];} catch(e) {var model_name = '';}
try {var user_capacity = value['user_capacity']['bytes']/1024/1024/1024;var user_capacity = ' | 容量: ' + user_capacity.toFixed(2) + ' GB';} catch(e) {var user_capacity = '';}
try {var power_on_time = ' | 已通电: ' + value['power_on_time']['hours'].toFixed(0) + ' 小时';} catch(e) {var power_on_time = '';}
try {var error_count = value['ata_smart_error_log']['summary']['count'].toFixed(0);if (error_count != 0){error_count = ' | 磁盘错误: ' + error_count;} else {var error_count = '';} } catch(e) {var error_count = '';}
try {var self_count = value['ata_smart_self_test_log']['standard']['error_count_total'].toFixed(0);if (self_count != 0){self_count = ' | 自检错误: ' + self_count;} else {var self_count = '';} } catch(e) {var self_count = '';}
try {var temperature = ' | 温度: ' + value['temperature']['current'].toFixed(1) + '°C';} catch(e) {var temperature = '';}
return `${model_name}${user_capacity}${power_on_time}${error_count}${self_count}${temperature}`;
}
}
},
{
itemId: 'MHz',
colspan: 2,
printBar: false,
title: gettext('CPU频率'),
textField: 'cpusensors',
renderer:function(value){
var f0 = value.match(/CPU MHz.*?([\d]+)/)[1];
var f1 = value.match(/CPU min MHz.*?([\d]+)/)[1];
var f2 = value.match(/CPU max MHz.*?([\d]+)/)[1];
return `实时: ${f0} MHz || 最小: ${f1} MHz | 最大: ${f2} MHz `
}
},

如果是 PVE 8.0,CPU 不再返回实时频率,需要修改为下列代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
itemId: 'MHz',
colspan: 2,
printBar: false,
title: gettext('CPU频率'),
textField: 'cpusensors',
renderer:function(value){
var f1 = value.match(/CPU min MHz.*?([\d]+)/)[1];
var f2 = value.match(/CPU max MHz.*?([\d]+)/)[1];
var f0 = value.match(/CPU.*scaling MHz.*?([\d]+)/)[1];
var f0 = f0*f2/100;
return `实时: ${f0} MHz || 最小: ${f1} MHz | 最大: ${f2} MHz `
}
},

修改显示范围
依然是 pvemanagerlib.js 文件
搜索 widget.pveNodeStatus
将 height: 300 (默认值) 改大为 420,或者更大,然后保存(每多一行大概增大 20~25)

重载 PVE 界面
修改完成后重载 PVE 界面
如无把握,建议不要一次加入太多代码,修改一段就重载一次

1
systemctl restart pveproxy

【RouterOS(ROS)】自动更新分流规则

  • 分流设置参照 :ROS 分流设置

  • 此处不再详述

  • 下载并导入规则

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    # 下载文件
    /tool fetch url=http://www.iwik.org/ipcountry/mikrotik/CN
    # 关闭日志输出,避免刷屏
    /system logging disable 0
    # 载入列表
    /import file-name=CN
    # 恢复日志输出输出选项
    /system logging enable 0
    # 查看当前列表数量
    :local CN [:len [/ip firewall address-list find list="CN"]]
    # 删除文件
    /file remove [find name="CN"]
    # 写入日志
    :log info ("CN列表更新:"."$CN"."条规则")

End

【RouterOS(ROS)】UPNP 设置 - 自动老化及重拨后修改 IP

  • 以下脚本命令基于 ROS 7.2.3,其他版本不一定适用

  • 此脚本在 7.9 或更早已经失效,新版本的 ROS 不允许删除动态对象

  • ROS 开启 UPNP 后,会自动映射端口,所生成的端口映射可以在 IP - Firewall - NAT 中查询,但 ROS 自动生成的端口映射没有老化时间,需要手动进行删除,或使用脚本进行删除,这里记录一下编写的脚本。

  • upnp 老化(自行设定定时执行)

    1
    2
    3
    4
    5
    6
    7
    /ip firewall nat;
    :foreach singleRule in=[find where dynamic=yes] do={
    :if ([:ping [get $singleRule to-addresses] count=2] < 1) do={
    remove $singleRule
    :log warning "*** 删除不可用的 upnp 规则 ***";
    }
    };
  • 拨号后自动修改 dst-address (建议 pppoe 接口绑定拨号脚本,然后在 PPP - Profiles 下添加)

    1
    2
    3
    4
    5
    6
    7
    8
    :global addold
    :global addnew
    :set addnew [/interface get [/interface find name="pppoe-out1"] running]
    :if ($addnew=true) do={
    :set addold [/ip address get [/ip address find dynamic=yes interface="pppoe-out1"] address]
    :set addold [:pick $addold 0 ([:len $addold ] -3)]
    /ip firewall nat set [find dynamic=yes comment ~"^upnp*."] dst-address=$addold
    }

End

ALL in one 记录二(PVE 初装设置&核显直通&HTPC相关设置)

因为新购入了主机,需要重新调试 PVE ,在这里做一些记录

PVE初装

1. BIOS设置

1)debian 默认 BIOS 时间为 UTC 时间,时间不对的情况下会造成主机开启关闭状态显示不正常,并造成令牌验证失败频繁退出登录,所以最好调整 BIOS 时间为 UTC 时间
PVE 安装时间同步软件也可以,但是初装电脑,开机网络不通的时候虚拟机开关会造成以上问题,所以推荐直接改 BIOS 时间
2)确认开启虚拟化
根据需要确认开启或关闭 CSM 、CPU 节能、板载声卡、来电自启动等选项(CPU C6/C7/C10 等节能请确认硬件支持再开启,以免造成低负载随机死机)

2. PVE安装

官网下载镜像:https://www.proxmox.com/en/downloads
使用 U盘刻录软件刻录即可,我这里使用的是 balenaEtcher
为了方便设置管理口,只插上一根自动分配IP的网线到要要设置的管理口上,IP 可以在安装界面上更改,主要是为了分辨网口编号
(尽量不要使用板载网卡,有些主板官方内核板载网卡、板载声卡等设备无法拆分,会导致后续声卡直通时出问题,我这里从 I340T4 里面选了一个口作为管理口使用)

3. PVE设置

1)删除 local-lvm 分区,只留下 local 分区

避免空间浪费,而且 PVE 首页上显示的空间剩余指的是 local 分区,我使用 J4125 的时候就发生过一次 local-lvm 塞满造成的 IO-err,推荐新装 PVE 时进行设置,不然还要备份还原虚拟机,比较麻烦

1
2
lvremove pve/data
lvextend -l +100%FREE -r pve/root

数据中心-存储-删除local-lvm
选择local,编辑,在内容里添加磁盘映像和容器
如果需要还原之前的虚拟机,则需要使用如下命令(无法使用 WEB 页面还原,因为储存位置不一致)

1
qmrestore /var/lib/vz/dump/vzdump-qemu-101-2022_05_19-19_07_41.vma.zst 101 -storage local
2)换源、关闭订阅、首页温度提示等操作

参考:
https://github.com/xiangfeidexiaohuo/ProxmoxVE-7.0-DIY
http://songw.top/archives/748.html
https://zry.io/archives/285

3)主页显示温度
使用环境:
sensors 有风扇(fan:)、CPU温度(Package id 0:)、PCI温度(PECI Agent 0: )输出,一块 NVME、两块 SATA
恩山代码已做空值错误处理
详细说明:
https://www.right.com.cn/forum/thread-8236620-1-1.html

1
2
3
4
5
6
7
8
9
10
11
12
# 更新软件包列表:
apt-get update
# 安装lm-sensors:
apt-get install lm-sensors
# 初始化 sensors(一路yes,回车):
sensors-detect
# 给予 smartctl 权限(如不需要硬盘信息可以忽略)
chmod +s /usr/sbin/smartctl
# 获取温度信息:
sensors
# 这个时候是没有风扇等信息的,需要重启:
reboot
1
2
3
4
5
6
7
8
9
10
11
12
13
# 备份
proxmoxlib_js="/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js"
Nodes_pm="/usr/share/perl5/PVE/API2/Nodes.pm"
pvemanagerlib_js="/usr/share/pve-manager/js/pvemanagerlib.js"
cp ${proxmoxlib_js} ${proxmoxlib_js}bak
cp ${Nodes_pm} ${Nodes_pm}bak
cp ${pvemanagerlib_js} ${pvemanagerlib_js}bak
# 应用补丁
patch ${proxmoxlib_js} < /tmp/proxmoxlib_js.patch
patch ${Nodes_pm} < /tmp/Nodes_pm.patch
patch ${pvemanagerlib_js} < /tmp/pvemanagerlib_js.patch
# 重载 PVE 界面
systemctl restart pveproxy
1
2
3
4
5
6
7
# 制作补丁
proxmoxlib_js="/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js"
Nodes_pm="/usr/share/perl5/PVE/API2/Nodes.pm"
pvemanagerlib_js="/usr/share/pve-manager/js/pvemanagerlib.js"
diff -uN ${proxmoxlib_js}bak ${proxmoxlib_js} > /tmp/proxmoxlib_js.patch
diff -uN ${Nodes_pm}bak ${Nodes_pm} > /tmp/Nodes_pm.patch
diff -uN ${pvemanagerlib_js}bak ${pvemanagerlib_js} > /tmp/pvemanagerlib_js.patch

页面效果

4. 直通篇

大同小异,只说一些坑和一些配置说明

1)/etc/default/grub 文件

据说 video=vesafb:off,efifb:off 已经无法使用(大概在7.x版本)
需要改成 video=vesafb:off video=efifb:off
如果是 pve-kernel 5.15 可能还需要 video=simplefb:off
详见:
https://forum.proxmox.com/threads/pve7-failed-to-mmap-xxxx-xx-xx-x-bar-3-performance-may-be-slow.108129/
https://forum.proxmox.com/threads/gpu-passthrough-not-working-bar-3.60996/

2)直通分组

如果你的硬件分组像我这样子,即使在 /etc/default/grub 文件中添加了 pcie_acs_override=downstream 参数依然无法拆分
00:1f.3 9 Audio device: Intel Corporation Comet Lake PCH cAVS
00:1f.4 9 SMBus: Intel Corporation Comet Lake PCH SMBus Controller
00:1f.5 9 Serial bus controller [0c80]: Intel Corporation Comet Lake PCH SPI Controller
00:1f.6 9 Ethernet controller: Intel Corporation Ethernet Connection (11) I219-V
有以下解决方案

  • 自行编译内核拆分设备
  • 对这台虚拟机直通该分组下的所有设备(或者点击直通所有功能,如果这样做,该分组下所有设备都将不能被其他虚拟机使用,尤其要确认你的管理网口不在这个分组下)
3)直通设备数量

PVE 模拟了主板的真实工作状态,所以 PCI、SATA、USB 都是有直通上限的,如果使用了超过上限的直通设备(包括写在 /etc/pve/nodes/pve/qemu-server/xxx.conf 文件下的直通设备),开机会就会报 400 错误
400 错误
Parameter verification failed. (400)
undefined: property is not defined in schema and the schema does not allow additional properties
有以下解决方案

  • 编辑 /etc/pve/nodes/pve/qemu-server/xxx.conf 文件,使用这样的参数(可能需要这些设备在一个分组下)
    hostpci1: 00:1f.3;00:1f.4;00:1f.5;00:1f.6
  • 直通整个分组(修改文件或在 WEB 页面中选中 所有功能)
    hostpci1: 00:1f
  • 直通整个控制器,如 USB 控制器
    00:14.0 USB controller: Intel Corporation Comet Lake USB 3.1 xHCI Host Controller
    我的配置参考
    官方WIKI:https://pve.proxmox.com/wiki/Pci_passthrough
4)无法开机、驱动装上了也没有画面

一些别的坑

  • 因为开始的时候没有 DP 转接头,我也不确定 DP 接口有没有信号输出,想着干脆做 GVT-G 让群晖和 Windows 都能用上核显算了,于是买了 USB 转 HDMI ,然后手贱觉得 type-c 比较小巧还有弯头可选
    买回来之后才知道台式机 type-c 不是全功能 C 口,根本无法传输视频信号,并且 type-c 视频输出其实也是走的 DP 输出,对于我当时的情况无济于事
    所以如果要做 GVT-G 和视频输出,认准这几个字 “USB外置显卡“!(因为不确定这玩意解码到底走的 GPU 还是 CPU 或者是外置显卡本身,我最后还是放弃了,还好 DP 信号正常)
    其实还是翻车了,69 的某绿转接头时不时黑屏闪屏,1080P 勉强能用,4K 压根就是残废,DP 接口对线材要求实在太高了

  • 华擎主板 改显存,增加 GVT-G “显卡” 需要使用这个引导
    https://github.com/XDleader555/grub_setup_var
    指令参考(我这个主板实测只能改到 512m,1G无法开机,老老实实扣电池)

    1
    setup_var SaSetup 0xAF 0x3
  • PVE 7.1/7.2 某些内核直通可能存在问题,需要尝试更换内核
    7.2 版本默认内核貌似无法使用 UPT 模式直通核显(Legacy 模式无影响)
    据说正常可用的版本有 5.13.19-4-pve
    参考:https://www.jianshu.com/p/822c167d0c3a

  • 虚拟机 Windows 关机后 HDMI 无声音
    原因不明,临时解决方案

  1. 不要使用关机选项,用休眠替代(重启或关机后无声音,也可以用休眠后重新开机恢复,奇葩的 bug)
    注:如果 Windows 开启休眠,无法正常唤醒(唤醒变重启等),请尝试更换驱动、romfile 文件
  2. 使用 USB 声卡或板载声卡接口输出音频(这是无奈之选,如果要接到电视这种设备,没有 3.5mm 音频口又各种尝试失败的话,VGA+3.5mm 转 HDMI,效果嘛…………:fa-meh-o::fa-meh-o::fa-meh-o::fa-meh-o:)

其他可能用到的东西

  • 群晖核显驱动状态和硬解状态查询

    1
    2
    3
    sudo -i
    ls /dev/dri
    cat /sys/kernel/debug/dri/0/i915_frequency_info
  • 群晖替换驱动文件(将 i915.ko 文件放入 /tmp/ 文件夹下)

    1
    2
    sudo -i
    rm /usr/lib/modules/i915.ko && cp /tmp/i915.ko /usr/lib/modules/
  • 让 VM 支持网络唤醒,配合 home assistant 做 htpc 开关机控制
    参考:https://bbs.hassbian.com/thread-16061-1-1.html

  • 在虚拟机下控制主板RGB
    安装 OpenRGB:https://openrgb.org/releases.html
    直通 USB 中的 RGB 控制器,下载安装开启 OpenRGB(第一次打开需要管理员权限)

  • PVE 内核 5.15 会出现显卡直通 (HDMI 直通) 下 Windows 虚拟机的 鼠标指针不显示 或 鼠标反应卡顿 的问题。解决方法如下:

  1. 使用 noVNC 或 RDP 登录进 Windows,在“控制面板 - 鼠标 - 指针选项”中启用“显示鼠标轨迹”,并把滑块拖至最左 (基本不影响显示体验);
  2. 升级到 6.x 内核或降级到 5.13 内核
    检查是否安装 5.13 版内核:
    proxmox-boot-tool kernel list

如果 5.13 内核未被安装或者内核被手动清理的话可能需要手动安装 5.13 内核:
apt install pve-kernel-5.13

安装成功后再次执行以下命令查看已安装的内核:
proxmox-boot-tool kernel list

固定之后启动的内核版本:
proxmox-boot-tool kernel pin 5.13.19-6-pve

保存配置:
proxmox-boot-tool refresh

重启后内核即被回退至 5.13。

如果你想解除内核固定,可以执行:
proxmox-boot-tool kernel unpin 5.13.19-6-pve
proxmox-boot-tool refresh

经历过的死机状况记录

  1. J4125 的时候,USB 口不够用,接了两个 USB 集线器,集线器上插超过 3 个 USB 设备直通给 Windows,一小时之内绝对会 boom,至今不知道是那块主板的问题还是 PVE 的问题(后来一直插着 3 个 USB,再也没遇到过死机现象,升级 PVE 后也没测试,没深究原因)
  2. 刚装完新机子,拿回家用之后莫名其妙的不稳定,脸黑就死机,重装并升级到 7.2 之后好了,误会是内核的原因,直到前几天想改风扇转速,顺便开节能,死机情况又发生了,才确定是主板开启 C6/C7 节能的原因。

End

ALL in one 记录一(购买及组装篇-十代主机10400)

前因

家里使用的是 J4125 小主机,原先只是为了做个软路由,然后挂挂青龙面板薅羊毛,但后来由于媳妇是在用不习惯电视的视频软件(没有弹幕、会员费用高、操作不方便、零零散散的独占节目太多又不想每个都充会员)

于是就在 J4125 上面虚拟化了一个 Windows 作为 HTPC 使用,但这对于 J4125 来说实在是太吃力了

尤其是当初装修的时候没规划好,导致弱电设备只能放在酒柜里,散热不太好,一到夏天就开始过热降频,于是打算 618 入手,但最终还是没忍住剁手,希望 618 不会遭受太多背刺(虽然大多东西都是海鲜市场购入)

弱电柜

海鲜市场零零散散淘了一个月,前几天终于将配件购买完成。

在这里对踩过的坑,PVE 直通、调试等做一个记录,避免自己忘记,也希望给看到的网友带来一点帮助。

成品展示

功耗(PVE 打开 ROS+openwrt,空载状态)

配件清单和选购原因

购买备注

机箱(第一个坑):

组装 ITX 或者 MATX 主机,一定要先选好机箱再围绕机箱选购其他配件,我一开始就是没挑好机箱就开始买配件,最后又把还在路上的电源给退了,而且如果把内存条插槽的数量降一降,还可以选择更小的主板,但当时我已经在海鲜市场上买好了主板,于是机箱选起来很蛋疼,花了我很久的时间

因为柜子空间为 80cm36cm50cm,所以只能选择长度小于 32 的机箱(还要考虑插头预留长度),所以 pass 掉了很多机箱,备注都在上图,最终选择了 小喆优品B3全铝MATX机箱 蓝色款,326161275

黑色版还能便宜 40 块,但颜狗还是买了蓝色款。

配合弯头电源线,尺寸完美

CPU:

我选择了 I5-10400,同为UHD630的核显, i3-10100 应该就够用了,但是还是比较馋 8核16线程的 10400,因为需要挂载的虚拟机比较多,RouterOS + OpenWrt + NAS + HassOS + Windows + CentOS ,这里可以降低需求,8代9代的价格的话,还不如买10代,还可以选择 QSRK 等不限型号的 CPU,进一步压缩价格。
(J4125再次传来不堪重负的声音 )

CPU

主板(第二个坑):

本来和 CPU 一样,打算 618 京东买盒装,但因为没忍到 618,海鲜市场淘了华擎 Z490m pro4(本来是在 B460m pro4 、钢铁传奇、B460M-HDV-A之中选一个的,但突然刷到一个没背板的z490,看到4个PCI插槽直接就买了,但实际根本没用上 ,还导致了机箱和电源购买差点翻车)

这里要重点说一下,500系列因为要兼容 10、11 系的 CPU,导致如果使用 10 系 CPU 的话,很多主板第一个 m.2 插槽是无法使用的,还好没等到 618 ,不然买了 560 我就傻眼了。

400系主板的话,因为 400 系主板设计原因,基本都是妥协后的产物,根据网上评论还有几个大坑

1.华硕系主板

存在核显无法开机的问题,可以通过 BIOS、亮机卡等操作恢复(注意别买到相关型号,要买的话,确定 BIOS 升级可以解锁,并升级 BIOS)

详见:

https://tieba.baidu.com/p/6758134915

https://tieba.baidu.com/p/7668455948

2.微星系主板

部分主板存在 pci、m.2 互相冲突,无法插满或降速的问题,当时怕海鲜市场淘主板记错型号,没选微星

但刚刚搜百度发现问题主要存在360、450、560主板,完全没问题

详见:

https://nga.178.com/read.php?tid=19129452&forder_by=postdatedesc

https://www.chiphell.com/thread-2320570-1-1.html

https://tieba.baidu.com/p/6761957926

3.技嘉系主板

没有理由,不买

4.华擎系主板

B460M RRO4、B460M 钢铁传奇、华擎 B460M-HDV-A、华擎 Z490M RRO4 均无 PCI 、M.2 冲突

华擎系主板均选择了 M.2 插槽和 SATA 冲突,插入第一个 M.2 会导致禁用一个 SATA 接口,如果是为了 NAS 使用慎选

详见:

https://www.asrock.com/mb/Intel/B460M%20Pro4/index.tw.asp#Specification

5.其他

精力有限,没看

电源:

再重复一遍,一定要先选好机箱再买 主板、电源、散热器

都怪京东送了一张 -30 的优惠券,买了 ATX 电源,后来发现跟 24*24 的标准板放一起,直接超尺寸,于是路上就被我退了。

功率算出来满载是 100~150 ,但实在找不到这么小的电源,用 DC 电源、1U 什么的又怕翻车,老老实实京东买了 SFX 铜牌

硬盘:

还是因为怕翻车,买了三星,简单说一下

970 EVO Plus:速度快、但发热量高、有缓存设计

980:速度慢一些,性价比高、无缓存设计、发热低

因为担心 PVE 断电丢配置啥的,买了有缓存的 970

网卡:

本来想买 I350 的,因为馋 SR-IOV ,但价格实在太高了,还都是寨卡(担心啸叫等问题),最后还是买了 I340 富士通版本
I340

软路由常见型号和对比详见:

https://www.bilibili.com/read/cv15982632

寨卡分辨等:

https://www.chiphell.com/thread-2148116-1-1.html

散热器:

其实这个是无用需求,玩虚拟机,放柜子里看不到,拷机温度不超过60,买什么 RGB ,我也不知道 :fa-frown-o:

总结

因为重要的配件直接京东某宝,所以的确没有翻车,但其实价格方面没有便宜很多,但因为长年外地出差,担心翻车没法处理,还是没省这个钱。

没改功耗墙什么的,拷机的时候全核 4.0 只能保持大概 20s(功耗 100w) ,然后就降频到 3.2G(功耗 65w)

没改 BIOS 的话,空载(PVE 只开 ROS、openwrt ,无网络负载)功耗大概是 3032w,稍稍开了一点节能选项(CPU 开到 C6),待机功率降到 2526w,算是比较满足了

本来设置了风扇按温度开关,但实际发现根本多不了什么功耗,索性一直转了。

功耗方面稍稍有点高,主要原因应该还是电源买大了转化率不够高(印象里一般来说电源50%左右转化率最高,DC 电源就更好一点)

机箱的话还算比较好装,毕竟挺大的,唯一蛋疼的就是装了底部风扇之后,第四个 PCI 插槽被完全挡住了,以后升万兆大概只能拆风扇,或者换 X1 插槽的千兆卡了。

总体来说比较满意。

下一篇再写 PVE 的安装 和直通等。

机箱内部

点亮和拷机测试

娱乐大师跑分

End

  • Copyrights © 2022-2023 tty228
  • Visitors: | Views:

请我喝杯咖啡吧~

支付宝
微信