最近我的PVE上的虚拟机频繁重启,甚至PVE自身也会重启或者死机。经过一番排除法的验证,我发现是由于小主机的CPU温度过高,导致服务器触发自我保护,所以重启了系统。于是我决定让PVE显示CPU温度信息。
我的需求
首先需要说明的是,PVE系统自身是不会收集硬件温度信息的,所以也就不会显示这些信息,而我要做的就是让它收集并显示出来,配置之后的效果如下:
需要注意的是,由于每个人的硬件不同,所以收集到的信息也不同,那么显示的方式和效果也不同,我这里就是要说清楚这三个问题。
针对这个需求,首先我找了一篇参考文档:让PVE显示CPU温度,这个文档很有用,但是并不能照搬,因为这个文档没有讲清楚配置的原理,所以拿着文档硬抄的大概率就是不行的。
配置步骤
安装sensors
sensors是一个用来显示Linux硬件温度的软件,执行安装命令:
- apt install lm-sensors -y
复制代码 如果没有安装到,可能是要配置源,或者更新源,网上随便一搜就知道,也可以 参考我的教程:Proxmox VE 8.2.2 屏蔽订阅企业源 && 修改国内软件源
执行sensors
安装完成后,执行命令探测(所有的选择都输入y,最后一个enter):
然后执行 sensors 命令就可以显示硬件温度信息:
- coretemp-isa-0000
- Adapter: ISA adapter
- Package id 0: +40.0°C (high = +80.0°C, crit = +100.0°C)
- Core 0: +33.0°C (high = +80.0°C, crit = +100.0°C)
- Core 4: +40.0°C (high = +80.0°C, crit = +100.0°C)
- Core 8: +38.0°C (high = +80.0°C, crit = +100.0°C)
- Core 12: +36.0°C (high = +80.0°C, crit = +100.0°C)
- Core 16: +35.0°C (high = +80.0°C, crit = +100.0°C)
- Core 20: +36.0°C (high = +80.0°C, crit = +100.0°C)
- Core 24: +39.0°C (high = +80.0°C, crit = +100.0°C)
- Core 25: +39.0°C (high = +80.0°C, crit = +100.0°C)
- Core 26: +39.0°C (high = +80.0°C, crit = +100.0°C)
- Core 27: +39.0°C (high = +80.0°C, crit = +100.0°C)
- Core 28: +37.0°C (high = +80.0°C, crit = +100.0°C)
- Core 29: +37.0°C (high = +80.0°C, crit = +100.0°C)
- Core 30: +37.0°C (high = +80.0°C, crit = +100.0°C)
- Core 31: +37.0°C (high = +80.0°C, crit = +100.0°C)
复制代码 但是重点来了,由于个人的硬件不同,这里显示的内容其实是不尽相同的,就比如我看到的文章都是有显示CPU的每个核心的温度,但是我这里并没有显示。
采集温度信息
能查询到温度信息后,现在需要修改文件 /usr/share/perl5/PVE/API2/Nodes.pm 来收集 sensors 命令的返回信息。直接打开文件,然后搜索 shared => $meminfo->{memshared} 找到如下位置,并在下面插入一行(注意里面不要有注释):
- $res->{ksm} = {
- shared => $meminfo->{memshared},
- };
- $res->{cpu_temperatures} = `sensors`;
复制代码 这个文件的作用就是使用命令 sensors 去采集硬件信息,然后传递给变量 cpu_temperatures,也就是说现在 cpu_temperatures 的内容其实就是我们查询到的信息,这个变量后续会用到。
提取温度信息
由于我们执行 sensors 命令显示的信息很多,而且每个人的电脑上面看到的结果也大概率不同,但是我们大概能判断哪些是温度信息,并且可以自己查一下分别是什么硬件的温度。
此时我们就需要把温度信息提取出来了。这里可以分享一下我自己的方法(独家方法,完全是自己临时想的,而且很有效):因为后续我们要展示信息的时候是使用的js文件,也就是js语法,所以可以直接在浏览器的控制台去调试,提取自己想要的温度信息。
首先,打开任意页面的控制台,然后把使用命令 sensors 查询的所有信息复制出来,放到控制台(浏览器按F12可以调出控制台)并赋值给变量 value,就像这样(注意使用代码符号括起来):
- var value = `coretemp-isa-0000
- Adapter: ISA adapter
- Package id 0: +40.0°C (high = +80.0°C, crit = +100.0°C)
- Core 0: +33.0°C (high = +80.0°C, crit = +100.0°C)
- Core 4: +40.0°C (high = +80.0°C, crit = +100.0°C)
- Core 8: +38.0°C (high = +80.0°C, crit = +100.0°C)
- Core 12: +36.0°C (high = +80.0°C, crit = +100.0°C)
- Core 16: +35.0°C (high = +80.0°C, crit = +100.0°C)
- Core 20: +36.0°C (high = +80.0°C, crit = +100.0°C)
- Core 24: +39.0°C (high = +80.0°C, crit = +100.0°C)
- Core 25: +39.0°C (high = +80.0°C, crit = +100.0°C)
- Core 26: +39.0°C (high = +80.0°C, crit = +100.0°C)
- Core 27: +39.0°C (high = +80.0°C, crit = +100.0°C)
- Core 28: +37.0°C (high = +80.0°C, crit = +100.0°C)
- Core 29: +37.0°C (high = +80.0°C, crit = +100.0°C)
- Core 30: +37.0°C (high = +80.0°C, crit = +100.0°C)
- Core 31: +37.0°C (high = +80.0°C, crit = +100.0°C)
- acpitz-acpi-0
- Adapter: ACPI interface
- temp1: +27.8°C
- nct6798-isa-0290
- Adapter: ISA adapter
- in0: 752.00 mV (min = +0.00 V, max = +1.74 V)
- in1: 1.02 V (min = +0.00 V, max = +0.00 V) ALARM
- in2: 3.41 V (min = +0.00 V, max = +0.00 V) ALARM
- in3: 3.33 V (min = +0.00 V, max = +0.00 V) ALARM
- in4: 1.01 V (min = +0.00 V, max = +0.00 V) ALARM
- in5: 152.00 mV (min = +0.00 V, max = +0.00 V)
- in6: 744.00 mV (min = +0.00 V, max = +0.00 V) ALARM
- in7: 3.41 V (min = +0.00 V, max = +0.00 V) ALARM
- in8: 3.23 V (min = +0.00 V, max = +0.00 V) ALARM
- in9: 1.07 V (min = +0.00 V, max = +0.00 V) ALARM
- in10: 1.12 V (min = +0.00 V, max = +0.00 V) ALARM
- in11: 16.00 mV (min = +0.00 V, max = +0.00 V) ALARM
- in12: 1.04 V (min = +0.00 V, max = +0.00 V) ALARM
- in13: 424.00 mV (min = +0.00 V, max = +0.00 V) ALARM
- in14: 904.00 mV (min = +0.00 V, max = +0.00 V) ALARM
- fan1: 0 RPM (min = 0 RPM)
- fan2: 798 RPM (min = 0 RPM)
- fan3: 0 RPM (min = 0 RPM)
- fan4: 0 RPM (min = 0 RPM)
- fan5: 0 RPM (min = 0 RPM)
- fan6: 0 RPM (min = 0 RPM)
- SYSTIN: +39.0°C (high = +80.0°C, hyst = +75.0°C)
- (crit = +125.0°C) sensor = thermistor
- CPUTIN: +39.0°C (high = +80.0°C, hyst = +75.0°C)
- (crit = +125.0°C) sensor = thermistor
- AUXTIN0: +40.0°C (high = +80.0°C, hyst = +75.0°C)
- (crit = +100.0°C) sensor = thermistor
- AUXTIN1: +19.0°C (high = +80.0°C, hyst = +75.0°C)
- (crit = +125.0°C) sensor = thermistor
- AUXTIN2: +127.0°C (high = +80.0°C, hyst = +75.0°C) ALARM
- (crit = +125.0°C) sensor = thermistor
- AUXTIN3: +31.0°C (high = +80.0°C, hyst = +75.0°C)
- (crit = +100.0°C) sensor = thermistor
- AUXTIN4: +127.0°C (high = +80.0°C, hyst = +75.0°C) ALARM
- (crit = +100.0°C)
- PECI Agent 0 Calibration: +39.0°C (high = +80.0°C, hyst = +75.0°C)
- PCH_CHIP_CPU_MAX_TEMP: +0.0°C
- PCH_CHIP_TEMP: +0.0°C
- PCH_CPU_TEMP: +0.0°C
- PCH_MCH_TEMP: +0.0°C
- intrusion0: ALARM
- intrusion1: ALARM
- beep_enable: disabled
- nvme-pci-e100
- Adapter: PCI adapter
- Composite: +41.9°C (low = -273.1°C, high = +81.8°C)
- (crit = +84.8°C)
- Sensor 1: +41.9°C (low = -273.1°C, high = +65261.8°C)
- Sensor 2: +45.9°C (low = -273.1°C, high = +65261.8°C)`;
复制代码
然后我们使用js语法来分别把不同的温度赋值给一个变量,就比如cpu的温度赋值代码(核心越多,写的越多,因为每个核心都有可能会有传感器):
- const c0 = value.match(/Core 0.*?\+([\d\.]+)?/)[1];
- const c1 = value.match(/Core 4.*?\+([\d\.]+)?/)[1];
- const c2 = value.match(/Core 8.*?\+([\d\.]+)?/)[1];
- const c3 = value.match(/Core 12.*?\+([\d\.]+)?/)[1];
- const c4 = value.match(/Core 16.*?\+([\d\.]+)?/)[1];
- const c5 = value.match(/Core 20.*?\+([\d\.]+)?/)[1];
- const c6 = value.match(/Core 24.*?\+([\d\.]+)?/)[1];
- const c7 = value.match(/Core 25.*?\+([\d\.]+)?/)[1];
- const c8 = value.match(/Core 26.*?\+([\d\.]+)?/)[1];
- const c9 = value.match(/Core 27.*?\+([\d\.]+)?/)[1];
- const c10 = value.match(/Core 28.*?\+([\d\.]+)?/)[1];
- const c11 = value.match(/Core 29.*?\+([\d\.]+)?/)[1];
- const c12 = value.match(/Core 30.*?\+([\d\.]+)?/)[1];
- const c13 = value.match(/Core 31.*?\+([\d\.]+)?/)[1];
- const p0 = value.match(/Package id 0.*?\+([\d\.]+)?/)[1];
复制代码 单行测试代码:
一起测试代码,输出总的结果:
当你调试OK,拿到你想要的所有信息之后,再继续下一步。
显示温度信息
上面提取温度信息完成后,开始编辑文件 /usr/share/pve-manager/js/pvemanagerlib.js 来将提取的方式和要显示的格式配置到这个js文件中。
首先找到添加的位置,使用搜索关键词 textField: 'pveversion' 定位到如下位置,然后添加如下代码:
- {
- itemId: 'version',
- colspan: 2,
- printBar: false,
- title: gettext('Manager Version'),
- textField: 'pveversion',
- value: '',
- },// 下面一块是新增的,这里的逗号不要漏掉
-
- {
- itemId: 'cpu-temperatures',
- colspan: 2,
- printBar: false,
- title: gettext('CPU温度'),
- textField: 'cpu_temperatures',
- renderer:function(value){
- const c0 = value.match(/Core 0.*?\+([\d\.]+)?/)[1];45145
- const c1 = value.match(/Core 4.*?\+([\d\.]+)?/)[1];
- const c2 = value.match(/Core 8.*?\+([\d\.]+)?/)[1];
- const c3 = value.match(/Core 12.*?\+([\d\.]+)?/)[1];
- const c4 = value.match(/Core 16.*?\+([\d\.]+)?/)[1];
- const c5 = value.match(/Core 20.*?\+([\d\.]+)?/)[1];
- const c6 = value.match(/Core 24.*?\+([\d\.]+)?/)[1];
- const c7 = value.match(/Core 25.*?\+([\d\.]+)?/)[1];
- const c8 = value.match(/Core 26.*?\+([\d\.]+)?/)[1];
- const c9 = value.match(/Core 27.*?\+([\d\.]+)?/)[1];
- const c10 = value.match(/Core 28.*?\+([\d\.]+)?/)[1];
- const c11 = value.match(/Core 29.*?\+([\d\.]+)?/)[1];
- const c12 = value.match(/Core 30.*?\+([\d\.]+)?/)[1];
- const c13 = value.match(/Core 31.*?\+([\d\.]+)?/)[1];
- const p0 = value.match(/Package id 0.*?\+([\d\.]+)?/)[1];
- return `Package: ${p0}℃; Core 0: ${c0}℃; Core 4: ${c1}℃; Core 8: ${c2}℃; Core 12: ${c3}℃; Core 16: ${c4}℃; Core 20: ${c5}℃; Core 24: ${c6}℃; Core 25: ${c7}℃; Core 26: ${c8}℃; Cor e 27: ${c9}℃; Core 28: ${c10}℃; Core 29: ${c11}℃; Core 30: ${c12}℃; Core 31: ${c13}℃`
- }
- },//注意这里的逗号
复制代码 我们来注释并分析一下这个新增的代码是在干嘛:
{
itemId: 'cpu-temperatures', //不用动,这是之前修改的那个文档中添加的采集变量
colspan: 2,//不用动
printBar: false,//不用动
title: gettext('CPU温度'),//不用动,显示标题,可以按需改
textField: 'cpu_temperatures',//不用动
renderer:function(value){
const c0 = value.match(/Core 0.*?\+([\d\.]+)?/)[1];
const c1 = value.match(/Core 4.*?\+([\d\.]+)?/)[1];
const c2 = value.match(/Core 8.*?\+([\d\.]+)?/)[1];
const c3 = value.match(/Core 12.*?\+([\d\.]+)?/)[1];
const c4 = value.match(/Core 16.*?\+([\d\.]+)?/)[1];
const c5 = value.match(/Core 20.*?\+([\d\.]+)?/)[1];
const c6 = value.match(/Core 24.*?\+([\d\.]+)?/)[1];
const c7 = value.match(/Core 25.*?\+([\d\.]+)?/)[1];
const c8 = value.match(/Core 26.*?\+([\d\.]+)?/)[1];
const c9 = value.match(/Core 27.*?\+([\d\.]+)?/)[1];
const c10 = value.match(/Core 28.*?\+([\d\.]+)?/)[1];
const c11 = value.match(/Core 29.*?\+([\d\.]+)?/)[1];
const c12 = value.match(/Core 30.*?\+([\d\.]+)?/)[1];
const c13 = value.match(/Core 31.*?\+([\d\.]+)?/)[1];
const p0 = value.match(/Package id 0.*?\+([\d\.]+)?/)[1];
return `Package: ${p0}℃; Core 0: ${c0}℃; Core 4: ${c1}℃; Core 8: ${c2}℃; Core 12: ${c3}℃; Core 16: ${c4}℃; Core 20: ${c5}℃; Core 24: ${c6}℃; Core 25: ${c7}℃; Core 26: ${c8}℃; Cor e 27: ${c9}℃; Core 28: ${c10}℃; Core 29: ${c11}℃; Core 30: ${c12}℃; Core 31: ${c13}℃`
}
},
这里的关键就是这个 renderer 函数返回的内容,也就是最后显示的内容,看这个js的内容,value 这个参数就是我们使用 sensors 命令获取到的所有信息,而下面各种 match 就是去提取信息,所以为什么前面我让在浏览器中调试这些信息的提前,就是为了调试好每个输出的信息。 最后返回了一个字符串,这个里面类似 ${cpu} 就是js语法,使用前面定义的变量去替换里面的内容。 面板高度修改
还需要调整下页面高度,不然会显示不完全。
pvemanagerlib.js中搜索widget.pveNodeStatus就可以看到height: 350,的字眼,对这个350进行修改即可
提示:所以,编写这个文件的内容的时候千万不要无脑复制粘贴,要结合自己查询的信息去调试提取(无非就是改一下正则而已),然后把自己想要显示的内容显示出来。
重启面板查看效果
修改了Nodes.pm文件,需要使用命令行运行下面命令重启API代理守护进程使修改生效,仅修改js文件,无需运行。
- systemctl restart pveproxy
复制代码刷新pve的概要页面,如果正常就能显示出温度信息,如果没有显示,一直在加载,那说明你的语法有错误,可以检查一下前后逗号是否漏了,其他语法可以在控制台或者你自己的node环境调试。 总结 通过这个让 PVE 显示温度的过程,可以非常清晰的了解 PVE 显示额外信息的原理,主要就是两个地方的操作:
- 修改 /usr/share/perl5/PVE/API2/Nodes.pm 文件,添加要执行的采集命令(我甚至觉得这里可以执行脚本来进行更复杂的采集操作,待求证)
- 修改 /usr/share/pve-manager/js/pvemanagerlib.js 文件来从采集命令的输出中提取要显示的信息,然后显示出来,这里是完全的 js 语法,所以可以在本地进行调试。
- 修改完上述两个文件后,重启服务即可 systemctl restart pveproxy
|