166 lines
9.7 KiB
Markdown
166 lines
9.7 KiB
Markdown
# 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 等),
|
||
然后重跑安装。同步后两层防护都会生效:
|
||
1. Ubuntu 列表源头已无 `libcurl4-gnutls-dev`(也不会再有 Skip 噪音)。
|
||
2. 即便将来有人把互斥包加回去,`filter_pkglist` 会自动摘掉。
|
||
|
||
## 第三轮:修复"卡很久"的黑屏问题
|
||
|
||
用户反馈"在运行到此处时会卡很久"。分析 `install_pkgs()` 的卡顿来源:
|
||
|
||
1. **批量 apt-get 遇冲突时静默求解**:apt 的依赖求解器遇到 `libcurl4-gnutls-dev`
|
||
vs `libcurl4-openssl-dev` 互斥时,会花 30s~2min 尝试各种组合才放弃,期间
|
||
**无任何输出**,看起来像冻住。
|
||
2. **逐包回退循环全静默**:批量失败后循环 ~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`)
|
||
|
||
1. `installDepsUbuntu` 的 pkgList 源头已删 `libcurl4-gnutls-dev` + 死链包。
|
||
2. `filter_pkglist()` 末尾自动消解 libcurl dev 互斥冲突。
|
||
3. `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` 全通过)
|
||
|
||
1. `lib/loader.sh` `run_install()`:加 `>> Installing: <func>` 横幅(带 module 路径)。
|
||
改这一处覆盖全部 47 个模块 + 主流程。
|
||
2. `lib/check_sw.sh` `install_pkgs()` 回退循环:去掉 `>/dev/null`,每个包打印
|
||
"Installing X ..." → "X installed OK / install FAILED",apt 下载进度可见。
|
||
3. `lib/openssl.sh` `Install_openSSL()`:开头加 ">> Installing: openSSL ver"。
|
||
4. `modules/web/jemalloc.sh` `Install_Jemalloc()`:开头加 ">> Installing: jemalloc ver"。
|
||
5. `lib/check_sw.sh` `installDepsBySrc()`(ICU):开头加 ">> Installing: ICU ver"。
|
||
6. `core/environment.sh` `prepare_install()`:`${PM} -y install wget gcc curl python`
|
||
加提示 + `tee` 写日志(与上方 apt-get update 一致)。
|
||
7. `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` 均通过):
|
||
1. 新增纯 shell 函数 `get_local_ipaddr()`(environment.sh),按
|
||
`ip route get src` → `hostname -I` → `ip -o -4 addr show scope global` → `127.0.0.1` 回退,**不依赖 python**。
|
||
2. `IPADDR=$(./lib/py/get_ipaddr.py)` 改为 `IPADDR=$(get_local_ipaddr)`。
|
||
3. base-tools 安装 `python` → `python3`;`/usr/bin/python` 软链改**无条件**创建,
|
||
让 get_public_ipaddr.py / get_ipaddr_state.py 也能跑。
|
||
4. `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`):
|
||
1. 取 IP 顺序改为先 `PUBLIC_IPADDR=$(get_public_ipaddr.py)` 再 `IPADDR=$(get_local_ipaddr)`,
|
||
让本地检测函数能引用已解析的公网 IP。
|
||
2. `get_local_ipaddr()` 末尾加 case:`10.* / 172.16-31.* / 192.168.*` 私网段且
|
||
`PUBLIC_IPADDR` 非空时,改用公网 IP;公网取不到则安全保留私网 IP。
|
||
|
||
**验证**:mock 四场景全过(VPC私网+公网→公网 / VPC私网+公网失败→私网 / 经典VM公网→公网 / 纯内网192.168+失败→192.168)。
|