PVE基础环境配置


PVE删除local-LVM存储空间合并到local中

合并存储
1
2
3
#删除local-lvm存储空间后合并
lvremove pve/data
lvextend -l +100%FREE -r pve/root
web界面删除local-lvm

数据中心—存储—删除local-lvm

编辑local,内容里勾选添加 磁盘映像和容器

PVE换国内源

PVE换源
1
2
3
wget https://mirrors.ustc.edu.cn/proxmox/debian/proxmox-release-bullseye.gpg -O /etc/apt/trusted.gpg.d/proxmox-release-bullseye.gpg
echo "#deb https://enterprise.proxmox.com/debian/pve bullseye pve-enterprise" > /etc/apt/sources.list.d/pve-enterprise.list
echo "deb https://mirrors.ustc.edu.cn/proxmox/debian/pve bullseye pve-no-subscription" > /etc/apt/sources.list.d/pve-no-subscription.list
Debian换源
1
2
mv /etc/apt/sources.list /etc/apt/sources.list.bk
vi /etc/apt/sources.list

Sources.list加入源

1
2
3
4
5
6
7
8
deb https://mirrors.ustc.edu.cn/debian/ bullseye main non-free contrib
deb-src https://mirrors.ustc.edu.cn/debian/ bullseye main non-free contrib
deb https://mirrors.ustc.edu.cn/debian-security/ bullseye-security main
deb-src https://mirrors.ustc.edu.cn/debian-security/ bullseye-security main
deb https://mirrors.ustc.edu.cn/debian/ bullseye-updates main non-free contrib
deb-src https://mirrors.ustc.edu.cn/debian/ bullseye-updates main non-free contrib
deb https://mirrors.ustc.edu.cn/debian/ bullseye-backports main non-free contrib
deb-src https://mirrors.ustc.edu.cn/debian/ bullseye-backports main non-free contrib
更新
1
2
apt update
apt upgrade -y
CT模板换源
1
2
cp /usr/share/perl5/PVE/APLInfo.pm /usr/share/perl5/PVE/APLInfo.pm_back
sed -i 's|http://download.proxmox.com|https://mirrors.tuna.tsinghua.edu.cn/proxmox|g' /usr/share/perl5/PVE/APLInfo.pm

重启服务

1
systemctl restart pvedaemon.service

PVE vi 编辑器方向键出现ABCD乱码

方法一: 更新PVE, 卸载pve 自带的vim编辑器,重新安装

1
2
3
apt-get update -y
apt-get remove vim-common -y #卸载原有的vim 编辑器
apt-get install vim -y #重新安装vim 编辑器

方法二:vi /etc/vim/vimrc.tiny

修改set compatible 为 set nocompatible,并在下一行添加set backspace=2

PVE删除订阅弹窗提醒

1
vi /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js

输入英文/ ,搜索data.status,把if(data.status!==’Active’) 修改为if(false),大概在381行

针对6.3版本到7版本,可以执行

1
sed -Ezi.bak "s/(Ext.Msg.show\(\{\s+title: gettext\('No valid sub)/void\(\{ \/\/\1/g" /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js && systemctl restart pveproxy.service

针对7.2-3版本,可以执行

1
sed -i.bak "s/data.status.toLowerCase() !== 'active'/false/g" /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js

给PVE增加温度、CPU频率显示,NVME,机械固态硬盘信息,删订阅弹窗提醒

脚本自动检测:一键给PVE增加温度和cpu频率显示,NVME,机械固态硬盘信息

  • 理论上适合任何设备
  • 自动适配传感器数据
  • 自动检测NVME硬盘数量
  • 自动检测机械,固态硬盘数量
  • 自动检测CPU核心数量

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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
#!/usr/bin/env bash

#添加硬盘信息的控制变量,如果你想不显示硬盘信息就设置为0
#NVME硬盘
sNVMEInfo=1
#固态和机械硬盘
sODisksInfo=1
#debug,显示修改后的内容,用于调试
dmode=0

#脚本路径
sdir=$(cd $(dirname ${BASH_SOURCE[0]}); pwd)
cd "$sdir"
sname=`awk -F '/' '{print $NF}' <<< ${BASH_SOURCE[0]}`
sap=$sdir/$sname
echo "脚本路径:$sap"

#需要修改的文件
np="/usr/share/perl5/PVE/API2/Nodes.pm"
pvejs="/usr/share/pve-manager/js/pvemanagerlib.js"
plib="/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js"

if ! command -v sensors > /dev/null 2>&1; then
echo 你需要先安装lm-sensors,脚本尝试给你自动安装
if apt update && apt install -y lm-sensors; then
echo 安装lm-sensors成功,脚本继续执行
else
echo 脚本安装lm-sensors失败,请手动安装后继续执行本脚本
echo 脚本退出
exit 1
fi
fi

#获取版本号
pvever=`pveversion | awk -F"/" '{print $2}'`
echo "你的PVE版本号:$pvever"

backup() {
cp "$np" "$np.$pvever.bak"
cp "$pvejs" "$pvejs.$pvever.bak"
cp "$plib" "$plib.$pvever.bak"
}

restore() {
mv "$np.$pvever.bak" "$np"
mv "$pvejs.$pvever.bak" "$pvejs"
mv "$plib.$pvever.bak" "$plib"
}

fail() {
echo "修改失败,可能不兼容你的pve版本:$pvever,开始还原"
restore
echo 还原完成
exit 1
}

#还原修改
case "$1" in
restore)
if [ -e "$np.$pvever.bak" ];then
restore
echo 已还原修改

if [ "$2" != 'remod' ];then
echo -e "请刷新浏览器缓存:\033[31mShift+F5\033[0m"
systemctl restart pveproxy
else
echo -----
fi
else
echo 文件没有被修改过
fi

exit 0
;;
remod)
echo 强制重新修改
echo -----------
"$sap" restore remod
"$sap"
exit 0
;;
esac

#检测是否已经修改过
[ -e "$np.$pvever.bak" ] && {
echo -e "
已经修改过,请勿重复修改
如果没有生效,或者页面一直转圈圈
请使用 \033[31mShift+F5\033[0m 刷新浏览器缓存
如果一直异常,请执行:\033[31m\"$sap\" restore\033[0m 命令,可以还原修改
"
exit 1
}

echo 备份源文件
backup


tmpf0=.dfadfasdf.tmp

cat > $tmpf0 << 'EOF'
$res->{thermalstate} = `sensors -A`;
$res->{cpuFreq} = `
cat /proc/cpuinfo | grep -i "cpu mhz"
echo -n 'gov:'
cat /sys/devices/system/cpu/cpufreq/policy0/scaling_governor
echo -n 'min:'
cat /sys/devices/system/cpu/cpufreq/policy0/cpuinfo_min_freq
echo -n 'max:'
cat /sys/devices/system/cpu/cpufreq/policy0/cpuinfo_max_freq
`;
EOF


tmpf=.sdfadfasdf.tmp

cat > $tmpf << 'EOF'
{
itemId: 'thermal',
colspan: 2,
printBar: false,
title: gettext('温度(°C)'),
textField: 'thermalstate',
renderer:function(value){
//value进来的值是有换行符的

let b = value.trim().split(/\s+(?=^\w+-)/m).sort();
let c = b.map(function (v){
let name = v.match(/^[^-]+/)[0].toUpperCase();

let temp = v.match(/(?<=:\s+\+?)-?\d+/g);

if (/coretemp/i.test(name)) {
name = 'CPU';
temp = temp[0] + ' ( ' + temp.slice(1).join(' | ') + ' )';
} else {
temp = temp[0];
}

let crit = v.match(/(?<=\bcrit\b[^+]+\+)\d+/);


return name + ': ' + temp + ( crit? ` ,crit: ${crit[0]}` : '');
});

//console.log(c);
//排序,把cpu温度放最前
let cpuIdx = c.findIndex(v => /CPU/i.test(v) );
if (cpuIdx > 0) {
c.unshift(c.splice(cpuIdx, 1)[0]);
}

// console.log(c)
c = c.join(' | ');
return c;
}
},
{
itemId: 'cpumhz',
colspan: 2,
printBar: false,
title: gettext('CPU频率(GHz)'),
textField: 'cpuFreq',
renderer:function(v){
//return v;
let m = v.match(/(?<=cpu[^\d]+)\d+/ig);
let m2 = m.map( e => ( e / 1000 ).toFixed(1) );
m2 = m2.join(' | ');
let gov = v.match(/(?<=gov:\s*).+/i)[0].toUpperCase();
let min = (v.match(/(?<=min[^\d+]+)\d+/i)[0]/1000000).toFixed(1);
let max = (v.match(/(?<=max[^\d+]+)\d+/i)[0]/1000000).toFixed(1);
return `${m2} | MAX: ${max} | MIN: ${min} | 调速器: ${gov}`
}
},
EOF


#检测nvme硬盘
echo 检测系统中的NVME硬盘
nvi=0
if [ $sNVMEInfo -eq 1 ] && ls /dev/nvme[0-9] >/dev/null 2>&1;then
for nvme in `ls /dev/nvme[0-9]`; do
chmod +s /usr/sbin/smartctl
#echo '$res->{nvme'"$nvi"'} = `smartctl '"$nvme"' -a -j`;' >> $tmpf0

cat >> $tmpf0 << EOF
\$res->{nvme$nvi} = \`smartctl $nvme -a -j\`;
EOF


cat >> $tmpf << EOF
{
itemId: 'nvme${nvi}0',
colspan: 2,
printBar: false,
title: gettext('NVME${nvi}'),
textField: 'nvme${nvi}',
renderer:function(value){
//return value;
try{
let v = JSON.parse(value);
//名字
let model = v.model_name;
if (! model) {
return '找不到硬盘,直通或已被卸载';
}
// 温度
let temp = v.temperature?.current;
temp = ( temp !== undefined ) ? " | " + temp + '°C' : '' ;

// 通电时间
let pot = v.power_on_time?.hours;
let poth = v.power_cycle_count;

pot = ( pot !== undefined ) ? (" | 通电: " + pot + '时' + ( poth ? ',次: '+ poth : '' )) : '';

// 读写
let log = v.nvme_smart_health_information_log;
let rw=''
let health=''
if (log) {
let read = log.data_units_read;
let write = log.data_units_written;
read = read ? (log.data_units_read / 1956882).toFixed(1) + 'T' : '';
write = write ? (log.data_units_written / 1956882).toFixed(1) + 'T' : '';
if (read && write) {
rw = ' | R/W: ' + read + '/' + write;
}
let pu = log.percentage_used;
let me = log.media_errors;
if ( pu !== undefined ) {
health = ' | 健康: ' + ( 100 - pu ) + '%'
if ( me !== undefined ) {
health += ',0E: ' + me
}
}
}

// smart状态
let smart = v.smart_status?.passed;
if (smart === undefined ) {
smart = '';
} else {
smart = ' | SMART: ' + (smart ? '正常' : '警告!');
}


let t = model + temp + health + pot + rw + smart;
//console.log(t);
return t;
}catch(e){
return '无法获得有效消息';
};

}
},
EOF
let nvi++
done
fi
echo "已添加 $nvi 块NVME硬盘"



#检测机械键盘
echo 检测系统中的SATA固态和机械硬盘
sdi=0
if [ $sODisksInfo -eq 1 ] && ls /dev/sd[a-z] >/dev/null 2>&1;then
for sd in `ls /dev/sd[a-z]`;do
chmod +s /usr/sbin/smartctl
#检测是否是真的机械键盘
sdsn=`echo $sd | awk -F '/' '{print $NF}'`
sdcr=/sys/block/$sdsn/queue/rotational
sdtype="机械硬盘$sdi"

if [ ! -e $sdcr ];then
continue
else
if [ "`cat $sdcr`" -eq 0 ];then
sdtype="固态硬盘$sdi"
fi
fi

#[] && 型条件判断,嵌套的条件判断的非 || 后面一定要写动作,否则会穿透到上一层的非条件
#机械/固态硬盘输出信息逻辑,
#如果硬盘不存在就输出空JSON

cat >> $tmpf0 << EOF
\$res->{sd$sdi} = \`
if [ -b $sd ];then
smartctl $sd -a -j
else
echo '{}'
fi
\`;
EOF

cat >> $tmpf << EOF
{
itemId: 'sd${sdi}0',
colspan: 2,
printBar: false,
title: gettext('${sdtype}'),
textField: 'sd${sdi}',
renderer:function(value){
//return value;
try{
let v = JSON.parse(value);
//名字
let model = v.model_name;
if (! model) {
return '找不到硬盘,直通或已被卸载';
}
// 温度
let temp = v.temperature?.current;
temp = ( temp !== undefined ) ? " | 温度: " + temp + '°C' : '' ;

// 通电时间
let pot = v.power_on_time?.hours;
let poth = v.power_cycle_count;

pot = ( pot !== undefined ) ? (" | 通电: " + pot + '时' + ( poth ? ',次: '+ poth : '' )) : '';

// smart状态
let smart = v.smart_status?.passed;
if (smart === undefined ) {
smart = '';
} else {
smart = ' | SMART: ' + (smart ? '正常' : '警告!');
}


let t = model + temp + pot + smart;
//console.log(t);
return t;
}catch(e){
return '无法获得有效消息';
};
}
},
EOF
let sdi++
done
fi
echo "已添加 $sdi 块SATA固态和机械硬盘"



echo 开始修改nodes.pm文件
if [ "$(sed -n "/PVE::pvecfg::version_text()/{=;p;q}" "$np")" ];then #确认修改点
#r追加文本后面必须跟回车,否则r 后面的文字都会被当成文件名,导致脚本出错
sed -i "/PVE::pvecfg::version_text()/{
r $tmpf0
}" "$np"
[ $dmode -eq 1 ] && sed -n "/PVE::pvecfg::version_text()/,+5p" "$np"
else
echo '找不到nodes.pm文件的修改点'

fail
fi


echo 开始修改pvemanagerlib.js文件
if [ "$(sed -n '/pveversion/,+3{
/},/{=;p;q}
}' "$pvejs")" ];then

sed -i "/pveversion/,+3{
/},/r $tmpf
}" "$pvejs"

[ $dmode -eq 1 ] && sed -n "/pveversion/,+8p" "$pvejs"
else
echo '找不到pvemanagerlib.js文件的修改点'
fail
fi

echo 修改页面高度
#统计加了几条
addRs=`grep -c '\$res' $tmpf0`
addHei=$(( 28 * addRs))
[ $dmode -eq 1 ] && echo "添加了$addRs条内容,增加高度为:${addHei}px"


#原高度300
echo 修改左栏高度
if [ "$(sed -n '/widget.pveNodeStatus/,+4{
/height:/{=;p;q}
}' "$pvejs")" ]; then

#获取原高度
wph=$(sed -n -E "/widget\.pveNodeStatus/,+4{
/height:/{s/[^0-9]*([0-9]+).*/\1/p;q}
}" "$pvejs")

sed -i -E "/widget\.pveNodeStatus/,+4{
/height:/{
s#[0-9]+#$(( wph + addHei))#
}
}" "$pvejs"

[ $dmode -eq 1 ] && sed -n '/widget.pveNodeStatus/,+4{
/height/{
p;q
}
}' "$pvejs"

#修改右边栏高度,让它和左边一样高,双栏的时候否则导致浮动出问题
#原高度325
echo 修改右栏高度和左栏一致,解决浮动错位
if [ "$(sed -n '/nodeStatus:\s*nodeStatus/,+10{
/minHeight:/{=;p;q}
}' "$pvejs")" ]; then
#获取原高度
nph=$(sed -n -E '/nodeStatus:\s*nodeStatus/,+10{
/minHeight:/{s/[^0-9]*([0-9]+).*/\1/p;q}
}' "$pvejs")

sed -i -E "/nodeStatus:\s*nodeStatus/,+10{
/minHeight:/{
s#[0-9]+#$(( nph + addHei - (nph - wph) ))#
}
}" "$pvejs"

[ $dmode -eq 1 ] && sed -n '/nodeStatus:\s*nodeStatus/,+10{
/minHeight/{
p;q
}
}' "$pvejs"

else
echo 右边栏高度找不到修改点,修改失败

fi

else
echo 找不到修改高度的修改点
fail
fi

echo 温度,频率,硬盘信息相关修改已完成
echo ------------------------
echo ------------------------
echo 开始修改proxmoxlib.js文件
echo 去除订阅弹窗

if [ "$(sed -n '/\/nodes\/localhost\/subscription/{=;p;q}' "$plib")" ];then
sed -i '/\/nodes\/localhost\/subscription/,+10{
/res === null/{
N
s/(.*)/(false)/
}
}' "$plib"

[ $dmode -eq 1 ] && sed -n "/\/nodes\/localhost\/subscription/,+10p" "$plib"
else
echo 找不到修改点,放弃修改这个
fi

echo -e "------------------------
修改完成
请刷新浏览器缓存:\033[31mShift+F5\033[0m
如果你看到主页面提示连接错误或者没看到温度和频率,请按:\033[31mShift+F5\033[0m,刷新浏览器缓存!
如果你对效果不满意,请执行:\033[31m\"$sap\" restore\033[0m 命令,可以还原修改
"

systemctl restart pveproxy

使用方法

每次pve升级之后都需要执行一次脚本,因为升级后PVE会自己还原文件

1
2
3
将上述脚本复制并命名showtempcpufreq.sh
chmod +x showtempcpufreq.sh #赋予脚本执行权限
./showtempcpufreq.sh

如果修改后不满意,后悔,请输入:

1
./showtempcpufreq.sh restore

更新脚本后,想重新应用脚本更新带来的新效果,请输入:

1
./showtempcpufreq.sh remod

如果你已经用别人的脚本之类的修改过页面,请先用下面命令先回复官方设置之后,才可以运行本脚本

1
apt update && apt reinstall pve-manager

开IOMMU硬件直通

1
2
3
4
5
6
7
8
9
10
11
12
#编辑grub,请不要盲目改。根据自己的环境,选择设置
vi /etc/default/grub
#在里面找到:
GRUB_CMDLINE_LINUX_DEFAULT="quiet"
#然后修改为:
GRUB_CMDLINE_LINUX_DEFAULT="quiet intel_iommu=on iommu=pt"
#如果是amd cpu请改为:
GRUB_CMDLINE_LINUX_DEFAULT="quiet amd_iommu=on iommu=pt"
#如果是需要显卡直通,建议在cmdline再加一句video=vesafb:off video=efifb:off video=simplefb:off,加了之后,pve重启进内核后停留在一个画面,这是正常情况
GRUB_CMDLINE_LINUX_DEFAULT="quiet amd_iommu=on iommu=pt video=vesafb:off video=efifb:off video=simplefb:off"
#如果你的pcie设备分组有问题也可以换成这一行对分组拆分(直通遇到问题都可以尝试这个)
GRUB_CMDLINE_LINUX_DEFAULT="quiet intel_iommu=on pcie_acs_override=downstream"

修改完成之后,直接更新后重启

1
2
3
update-grub
update-initramfs -u
reboot

注意:如果此方法还不能开启iommu,请修改 /etc/kernel/cmdline文件,并且使用proxmox-boot-tool refresh 更新启动项。

验证是否开启iommu

重启之后,在终端输入

1
dmesg | grep iommu

出现如下例子。则代表成功

1
2
3
4
5
[ 1.341100] pci 0000:00:00.0: Adding to iommu group 0
[ 1.341116] pci 0000:00:01.0: Adding to iommu group 1
[ 1.341126] pci 0000:00:02.0: Adding to iommu group 2
[ 1.341137] pci 0000:00:14.0: Adding to iommu group 3
[ 1.341146] pci 0000:00:17.0: Adding to iommu group 4

此时输入命令

1
2
find /sys/kernel/iommu_groups/ -type l 
#出现很多直通组,就代表成功了。如果没有任何东西,就是没有开启