PVE 8.3.1安装后的优化
网上PVE优化文章比较比较多,记录一下优化的过程:
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 # 执行完成后,浏览器Ctrl+F5强制刷新缓存
2,更换Debian源:
需修改文件
/etc/apt/sources.list/etc/apt/sources.list.d/ceph.list/etc/apt/sources.list.d/pve-enterprise.list
修改前先备份,以防万一:
mkdir /etc/apt/sources_backup cp /etc/apt/sources.list /etc/apt/sources_backup/sources.list.bak cp /etc/apt/sources.list.d/ceph.list /etc/apt/sources_backup/ceph.list.bak cp /etc/apt/sources.list.d/pve-enterprise.list /etc/apt/sources_backup/pve-enterprise.list.bak
方法一(推荐):
sed -i 's|^deb http://ftp.debian.org|deb https://mirrors.ustc.edu.cn|g' /etc/apt/sources.list sed -i 's|^deb http://security.debian.org|deb https://mirrors.ustc.edu.cn/debian-security|g' /etc/apt/sources.list
方法二:
wget --no-check-certificate https://v2rayssr.com/tool/yuan.sh -O yuan.sh && chmod +x yuan.sh && ./yuan.sh
如果以上脚本失效,可以自己编写:
#!/bin/bash dir="/etc/apt/sources.list.d/" file="/etc/apt/sources.list" if [ -d "$dir" ]; then echo "Deleting directory $dir..." rm -rf "$dir" echo "Directory deleted." else echo "Directory $dir does not exist. Skipping deletion." fi echo "Replacing content of $file..." echo "deb https://mirrors.ustc.edu.cn/debian/ bookworm main contrib non-free non-free-firmware" > "$file" echo "deb https://mirrors.ustc.edu.cn/debian/ bookworm-updates main contrib non-free non-free-firmware" >> "$file" echo "deb https://mirrors.ustc.edu.cn/debian/ bookworm-backports main contrib non-free non-free-firmware" >> "$file" echo "deb https://mirrors.ustc.edu.cn/debian-security bookworm-security main" >> "$file" echo "deb https://mirrors.ustc.edu.cn/proxmox/debian bookworm pve-no-subscription" >> "$file" echo "Content replaced."
3,pve页面上显示cpu、磁盘等温度、频率、功率等信息

wget --no-check-certificate -c https://raw.githubusercontent.com/a904055262/PVE-manager-status/main/showtempcpufreq.sh && chmod +x showtempcpufreq.sh && ./showtempcpufreq.sh
同样,如果以上脚本失效,自行编写:
#!/usr/bin/env bash
# version: 2023.9.5
#添加硬盘信息的控制变量,如果你想不显示硬盘信息就设置为false
#NVME硬盘
sNVMEInfo=true
#固态和机械硬盘
sODisksInfo=true
#debug,显示修改后的内容,用于调试
dmode=false
#脚本路径
sdir=$(cd "$(dirname "${BASH_SOURCE[0]}")"; pwd)
cd "$sdir"
sname=$(basename "${BASH_SOURCE[0]}")
sap=$sdir/$sname
echo 脚本路径:"$sap"
#需要修改的文件
np=/usr/share/perl5/PVE/API2/Nodes.pm
pvejs=/usr/share/pve-manager/js/pvemanagerlib.js
plibjs=/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js
if ! command -v sensors > /dev/null; then
echo 你需要先安装 lm-sensors 和 linux-cpupower,脚本尝试给你自动安装
if apt update ; apt install -y lm-sensors; then
echo lm-sensors 安装成功
echo 尝试继续安装linux-cpupower获取功耗信息
if apt install -y linux-cpupower;then
echo linux-cpupower安装成功
else
echo -e "linux-cpupower安装失败,可能无法正常获取功耗信息,你可以使用\033[34mapt update ; apt install linux-cpupower && modprobe msr && echo msr > /etc/modules-load.d/turbostat-msr.conf && chmod +s /usr/sbin/turbostat && echo 成功!\033[0m 手动安装"
fi
else
echo 脚本自动安装所需依赖失败
echo -e "请使用蓝色命令:\033[34mapt update ; apt install -y lm-sensors linux-cpupower && chmod +s /usr/sbin/turbostat && echo 成功! \033[0m 手动安装后重新运行本脚本"
echo 脚本退出
exit 1
fi
fi
#获取版本号
pvever=$(pveversion | awk -F"/" '{print $2}')
echo "你的PVE版本号:$pvever"
restore() {
[ -e $np.$pvever.bak ] && mv $np.$pvever.bak $np
[ -e $pvejs.$pvever.bak ] && mv $pvejs.$pvever.bak $pvejs
[ -e $plibjs.$pvever.bak ] && mv $plibjs.$pvever.bak $plibjs
}
fail() {
echo "修改失败,可能不兼容你的pve版本:$pvever,开始还原"
restore
echo 还原完成
exit 1
}
#还原修改
case $1 in
restore)
restore
echo 已还原修改
if [ "$2" != 'remod' ];then
echo -e "请刷新浏览器缓存:\033[31mShift+F5\033[0m"
systemctl restart pveproxy
else
echo -----
fi
exit 0
;;
remod)
echo 强制重新修改
echo -----------
"$sap" restore remod > /dev/null
"$sap"
exit 0
;;
esac
#检测是否已经修改过
[ $(grep 'modbyshowtempfreq' $np $pvejs $plibjs | wc -l) -eq 3 ] && {
echo -e "
已经修改过,请勿重复修改
如果没有生效,或者页面一直转圈圈
请使用 \033[31mShift+F5\033[0m 刷新浏览器缓存
如果一直异常,请执行:\033[31m\"$sap\" restore\033[0m 命令,可以还原修改
如果想强制重新修改,请执行:\033[31m\"$sap\" remod\033[0m 命令,可以还原修改
"
exit 1
}
contentfornp=/tmp/.contentfornp.tmp
[ -e /usr/sbin/turbostat ] && {
modprobe msr
chmod +s /usr/sbin/turbostat
}
echo msr > /etc/modules-load.d/turbostat-msr.conf
cat > $contentfornp << 'EOF'
#modbyshowtempfreq
$res->{thermalstate} = `sensors -A`;
$res->{cpuFreq} = `
goverf=/sys/devices/system/cpu/cpufreq/policy0/scaling_governor
maxf=/sys/devices/system/cpu/cpufreq/policy0/cpuinfo_max_freq
minf=/sys/devices/system/cpu/cpufreq/policy0/cpuinfo_min_freq
cat /proc/cpuinfo | grep -i "cpu mhz"
echo -n 'gov:'
[ -f \$goverf ] && cat \$goverf || echo none
echo -n 'min:'
[ -f \$minf ] && cat \$minf || echo none
echo -n 'max:'
[ -f \$maxf ] && cat \$maxf || echo none
echo -n 'pkgwatt:'
[ -e /usr/sbin/turbostat ] && turbostat --quiet --cpu package --show "PkgWatt" -S sleep 0.25 2>&1 | tail -n1
`;
EOF
contentforpvejs=/tmp/.contentforpvejs.tmp
cat > $contentforpvejs << 'EOF'
//modbyshowtempfreq
{
itemId: 'thermal',
colspan: 2,
printBar: false,
title: gettext('温度(°C)'),
textField: 'thermalstate',
renderer:function(value){
//value进来的值是有换行符的
console.log(value)
let b = value.trim().split(/\s+(?=^\w+-)/m).sort();
let c = b.map(function (v){
// 风扇转速数据,直接返回
let fandata = v.match(/(?<=:\s+)[1-9]\d*(?=\s+RPM\s+)/ig)
if ( fandata ) {
return '风扇: ' + fandata.join(';')
}
let name = v.match(/^[^-]+/)[0].toUpperCase();
let temp = v.match(/(?<=:\s+)[+-][\d.]+(?=.?°C)/g);
// 某些没有数据的传感器,不是温度的传感器
if ( temp ) {
temp = temp.map(v => Number(v).toFixed(0))
if (/coretemp/i.test(name)) {
name = 'CPU';
temp = temp[0] + ( temp.length > 1 ? ' ( ' + temp.slice(1).join(' | ') + ' )' : '');
} else {
temp = temp[0];
}
let crit = v.match(/(?<=\bcrit\b[^+]+\+)\d+/);
return name + ': ' + temp + ( crit? ` ,crit: ${crit[0]}` : '');
} else {
return 'null'
}
});
console.log(c);
// 排除null值的
c=c.filter( v => ! /^null$/.test(v) )
//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;
console.log(v);
let m = v.match(/(?<=^cpu[^\d]+)\d+/img);
let m2 = m.map( e => ( e / 1000 ).toFixed(1) );
m2 = m2.join(' | ');
let gov = v.match(/(?<=^gov:).+/im)[0].toUpperCase();
let min = (v.match(/(?<=^min:).+/im)[0]);
if ( min !== 'none' ) {
min=(min/1000000).toFixed(1);
}
let max = (v.match(/(?<=^max:).+/im)[0])
if ( max !== 'none' ) {
max=(max/1000000).toFixed(1);
}
let watt= v.match(/(?<=^pkgwatt:)[\d.]+$/im);
watt = watt? " | 功耗: " + (watt[0]/1).toFixed(1) + 'W' : '';
return `${m2} | MAX: ${max} | MIN: ${min}${watt} | 调速器: ${gov}`
}
},
EOF
#检测nvme硬盘
echo 检测系统中的NVME硬盘
nvi=0
if $sNVMEInfo;then
for nvme in $(ls /dev/nvme[0-9] 2> /dev/null); do
chmod +s /usr/sbin/smartctl
cat >> $contentfornp << EOF
\$res->{nvme$nvi} = \`smartctl $nvme -a -j\`;
EOF
cat >> $contentforpvejs << 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;then
for sd in $(ls /dev/sd[a-z] 2> /dev/null);do
chmod +s /usr/sbin/smartctl
chmod +s /usr/sbin/hdparm
#检测是否是真的机械键盘
sdsn=$(awk -F '/' '{print $NF}' <<< $sd)
sdcr=/sys/block/$sdsn/queue/rotational
[ -f $sdcr ] || continue
if [ "$(cat $sdcr)" = "0" ];then
hddisk=false
sdtype="固态硬盘$sdi"
else
hddisk=true
sdtype="机械硬盘$sdi"
fi
#[] && 型条件判断,嵌套的条件判断的非 || 后面一定要写动作,否则会穿透到上一层的非条件
#机械/固态硬盘输出信息逻辑,
#如果硬盘不存在就输出空JSON
cat >> $contentfornp << EOF
\$res->{sd$sdi} = \`
if [ -b $sd ];then
if $hddisk && hdparm -C $sd | grep -iq 'standby';then
echo '{"standy": true}'
else
smartctl $sd -a -j
fi
else
echo '{}'
fi
\`;
EOF
cat >> $contentforpvejs << 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);
console.log(v)
if (v.standy === true) {
return '休眠中'
}
//名字
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 ! grep -q 'modbyshowtempfreq' $np ;then
[ ! -e $np.$pvever.bak ] && cp $np $np.$pvever.bak
if [ "$(sed -n "/PVE::pvecfg::version_text()/{=;p;q}" "$np")" ];then #确认修改点
#r追加文本后面必须跟回车,否则r 后面的文字都会被当成文件名,导致脚本出错
sed -i "/PVE::pvecfg::version_text()/{
r $contentfornp
}" $np
$dmode && sed -n "/PVE::pvecfg::version_text()/,+5p" $np
else
echo '找不到nodes.pm文件的修改点'
fail
fi
else
echo 已经修改过
fi
echo 开始修改pvemanagerlib.js文件
if ! grep -q 'modbyshowtempfreq' $pvejs ;then
[ ! -e $pvejs.$pvever.bak ] && cp $pvejs $pvejs.$pvever.bak
if [ "$(sed -n '/pveversion/,+3{
/},/{=;p;q}
}' $pvejs)" ];then
sed -i "/pveversion/,+3{
/},/r $contentforpvejs
}" $pvejs
$dmode && sed -n "/pveversion/,+8p" $pvejs
else
echo '找不到pvemanagerlib.js文件的修改点'
fail
fi
echo 修改页面高度
#统计加了几条
addRs=$(grep -c '\$res' $contentfornp)
addHei=$(( 28 * addRs))
$dmode && 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 && 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 && sed -n '/nodeStatus:\s*nodeStatus/,+10{
/minHeight/{
p;q
}
}' $pvejs
else
echo 右边栏高度找不到修改点,修改失败
fi
else
echo 找不到修改高度的修改点
fail
fi
else
echo 已经修改过
fi
echo 温度,频率,硬盘信息相关修改已完成
echo ------------------------
echo ------------------------
echo 开始修改proxmoxlib.js文件
echo 去除订阅弹窗
if ! grep -q 'modbyshowtempfreq' $plibjs ;then
[ ! -e $plibjs.$pvever.bak ] && cp $plibjs $plibjs.$pvever.bak
if [ "$(sed -n '/\/nodes\/localhost\/subscription/{=;p;q}' $plibjs)" ];then
sed -i '/\/nodes\/localhost\/subscription/,+10{
/res === null/{
N
s/(.*)/(false)/
a //modbyshowtempfreq
}
}' $plibjs
$dmode && sed -n "/\/nodes\/localhost\/subscription/,+10p" $plibjs
else
echo 找不到修改点,放弃修改这个
fi
else
echo 已经修改过
fi
echo -e "------------------------
修改完成
请刷新浏览器缓存:\033[31mShift+F5\033[0m
如果你看到主页面提示连接错误或者没看到温度和频率,请按:\033[31mShift+F5\033[0m,刷新浏览器缓存!
如果你对效果不满意,请执行:\033[31m\"$sap\" restore\033[0m 命令,可以还原修改
"
systemctl restart pveproxy
4,CT 模板换源
需修改文件:
/usr/share/perl5/PVE/APLInfo.pm
用如下指令修改,把 APLInfo.pm 里所有 http://download.proxmox.com 替换成中科大的镜像
#先备份以防万一 cp /usr/share/perl5/PVE/APLInfo.pm /usr/share/perl5/PVE/APLInfo.pm.bak sed -i 's|http://download.proxmox.com|https://mirrors.ustc.edu.cn/proxmox|g' /usr/share/perl5/PVE/APLInfo.pm
具体变更的内容如下所示
--- a/usr/share/perl5/PVE/APLInfo.pm.bak
+++ b/usr/share/perl5/PVE/APLInfo.pm
@@ -197,7 +197,7 @@ sub get_apl_sources {
my $sources = [
{
host => "download.proxmox.com",
- url => "http://download.proxmox.com/images",
+ url => "https://mirrors.ustc.edu.cn/proxmox/images",
file => 'aplinfo-pve-8.dat',
},
{
注意这里的 host 属性是不能修改的,只改 url 就好
重启下 pvedaemon.service,刷新下 web 页面,完事
systemctl restart pvedaemon.service
5,pve-enterprise.list
把 pve-enterprise.list 的企业源扬了。毕竟这个企业源得订阅了才能用,没订阅意味着没用
echo "" > /etc/apt/sources.list.d/pve-enterprise.list
(可选)如果没有订阅,却依然想要一个可以更新 PVE 的源,可以用 PVE 的 pve-no-subscription 源。可以用如下指令添加
echo "deb https://mirrors.ustc.edu.cn/proxmox/debian/pve bookworm pve-no-subscription" > /etc/apt/sources.list.d/pve-no-subscription.list
如文档所述,这个源的 PVE 软件包是作为企业源的上游源,可能相对不那么的稳定
6,ceph.list
这个原文件就一行,直接覆盖了完事
echo "deb https://mirrors.ustc.edu.cn/proxmox/debian/ceph-quincy bookworm no-subscription" > /etc/apt/sources.list.d/ceph.list
这里,我这里用了 no-subscription,但中科大文档里用的是 pve-no-subscription,原因是 中科院源里 里只有叫个 no-subscription 子目录,并没有 pve-no-subscription,因此得根据情况改一下
7,扩充root分区,删除lvm-thin
直接参考:https://www.cnblogs.com/airoot/p/18721178
8,工具推荐
pve_source
Pve Tools:https://github.com/ivanhao/pvetools
其他参考链接:
https://pkernel.com/?p=1415
https://bozai.me/pve-install.html
https://bozai.me/pve.html
https://blog.fallenbreath.me/zh-CN/2023/pve8-change-sourceslist/

浙公网安备 33010602011771号