9.7 KiB
2026-07-18
ServerStack: 修复 Ubuntu 依赖安装的 libcurl 冲突
问题:在 Ubuntu 22.04 上跑 installDepsUbuntu 时出现
- 图片 1:
libcurl4-gnutls-dev与libcurl4-openssl-dev互相 Conflicts,导致E: Unable to correct problems, you have held broken packages,整批依赖装不下去。 - 图片 2: 大量老包被
filter_pkglist跳过(libpng12-0/-dev、libpng3、libidn11、libcloog-ppl1、sysv-rc、libjpeg62-turbo-dev),虽然不报错, 但每次都刷一堆Skip unavailable package: ...噪音。
根因:lib/check_sw.sh 的 installDepsUbuntu(line 119)的 pkgList
同时列了 libcurl4-gnutls-dev 和 libcurl4-openssl-dev 这两个互斥的 -dev 包。
注释里说"Modern Debian/Ubuntu removed several legacy package names",但实际
pkgList 自身并没有清理这些老包。
修复(E:\workbuddy\ServerStack\lib\check_sw.sh,仅改 Ubuntu 列表 line 119):
- 删掉
libcurl4-gnutls-dev(保留libcurl3-gnutls这个 runtime)。 依据:modules/php/php-7.4.sh、php-8.0.sh、php-8.1.sh全部用libcurl4-openssl-dev,没有任何地方用 gnutls dev。 - 顺手清理在新版 Ubuntu 上永远被 filter 跳过的死链包:
libjpeg62-turbo-dev、libpng12-0/-dev、libpng3、libidn11、libcloog-ppl1、sysv-rc。libidn11-dev保留(仍可用),Debian 分支的 列表不动(不同发行版软件源不同)。 - 加了一段说明注释,避免后人重新加回
libcurl4-gnutls-dev。
验证:bash -n 通过;图片 1 的冲突不会再出现,图片 2 的 Skip 噪音也基本清零。
补充:用户反馈同样的报错仍在出现
用户第二轮贴出完全相同的报错文本(含 7.81.0-1ubuntu1.25 版本号和
No VM guests are running outdated hypervisor (qemu) 这条云 VM 特征消息)。
排查结论:
- 本地
lib/check_sw.sh的 Ubuntu 列表(line 141)已经是干净的,没有libcurl4-gnutls-dev。 backup/、runtime/都是空目录,全项目只有一份check_sw.sh,没有其它副本。- 报错来自远程 Ubuntu 22.04 服务器上跑的旧版脚本,本地修改还没同步过去。
加防御层(filter_pkglist() 末尾,line 33-47)
为了即使旧版 pkgList 被部署上去也不炸,在 filter_pkglist() 末尾加了一段
互斥冲突消解:检测列表里同时有 libcurl4-gnutls-dev 和 libcurl4-openssl-dev
时,自动 sed 摘掉 gnutls dev 版,保留 openssl 版(PHP 各模块用的就是它),
libcurl3-gnutls runtime 不动。
隔离测试通过:libcurl3-gnutls 保留 / libcurl4-openssl-dev 保留 /
libcurl4-gnutls-dev 被移除。bash -n 语法通过。
给用户的行动项
需要把更新后的 lib/check_sw.sh 重新同步到服务器(rsync/scp/git pull 等),
然后重跑安装。同步后两层防护都会生效:
- Ubuntu 列表源头已无
libcurl4-gnutls-dev(也不会再有 Skip 噪音)。 - 即便将来有人把互斥包加回去,
filter_pkglist会自动摘掉。
第三轮:修复"卡很久"的黑屏问题
用户反馈"在运行到此处时会卡很久"。分析 install_pkgs() 的卡顿来源:
- 批量 apt-get 遇冲突时静默求解:apt 的依赖求解器遇到
libcurl4-gnutls-devvslibcurl4-openssl-dev互斥时,会花 30s~2min 尝试各种组合才放弃,期间 无任何输出,看起来像冻住。 - 逐包回退循环全静默:批量失败后循环 ~60 个包,每个
apt-get install输出 全 redirect 到/dev/null,用户看到几分钟黑屏。
改动(lib/check_sw.sh 的 install_pkgs(),line 74-109)
- 批量安装前再补一道冲突消解(防御纵深,防 filter_pkglist 被绕过或 pkgList 被中间修改)。
- 回退循环改成可见进度:每个包先
printf包名(cyan,左对齐 40 列),再装, 装完打OK(绿)/FAILED(红)。屏幕永不空白。 - 颜色变量复用
lib/color.sh里已定义的CMSG/CSUCCESS/CFAILURE/CEND。 cat -v验证对齐和转义正确,bash -n语法通过。
三层防护总览(都已在本地 lib/check_sw.sh)
installDepsUbuntu的 pkgList 源头已删libcurl4-gnutls-dev+ 死链包。filter_pkglist()末尾自动消解 libcurl dev 互斥冲突。install_pkgs()开头再消解一次 + 回退循环可见进度。
用户必须做的:把 lib/check_sw.sh 同步到服务器再重跑。当前服务器上跑的
还是旧版,所以三轮都看到同样的报错。
第四轮:审视整个项目,杜绝静默安装
用户要求"不要静默安装, 要有相关提示"。全项目扫描结论:
扫描发现
- 大多数
make -j/./configure没有被/dev/null吞输出(调用方run_install()或Install_X | tee会显示并写日志),只是缺起始提示。 - 唯一真正把安装输出吞掉的只有
lib/check_sw.sh逐包回退的apt-get ... >/dev/null 2>&1(第三轮已改成可见进度,本轮再改成完全不吞)。 - 下载环节
lib/download.sh的Download_src()用wget -c(无-q),带进度,OK。 - 所有模块安装统一经
lib/loader.sh的run_install(),是加统一提示的单点。
改动清单(7 个文件,bash -n 全通过)
lib/loader.shrun_install():加>> Installing: <func>横幅(带 module 路径)。 改这一处覆盖全部 47 个模块 + 主流程。lib/check_sw.shinstall_pkgs()回退循环:去掉>/dev/null,每个包打印 "Installing X ..." → "X installed OK / install FAILED",apt 下载进度可见。lib/openssl.shInstall_openSSL():开头加 ">> Installing: openSSL ver"。modules/web/jemalloc.shInstall_Jemalloc():开头加 ">> Installing: jemalloc ver"。lib/check_sw.shinstallDepsBySrc()(ICU):开头加 ">> Installing: ICU ver"。core/environment.shprepare_install():${PM} -y install wget gcc curl python加提示 +tee写日志(与上方 apt-get update 一致)。core/os/init_Ubuntu.sh/init_Debian.sh:iptables 安装两处apt-get加提示。
验证
grep 'apt-get.*install.*>/dev/null'全项目无匹配 → 再无静默 apt 安装。- 编译步骤输出仍可经
| tee看到并落日志。 - 收尾仍要提醒:所有改动需
rsync/git pull到服务器才会生效。
ServerStack: apt-get 依赖安装改为静默(-y) + 写日志
需求变更:上一轮把逐包回退改成屏幕逐行可见;这轮用户改口要
「apt-get 静默安装(-y) + 输出安装日志」。
改动(lib/check_sw.sh 的 install_pkgs()):
- 统一
export DEBIAN_FRONTEND=noninteractive,apt 完全非交互(不再卡 debconf 提示)。 - 批量安装:
apt-get --no-install-recommends -y install ${pkgList} >> runtime/install.log 2>&1, 屏幕只打印Installing dependency packages (... -> install.log)起始行 + 成功后All dependency packages installed successfully.。 - 逐包回退:每个包同样
apt-get -y ... >> install.log 2>&1,屏幕只保留一行-> <pkg> ... OK/FAILED(printf 左对齐 40 列,OK 绿/FAILED 红)。 - 日志路径
local _log="${oneinstack_dir:-.}/runtime/install.log",与外层installDepsUbuntu 2>&1 | tee同一文件;apt 详细输出直接追加、屏幕状态经 tee 落一份,无重复。 - 同步更新函数顶部注释,去掉旧的 /dev/null 描述。
bash -n通过。
设计要点:屏幕保留简洁状态(可读、不黑屏),完整 apt 输出进 install.log(可 grep 排障)。
第五轮:修复安装摘要 URL 显示 http:/// (IPADDR 为空)
根因:IPADDR 在 core/environment.sh 的 prepare_install() 由 ./lib/py/get_ipaddr.py 获取,
该脚本靠 shebang #!/usr/bin/env python 启动;Ubuntu 22.04+ 只有 python3 无 python 命令,
且 base-tools 装的是不存在的 python 包、symlink 补救被 ~/.oneinstack 判断限制,
导致脚本静默失败 → 标准输出空 → IPADDR 空 → 摘要 URL 变成 http:///ocp.php 等。
修复(仅 environment.sh + bin/upgrade.sh,bash -n 均通过):
- 新增纯 shell 函数
get_local_ipaddr()(environment.sh),按ip route get src→hostname -I→ip -o -4 addr show scope global→127.0.0.1回退,不依赖 python。 IPADDR=$(./lib/py/get_ipaddr.py)改为IPADDR=$(get_local_ipaddr)。- base-tools 安装
python→python3;/usr/bin/python软链改无条件创建, 让 get_public_ipaddr.py / get_ipaddr_state.py 也能跑。 bin/upgrade.sh独立入口同样加无条件python软链兜底。
验证:mock 命令测 get_local_ipaddr 三种场景均正确(有路由取 src / 无路由回退 hostname / 全无回退 127.0.0.1)。
注意:改动仍在本地,需同步到服务器后重装/重跑 install 生效。
第五轮补充:VPC/私网场景让摘要 URL 改用公网 IP
用户指出服务器是 VPC 网络。澄清:空 IP bug 与 VPC 无关(是 python 缺失);但 VPC 决定了
"显示哪个 IP"——ip route get 在 VPC 取到的是私网 RFC1918 地址,从外部经公网 IP/EIP 访问时
私网 URL 打不开。
补充改动(core/environment.sh):
- 取 IP 顺序改为先
PUBLIC_IPADDR=$(get_public_ipaddr.py)再IPADDR=$(get_local_ipaddr), 让本地检测函数能引用已解析的公网 IP。 get_local_ipaddr()末尾加 case:10.* / 172.16-31.* / 192.168.*私网段且PUBLIC_IPADDR非空时,改用公网 IP;公网取不到则安全保留私网 IP。
验证:mock 四场景全过(VPC私网+公网→公网 / VPC私网+公网失败→私网 / 经典VM公网→公网 / 纯内网192.168+失败→192.168)。