ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Erlang依赖错误libcrypto.so.10缺失:RPM符号版本解析

Erlang依赖错误libcrypto.so.10缺失:RPM符号版本解析 看到libcrypto.so.10(OPENSSL_1.0.2)(64bit) is needed by erlang-22.0.7-1.el7.x86_64这行报错很多人的第一反应是系统里没装 OpenSSL然后去装了一遍openssl发现版本明明比 1.0.2 还高结果依然过不去。这个坑我踩过不止一次折腾到最后才搞明白这行报错真正在问的不是你装了 OpenSSL 没而是你系统里有没有一个带 OPENSSL_1.0.2 符号版本的 libcrypto.so.10以及 RPM 的依赖解析能不能找到它。这篇文章我把这个报错从原理到排查再到几种实际可行的解法完整拆一遍。不管你是还在 CentOS 7 上维护老 RabbitMQ 集群还是不小心把 el7 的 Erlang 包装到了 CentOS Stream 9 上看完基本都能定位到问题然后选一条自己能走通的路。1. 先看懂报错的三层含义SONAME、符号版本和 RPM 依赖解析1.1 libcrypto.so.10 里的 .10本质是 ELF 的 SONAMElibcrypto.so.10并不是一个真实的物理文件名。在 CentOS 7 上OpenSSL 1.0.2 系列实际安装的文件通常叫/usr/lib64/libcrypto.so.1.0.2k。而.so.10这个名称是编译 OpenSSL 时写入 ELF 文件头里的DT_SONAME字段。你可以用下面命令验证readelf -d /usr/lib64/libcrypto.so.10 | grep SONAME输出会是0x000000000000000e (SONAME) Library soname: [libcrypto.so.10]用生活类比理解libcrypto.so.1.0.2k是人的身份证全名libcrypto.so.10是大家叫惯的绰号。程序在编译时记录的不是全名而是这个绰号运行时动态加载器拿着绰号去/etc/ld.so.cache里找对应文件。这就是为什么你/usr/lib64/下明明有一个带 OpenSSL 1.1.1 的 libcrypto却不能满足老程序的加载需求——因为它不叫libcrypto.so.10。RPM 在做依赖检查时也会检查系统里有没有提供libcrypto.so.10这个 SONAME 的文件或者有没有某个 RPM 包在自己的Provides字段里声明了这个能力。如果系统里只有libcrypto.so.3OpenSSL 3.0 的 SONAME那这一项就直接判定为不满足。1.2 OPENSSL_1.0.2 是符号版本不是文件名比 SONAME 更绕的一层是括号里的OPENSSL_1.0.2。这是 ELF 的符号版本机制Symbol Versioning它不是指文件名里带 1.0.2而是指这个.so文件在导出函数符号时给符号打上的版本标签。OpenSSL 1.0.2 编译出来的libcrypto.so.10内部会导出一组带版本标签的符号objdump -T /usr/lib64/libcrypto.so.10 | grep OPENSSL_1.0.2 | head你会看到类似000000000035a240 g DF .text 00000000000000d0 OPENSSL_1.0.2 BIO_new 000000000035a280 g DF .text 0000000000000030 OPENSSL_1.0.2 BIO_free 000000000035a540 g DF .text 0000000000000020 OPENSSL_1.0.2 OPENSSL_cleanseOPENSSL_1.0.2就是这套符号版本标签中的一个集合名。程序链接 OpenSSL 并使用某个符号后动态链接器不仅要求运行时能找到libcrypto.so.10还要求该库必须导出对应符号的OPENSSL_1.0.2版本否则程序即使启动了也随时可能因为找不到符号版本而崩溃。这就能解释一个很常见的怪象有人从某个老系统里手工拷了一个libcrypto.so.10放到/usr/lib64/文件存在了但 RPM 依然报缺少libcrypto.so.10(OPENSSL_1.0.2)(64bit)。原因很简单——拷过来的库符号版本标签不完整或者根本不带OPENSSL_1.0.2这个版本集合。1.3 RPM 依赖是包提供能力的匹配过程RPM 的依赖解析不是简单做文件比对而是基于包的Requires和Provides元数据。你在安装 erlang-22.0.7 时看到的报错完整形态是这样的错误软件包erlang-22.0.7-1.el7.x86_64/erlang-22.0.7-1.el7.x86_64 需要libcrypto.so.10(OPENSSL_1.0.2)(64bit)libcrypto.so.10(OPENSSL_1.0.2)(64bit)是 erlang 这个 RPM 的Requires声明。yum 在解决依赖时会去所有已启用仓库中寻找哪个包的Provides能覆盖这一项。在 CentOS 7 里提供这项能力的包是openssl-libs。rpm -q --provides openssl-libs | grep libcrypto.so.10正常输出libcrypto.so.10()(64bit) libcrypto.so.10(OPENSSL_1.0.2)(64bit) libcrypto.so.10(OPENSSL_1.0.2_EC)(64bit)注意openssl-libs的版本必须是 1.0.2k 这一代如果系统里装的是从 CentOS Stream 9 那边移植过来的 OpenSSL 3.x它Provides的是libcrypto.so.3跟libcrypto.so.10没有任何关系报错就必然出现了。所以这个报错本质上是在告诉你RP M 解析器在当前的系统环境和仓库组合里找不到一个能提供libcrypto.so.10(OPENSSL_1.0.2)(64bit)的包。至于为什么找不到往下看。2. 三种最容易踩出这个报错的场景自查2.1 CentOS 7 已 EOLyum 源失效导致依赖链断裂这是 2024 年之后最容易踩的场景。CentOS 7 在 2024 年 6 月 30 日正式停止维护官方源整体从mirror.centos.org挪到了vault.centos.org。如果你机器的/etc/yum.repos.d/CentOS-Base.repo里还写着老地址执行yum install时极大概率伴随这一串东西cannot find a valid baseurl for repo: base/7/x86_64 cannot find a valid baseurl for repo: centos-sclo-rh/x86_64base/7/x86_64就是 CentOS 7 的基础源centos-sclo-rh/x86_64是老的 Software Collections 库同样只面向 CentOS 7。这些源一旦失效yum 连 repo 元数据都拉不下来依赖解析自然不可能成功。你看到的缺少 libcrypto.so.10很多时候只是暴露出来的表面错误真正的病根是仓库列表里没有任何一个可用 base 源。自查命令yum repolist如果提示 Cannot retrieve metalink for repository 或者屏幕上直接出现 cannot find a valid baseurl那基本可以确定是源的问题。2.2 系统 OpenSSL 被替换/升级libcrypto.so.10 整个消失这种情况多发生在有人手动编译安装过高版本 OpenSSL或者装过某些第三方源里自带的 openssl 包。系统里openssl version输出是高版本但底层的openssl-libs已经被动过手脚。自查命令rpm -qa | grep openssl ldconfig -p | grep libcrypto如果看到libcrypto.so.3 (libc6,x86-64) /usr/lib64/libcrypto.so.3而完全没有libcrypto.so.10说明系统的 OpenSSL 主流已经切换到 3.x 时代。此时即便你恢复了 yum 源依然要去仓库里把匹配 CentOS 7 的openssl-libs拉回来或者用兼容包把缺口补上。还有一种隐蔽情况机器上确实存在/usr/lib64/libcrypto.so.10但它来自某次手工tar解包或非标准安装RPM 数据库里没有任何包登记Provides: libcrypto.so.10(OPENSSL_1.0.2)(64bit)。这种情况 yum 一样会报错因为它认的是 RPM 元数据而不是裸文件。2.3 把 el7 的 rpm 装到了 CentOS Stream 8/9 上这个场景最近特别常见。很多人搜到 erlang RPM 下载页看到链接里带el7就下了也不看自己系统是什么。CentOS Stream 9 自带的是 OpenSSL 3.0/usr/lib64/里只有libcrypto.so.3用yum install ./erlang-22.0.7-1.el7.x86_64.rpm安装时第一关就死在这个依赖上。而且这类问题的报错会非常有迷惑性——它明确告诉你缺的是OPENSSL_1.0.2容易让新手以为装个 OpenSSL 1.0.2 兼容库就行。但 CentOS Stream 9 的软件包生态整体基于 RHEL 9强行往里面塞 el7 的依赖轻则依赖冲突重则把系统的 openssl 相关组件搅成一锅粥。自查命令cat /etc/os-release看一眼VERSION_ID再回头看你下载的 Erlang 包名字里是el7、el8还是el9。如果系统是 Stream 9包名却是el7那这就是当前报错的直接原因。3. 老集群救法CentOS 7 上恢复可用环境并装对 Erlang如果你确实还在 CentOS 7 上维护老业务尤其是跑着 RabbitMQ 3.8 这类需要 Erlang 22 的环境目标不是升级 OpenSSL而是把系统环境恢复到一个el7 包能正常装的状态。3.1 第一步把源切到 vault.centos.orgCentOS 7 的官方归档地址是https://vault.centos.org/7.9.2009/。修改/etc/yum.repos.d/CentOS-Base.repo时核心是把mirrorlist相关配置全部注释掉改成baseurl指向 vault下面是一个经过验证的最小可用配置[base] nameCentOS-7 - Base baseurlhttps://vault.centos.org/7.9.2009/os/x86_64/ enabled1 gpgcheck1 gpgkeyfile:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7 [updates] nameCentOS-7 - Updates baseurlhttps://vault.centos.org/7.9.2009/updates/x86_64/ enabled1 gpgcheck1 gpgkeyfile:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7 [extras] nameCentOS-7 - Extras baseurlhttps://vault.centos.org/7.9.2009/extras/x86_64/ enabled1 gpgcheck1 gpgkeyfile:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7改完后执行yum clean all yum makecachemakecache能正常拉取元数据说明源已经可用。如果机器在国内访问 vault 速度不理想也可以用阿里云的归档镜像baseurlhttps://mirrors.aliyun.com/centos-vault/7.9.2009/os/x86_64/注意不要再把源指到清华 tuna 或阿里云上那些centos-stream/9-stream的目录那是 CentOS Stream 9 的镜像。CentOS 7 机器用了 Stream 9 的仓库依赖解析会直接乱套libcrypto.so.10这种东西在 Stream 9 仓库里不可能存在。3.2 第二步确认 openssl-libs 能否满足依赖源恢复后先确认当前openssl-libs的情况rpm -q openssl-libs如果返回package openssl-libs is not installed直接装yum install openssl-libs装好后再次验证rpm -q --provides openssl-libs | grep libcrypto.so.10(OPENSSL_1.0.2)能看到输出说明依赖缺口已经补上。如果yum install openssl-libs报错先排查是不是还有别的失效仓库比如centos-sclo-rhyum repolist --verbose | grep -B2 -A2 centos-sclo老架构的 SCL 仓库已经没人维护建议直接把/etc/yum.repos.d/下对应的 repo 文件禁用或删除不要让它干扰依赖解析。对绝大多数装 Erlang 的场景SCL 里的软件用不到。3.3 第三步用 yum install ./rpm 或 Erlang Solutions 源安装这一步是最容易翻车的环节。很多人下载 Erlang RPM 后直接rpm -ivh erlang-xxx.rpm结果报出一个依赖错误又手动去下一个依赖陷入依赖地狱。正确操作是让 yum 替你处理依赖yum install ./erlang-22.0.7-1.el7.x86_64.rpmyum install ./xxx.rpm和rpm -ivh xxx.rpm的区别在于yum 会把这个本地包纳入依赖解析流程如果它还需要别的包而仓库里有yum 会一并安装rpm 则不会去查任何仓库。如果你更希望走官方源可以用 Erlang Solutions 为 CentOS 7 提供的 rpm 源wget https://binaries2.erlang-solutions.com/rpm/centos/erlang-solutions-2.0-1.noarch.rpm rpm -ivh erlang-solutions-2.0-1.noarch.rpm yum install erlang在源和依赖都正常的情况下这条路最省事装出来的 Erlang 直接和系统 OpenSSL 1.0.2 对接好。提示如果你的原始需求是给 RabbitMQ 用更推荐从 rabbitmq/erlang-rpm Releases 下载和 RabbitMQ 版本匹配的 Erlang 包选el7后缀那个然后同样用yum install ./方式装。RabbitMQ 官方维护的 Erlang 包在兼容性上更稳。3.4 备选源码编译 OTP 22如果必须锁死在 erlang 22.0.7 这个版本又不想被第三方包装包方式绑定源码编译是保底方案。在 CentOS 7 上编译 OTP 22 需要先准备好编译器工具链和依赖yum groupinstall Development Tools yum install ncurses-devel openssl-devel unixODBC-devel下载OTP-22.0.7源码后tar -xf otp_src_22.0.7.tar.gz cd otp_src_22.0.7 ./configure --prefix/usr/local/erlang --with-ssl/usr make -j$(nproc) make install--with-ssl/usr是为了让它明确找到 CentOS 7 上 OpenSSL 1.0.2 的头文件和库文件。编译完成后把/usr/local/erlang/bin加入 PATHecho export PATH/usr/local/erlang/bin:$PATH /etc/profile.d/erlang.sh source /etc/profile.d/erlang.sh erl -version源码编译最大的好处是绕开了 RPM 依赖层的所有检查只要你机器上编译时能链接到 OpenSSL 1.0.2产出的 Erlang 运行起来就没有libcrypto.so.10的问题。缺点是后续维护更新要靠自己不像 RPM 包装的那么好升级。4. 新系统该怎么办配对的发行版包比硬刚依赖更重要4.1 先看 /etc/os-release再挑包的后缀如果你机器是 CentOS Stream 9 或者 RHEL 9那刚才所有围绕恢复 CentOS 7 环境的操作都不适用。你应该做的是停止尝试安装 el7 的 Erlang RPM而是去下载对应 el9 版本的包。判断系统版本cat /etc/os-release只要看到VERSION_ID9后面下载包时就要认准el9后缀。el8 的包原则上也比 el7 的可接受度高一些但最稳妥的还是和系统大版本保持一致。用 RabbitMQ 官方 erlang-rpm 仓库举例下载地址里的文件名长这样erlang-26.2.5-1.el9.x86_64.rpm安装命令不变yum install ./erlang-26.2.5-1.el9.x86_64.rpmyum 会从当前系统仓库中找到匹配的 OpenSSL 3.x 依赖装完就完事。4.2 用 RabbitMQ 官方 erlang-rpm 里的 el9 包之前有朋友问为什么我直接用yum install erlang在 CentOS Stream 9 上也能装但装出来的版本很老因为 CentOS Stream 9 的 AppStream 仓库里 Erlang 版本往往偏向较新 OTP如果你需要的是和某个业务框架严格匹配的 Erlang 版本用发行版自带包反而不合适。RabbitMQ 官方 erlang-rpm 仓库里对不同系统版本维护了多套构建产物它至少覆盖 el7、el8、el9。需要什么 Erlang 版本就去 Releases 页找对应的 tag。比如 Erlang 26.2.5 的 release 页面里el9 和 el7 的包是分开放的下载时看清楚。这种集中维护的仓库还有一个好处它的包在构建时已经验证过和同一发行版上的 OpenSSL 能正常配合不会出现装完 erlang 后发现 crypto 应用起不来的尴尬。相比之下个人在不知名源里打包的 Erlang 就不好说了。4.3 由 Erlang 版本反查业务你现在到底为啥要 22.0.7这里想多说一句和 OpenSSL 无关但实际工作中经常卡住人的事很多时候安装 Erlang 22 只是因为它和 RabbitMQ 3.8 是搭好的组合。如果项目允许在新系统上更合理的做法是同步升级 RabbitMQ 到 3.12/3.13 或 4.x然后直接使用 Erlang 26/27。原因是 Erlang 22 是 2019 年的版本OpenSSL 1.0.2 也已经 EOL 很久。你为了一个老依赖去整体维持一套 EOL 环境后面遇到的安全漏洞和兼容问题会源源不断。给一个粗略的对照参考服务版本常用 Erlang/OTP 版本说明RabbitMQ 3.8.x22.3.x老集群常见需要 el7 时代 OpenSSL 1.0.2/1.1.xRabbitMQ 3.11.x24.x / 25.x已经支持 OpenSSL 3.0RabbitMQ 3.12.x25.x / 26.x新系统上比较稳的搭配RabbitMQ 4.x26.x / 27.x新项目推荐直接走 el9 包如果最后还是决定用 Erlang 22那就接受它只能在 CentOS 7 类环境下好用的现实如果用新系统趁早选新 Erlang 版本而不是想着让新系统去兼容 2019 年的动态库命名。5. --nodeps 等歪门邪道的实际后果与仅有的救急场景遇到这类依赖报错总有同学会想到跳过依赖检查。我可以明确说rpm -ivh --nodeps和yum install --nodeps在这些场景下大概率会留下一个看起来装了实际跑不动的 Erlang。5.1 用 --nodeps 装上去第一关就挂在 crypto/ssl 应用Erlang 的crypto和ssl两个标准库是通过 NIF 直接加载 OpenSSL 动态库的。系统里没有libcrypto.so.10时即使你强制装上 Erlang RPM启动erl后执行application:start(crypto).大概率得到{error,{not_started,crypto}}或者更直接的Failed to load NIF: libcrypto.so.10: cannot open shared object fileerl本身能进 shell但那完全是表象。RabbitMQ 启动时如果依赖 crypto/ssl 应用会在初始化阶段直接崩掉日志里又是一长串 NIF 加载错误。还有一个隐藏问题--nodeps装的包在 RPM 数据库里处于依赖不完整状态之后你执行任何yum update、yum remove都可能因为它引发连锁检查失败反而把系统包管理状态搞脏。5.2 手工把 libcrypto.so.10 拷进 /usr/lib64 的连锁反应更不建议的做法是从别的机器上把libcrypto.so.10直接scp到/usr/lib64/。前面讲过RPM 依赖检查认的是包元数据而不是裸文件所以拷文件并不能消除报错。更麻烦的是这个手工拷贝的库可能和系统里已有的 OpenSSL 1.0.2 头文件、工具链版本不匹配覆盖后可能导致openssl命令行、yum自身乃至 sshd 的加密模块工作异常。如果你非要手工验证正确姿势不是往/usr/lib64/里丢文件而是把库放到独立目录比如/opt/openssl-1.0.2/lib/然后通过/etc/ld.so.conf.d/下新增配置echo /opt/openssl-1.0.2/lib /etc/ld.so.conf.d/openssl-1.0.2.conf ldconfig再确认ldconfig -p | grep libcrypto.so.10这样至少不会污染系统自带库目录。但依然要注意RPM 依赖检查仍然不认因为没有任何包声明Provides: libcrypto.so.10。5.3 什么情况下的确可以绕过符号版本匹配的库已在系统里--nodeps也并非完全没有使用场景。有一种情况系统里本身已经由源码编译方式安装了一整套 OpenSSL 1.0.2 到/usr/local/ssl其libcrypto.so.10符号版本完整并且已经通过 ld.so.conf 或LD_LIBRARY_PATH让动态加载器能找到。此时你完全清楚自己在做什么只是想让 Erlang 的 RPM 装进系统然后依赖这个自定义 OpenSSL 运行。这种情况下用rpm -ivh --nodeps erlang-22.0.7-1.el7.x86_64.rpm是可行的但需要同时保证运行 Erlang 的进程环境里LD_LIBRARY_PATH包含了/usr/local/ssl/lib否则erl一启动就找不到libcrypto.so.10。如果是在容器里做测试也可以把编译好的 Erlang 直接放进镜像配合指定 OpenSSL 1.0.2 的基础镜像绕开 RPM 依赖体系。生产环境我不建议这么干因为维护成本太高你以后每次重构环境都要重新梳理这些手工约定。注意无论你采用什么绕过方案安装完都务必验证一行命令erl -noshell -eval io:format(~p~n, [crypto:supports()]), halt().如果crypto模块不能正常输出支持的算法列表说明 OpenSSL 库加载还是有问题趁早回头修依赖才是正路。在我自己处理过的类似问题里最省心的永远是让系统的包管理和 Erlang 包的标注匹配起来CentOS 7 就老老实实修好 vault 源用 el7 包Stream 9 就用 el9 包。跳过依赖检查、手工拷贝动态库那些都是把问题推迟到运行时的做法代价只会更高。最后再提醒一句不管哪条路改完源或装完包后先把yum repolist和rpm -q --provides openssl-libs两个输出看清楚这两个命令比任何网上搜来的报错帖子都更能说明你机器现在的真实状态。
返回列表