说实话,我刚拿到这台跑了 AlmaLinux 9.4 的服务器时,心里其实挺踏实的。毕竟大家都知道,AlmaLinux 是 CentOS 最好的继任者之一,RHEL 100% 二进制兼容,稳如老狗。但那天下午,当我兴冲冲地试图编译一个开源项目,然后顺手跑了一下 dnf update 之后,现实给了我一记响亮的耳光。
屏幕上那些红底白字的报错,简直比前任代码里的 Bug 还让人头大。如果你现在正盯着类似的终端输出发愁,别慌,把椅子拉近点,我把自己踩过的坑、流过的泪,都整理成了这篇记录。咱们不整那些虚头巴脑的理论,直接看问题、看解法。
第一坑:源码编译时的“头文件失踪案”
事情是这样的,我想在一个干净的环境里编译 my-project,一个基于 OpenSSL 库的应用。我在源码目录里自信地敲下了 ./configure,然后……
[root@server ~]# ./configure
...
checking for SSL_library_init in -lssl... no
configure: error: OpenSSL is required
那一刻,我的内心是崩溃的。OpenSSL?我明明刚刚把系统更新到了最新状态!openssl 命令也能跑,版本是 3.0.x。难道系统对源码编译有什么隐藏的黑客行为?
我迅速检查了环境:
[root@server ~]# openssl version
OpenSSL 3.0.7 1 Nov 2022 (Library: OpenSSL 3.0.7 1 Nov 2022)
有啊,确实在。那为什么找不到?我翻遍了 Google,最后在一篇不起眼的社区帖子里找到了答案:AlmaLinux 9(以及 RHEL 9)默认不再提供开发头文件和静态库,而是将它们拆分到了独立的包中。
在 CentOS 7 或者更早的版本里,你可能只需要装 openssl,头文件就自动躺在那了。但在 EL9 时代,为了精简主包体积和安全考虑,一切都被模块化了。
为什么会有这种变化?
这其实是红帽系大生态的一次“大换血”。El8/El9 开始,系统强调模块化和最小化安装。主包 openssl 只包含运行时库,而开发人员需要的 openssl-devel、头文件、链接器脚本都被移到了专门的开发包中。这听起来很合理,但对于习惯了“不管三七二十一先装个包再说”的老手来说,确实是个不小的观念冲击。
解决方案
既然找到了病因,下药就容易了。你需要安装的包名也变了:
方案 A:安装标准的开发包(推荐)
这是最标准的做法。你只需要告诉 dnf 你要头文件和库:
sudo dnf install openssl-devel libcurl-devel zlib-devel
安装完后,再次运行 ./configure,你会发现它顺利通过了。如果你不确定缺什么,可以看 configure 最后的报错,它通常会提示缺哪个库,然后去 dnf provides */<headerfile.h> 里反查。
方案 B:使用“组包”一键解决(适合懒人)
如果你不知道项目具体缺什么依赖,可以安装一组常用的开发工具:
sudo dnf groupinstall "Development Tools"
sudo dnf groupinstall "Development Libraries"
Development Tools 组里包含了 gcc, make, autoconf, automake 等基础编译链,而 Development Libraries 则拉了一大堆常用的 .pc 文件和头文件。
方案 C:源码自编译 OpenSSL 并指定路径(高阶操作)
有时候,你想用的库版本比系统自带的更新,或者项目要求特定版本。这时候你可以从源码编译 OpenSSL,然后告诉 configure 你的路径:
# 1. 下载 OpenSSL 源码
wget https://www.openssl.org/source/openssl-3.1.0.tar.gz
tar -xzf openssl-3.1.0.tar.gz
cd openssl-3.1.0
# 2. 配置、编译、安装到本地目录
./config --prefix=/usr/local/openssl --openssldir=/usr/local/openssl
make -j$(nproc)
sudo make install
# 3. 设置环境变量
export LD_LIBRARY_PATH=/usr/local/openssl/lib:$LD_LIBRARY_PATH
export PATH=/usr/local/openssl/bin:$PATH
export LDFLAGS="-L/usr/local/openssl/lib"
export CPPFLAGS="-I/usr/local/openssl/include"
# 4. 再次编译你的项目
cd ../my-project
./configure --with-ssl=/usr/local/openssl
make
这一步要小心,千万不要用 make install 覆盖系统默认的 /usr/bin/openssl,除非你准备好面对整个系统崩溃的风险。在 AlmaLinux 9 中,很多系统组件(包括 dnf 本身)都强依赖系统级的 OpenSSL。
第二坑:dnf update 时的“依赖地狱”
解决了编译问题,我心想,既然都更新到 9.4 了,顺手跑个系统更新吧。于是,我敲下了那行经典的命令:
sudo dnf update
回车。三秒钟后,终端吐出了一长串依赖冲突的错误:
problem with installed package libxcrypt-compat-4.4.18-4.el9.x86_64
- package libxcrypt-compat-4.4.18-4.el9.x86_64 requires libxcrypt, but none of the providers can be installed
- conflicting requests
(try to add '--allowerasing' to command line to replace conflicting packages)
看到 libxcrypt 和 libxcrypt-compat 打架,我愣住了。这两个包是什么关系?为什么好好的系统会突然不兼容?
深入剖析:libcrypt 的版本分裂
这里涉及到一个 Linux 基础库的历史包袱。libxcrypt 是负责密码哈希(比如 crypt() 函数,用于存储用户密码)的库。
在 EL8 之前,这个库叫 libcrypt。从 EL8 开始,为了分离新旧 API,红帽将库重命名为 libxcrypt,并提供了一个兼容性包 libxcrypt-compat 给还在链接旧 libcrypt 的二进制文件使用。
问题的根源在于:
- 你的系统中可能残留了一些旧的应用程序或第三方仓库(比如某些 ERP、CRM 软件,或者从源码编译安装的软件)的旧版
.so链接。 - 当
dnf尝试更新libxcrypt主包时,发现某个已安装的包(通常是libxcrypt-compat)的版本和主包不匹配,或者主包被某个强依赖锁住了。 - 更常见的一种情况是:你之前手动下载过
.rpm安装包并用rpm -ivh安装,而没有使用dnf。这会导致依赖关系在 dnf 数据库中“断裂”。
修复方案:三种策略,由浅入深
策略一:使用 --allowerasing(谨慎使用)
报错信息里其实已经给了提示:--allowerasing。这个参数的意思是“允许 dnf 为了安装/更新当前包而移除冲突的包”。
sudo dnf update --allowerasing
注意: 这不是万能药。如果你盲目使用,可能会误删一些你急需的旧版库,导致某些老旧软件无法运行。所以,先看它要删什么。如果它说要把 libxcrypt-compat 删掉,而你确认没有程序强依赖旧版 libcrypt 符号,那就可以这么干。
策略二:清理并重建依赖数据库(最常用)
很多时候,问题出在 dnf 的缓存或元数据上。试试这一套组合拳:
# 1. 清空所有缓存
sudo dnf clean all
# 2. 重新下载元数据
sudo dnf makecache
# 3. 修复可能的损坏依赖
sudo dnf check
# 4. 尝试修复
sudo dnf --refresh upgrade
如果 dnf check 提示有包损坏,可以尝试:
sudo rpm -Va --nofiles --nodigest
这会检查所有已安装包的文件和元数据是否完整。如果有输出,说明有文件被意外修改或损坏。
策略三:定位并移除“钉子户”包(根治)
这是最根本的解决办法。我们需要找到是哪个包在捣乱。
# 查看 libxcrypt-compat 被谁依赖
sudo dnf repoquery --requires libxcrypt-compat
或者反过来,查看冲突的具体原因:
sudo dnf info libxcrypt-compat
如果发现某个第三方软件(比如一个旧的 Java 应用或 Python 库)依赖了 libxcrypt-compat,而你又不需要它了,那就:
sudo dnf remove libxcrypt-compat
sudo dnf update
如果必须保留它,那就需要锁定版本,或者从第三方仓库重新安装匹配版本的 libxcrypt。
第三坑:模块化流(AppStream)的“幽灵包”
在处理完前两个坑后,我遇到了一个更诡异的现象。我想安装一个常用的工具 htop,结果 dnf 提示:
No match for argument: htop
htop 不存在?这不可能!我可是 AlmaLinux 9.4,这玩意儿应该是标配啊。
我灵机一动,查一下模块流:
sudo dnf module list htop
输出显示:
Name Stream Profiles Summary
htop 2.2 [d] default [d] Interactive process viewer
原来,htop 在 EL9 中被移除了传统的 RPM 包形式,转而使用 AppStream 模块化 来管理。这意味着你不能直接 dnf install htop,而必须通过模块流来安装:
sudo dnf module enable htop
sudo dnf install htop
这仅仅是 htop 吗? 不,很多工具在 EL9 中都变成了模块,比如 python39、nodejs、postgresql、mariadb 等。如果你之前是从源码编译安装这些软件的,现在再想装回系统包,可能会遇到找不到包的尴尬。
为什么会有模块化?
模块化是红帽为了在同一台机器上提供多个软件版本而设计的。比如你既需要 Python 3.9(系统默认),又需要 Python 3.11(通过 AppStream 模块提供)。如果没有模块化,pip install 可能会搞乱系统 Python 环境。
如何处理模块化带来的混乱?
- 养成查看模块列表的习惯:在
dnf install之前,先dnf module list <package>看看它是否是一个模块。 - 不要随意
dnf module enable:除非你明确知道自己在做什么。一旦启用了某个模块流,它会覆盖系统默认版本,可能会引起依赖冲突。 - 如果已经乱了,重置模块:
sudo dnf module reset <module-name> sudo dnf module disable <module-name>
升级过程中的“断崖式”变化:SELinux 和 PAM
除了软件包的问题,AlmaLinux 9.4 的升级还带来了一些底层策略的变化,这些变化往往在报错后才被发现,让人措手不及。
SELinux 的强制模式
升级后,你可能会发现某些服务启动失败,日志里满是 avc: denied。这是因为 EL9 默认开启了更严格的 SELinux 策略,并且对 permissive 模式的宽容度降低了。
建议:
- 升级前,确保你的应用已经适配了 SELinux。
- 如果遇到权限拒绝,使用
ausearch -m avc -ts recent查看具体的拒绝记录。 - 对于新手,如果实在搞不定,可以在临时测试环境中将 SELinux 设为
permissive模式:
但这只是权宜之计,生产环境务必保持sudo setenforce 0enforcing,并针对具体应用编写 SELinux 策略。
PAM 认证模块的变更
在 EL9 中,pam_ssh_agent_auth 等模块的行为有所调整。如果你使用了 SSH 密钥代理转发,可能会遇到认证失败的问题。
排查思路:
检查 /var/log/secure 或 journalctl -u sshd,看看 PAM 的具体报错信息。有时候需要更新 SSH 客户端版本,或者调整 PAM 配置文件 /etc/pam.d/sshd。
给新手的“避坑”检查清单
经历了这一系列的波折,我总结了一份清单。下次再面对 AlmaLinux 9.4 的升级或新系统部署时,按这个顺序操作,能省去你大半的头发:
备份!备份!备份! 在升级前,备份
/etc目录、数据库、以及关键的应用配置文件。如果可能,对整个/var和/home做快照。阅读发行注记(Release Notes) AlmaLinux 的官方文档非常详细。特别是“Upgrading from CentOS”或“Upgrade from 9.3 to 9.4”的部分,里面列出了已知的变更和破坏性更新。不要偷懒,花 20 分钟读一下,能省下 20 小时的排查时间。
检查第三方仓库 EPEL、Remi、Nginx 官方源等。确保它们都有 EL9 的版本。如果某个第三方源还没有适配 EL9,你需要暂时禁用它,或者找到替代品。
sudo dnf repolist小规模测试 不要直接在生产服务器上手残升级。搭建一个相同的测试环境,模拟升级过程,验证关键业务是否能正常运行。
保留旧的内核和回滚方案 升级后,确保 GRUB 里还保留着旧的内核选项。万一新内核有兼容性问题,你可以从旧内核启动。
sudo dracut --force sudo grub2-mkconfig -o /boot/grub2/grub.cfg使用
dnf distro-sync而非盲目update如果你是从早期版本(如 9.0)升级到 9.4,建议使用dnf distro-sync来确保所有包都与目标版本对齐,避免留下半升级状态的包。
结语:拥抱变化,保持耐心
AlmaLinux 9.4 是一次重要的迭代,它带来了更好的安全性、更现代化的工具链,当然也伴随着一些“成长的烦恼”。
作为新手,遇到这些报错时,千万不要气馁。每一个报错信息都是系统在和你对话,告诉你哪里不对。学会使用 journalctl、dnf module、sealert 等工具,慢慢你就会发现,Linux 的底层逻辑其实非常有规律。
我把这些踩坑经历写下来,就是希望你在遇到类似问题时,能有一个可以参照的“地图”。毕竟,我们都是从新手一路走来的,谁还没有几个红色的报错日志呢?
希望这篇指南能帮到你。如果还有具体的报错信息搞不定,欢迎在评论区贴出来,咱们一起讨论。祝你的服务器运行平稳,Bug 远离!
