ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Erlang安装报错libcrypto.so.10缺失?OpenSSL兼容库与依赖解析全指南

Erlang安装报错libcrypto.so.10缺失?OpenSSL兼容库与依赖解析全指南 相信不少人在装 Erlang 或者 RabbitMQ 的时候都被这么一行红字卡住过libcrypto.so.10(OPENSSL_1.0.2)(64bit) is needed by erlang-22.0.7-1.el7.x86_64我第一次看到这行报错时第一反应是去重装 Erlang结果换了好几个版本提示一字不差。后来才明白问题根本不在 Erlang而是它依赖的 OpenSSL 1.0.2 这个老版本库没有就位。这个坑在 CentOS 7 停止维护之后特别容易踩尤其是当你手里只有一个 minimal 镜像、yum 源还失效的时候那叫一个酸爽。这个报错本质上是一个典型的 Linux 依赖解析问题。它不挑人新手会碰到老手在 CentOS Stream、RHEL 9 上装老包时一样会碰到。这篇文章我会从报错信息本身的含义讲起给你一套从“源失效”到“依赖满足”再到“Erlang 成功跑起来”的完整操作路径同时把那些网上很少讲透的细节比如符号版本、软链接为什么不能用、i686 和 x86_64 的坑一次说清楚。1. 报错拆解先搞清楚这行红字到底在说什么1.1 三块拼图libcrypto.so.10、OPENSSL_1.0.2、64bit先别急着上网找“修复包”把这行报错拆开看其实就三块信息。libcrypto.so.10 是 OpenSSL 1.0.x 的共享库文件名。在 Linux 下OpenSSL 1.0.x 编译出来的加密库叫 libcrypto.so.10 和 libssl.so.10后面的 .10 叫 SONAME 版本号。OpenSSL 1.1.x 对应的是 libcrypto.so.1.1OpenSSL 3.x 对应的是 libcrypto.so.3。所以当系统里只有 OpenSSL 1.1.1 或 3.0 时是不会有 libcrypto.so.10 这个文件的。括号里的 OPENSSL_1.0.2 是符号版本标记。这个容易被人忽略却是最容易翻车的地方。它在编译时被写进二进制文件里相当于一份 API 契约Erlang 编译时用的 OpenSSL 版本是 1.0.2那么运行时要求动态库里必须存在 OPENSSL_1.0.2 这一组符号版本。你可以把它理解成“库提供方承诺支持的接口版本号”不太准确但好记。64bit 表示需要的是 x86_64 位架构的库。如果系统里只装了一个 i686 的 libcrypto.so.10rpm 依然会报错因为架构不匹配。这也是很多人安装了“看起来对的包”却依然失败的原因。1.2 Erlang 只是受害者依赖链的真相很多人看到“is needed by erlang”就以为 Erlang 坏了其实 Erlang 是无辜的。Linux 的 rpm 包管理器在安装软件时会读取这个包里的 Require 依赖声明。erlang-22.0.7-1.el7.x86_64 这个包在构建时编译环境里的 OpenSSL 是 1.0.2于是 rpm 打包工具就把 libcrypto.so.10(OPENSSL_1.0.2)(64bit) 写进了依赖列表。安装时包管理器去系统里找这个库文件找不到就中断安装。我把这个报错截图上给我一个刚入行的同事看他说了一句“这不就是个 DLL 缺失吗” 虽然 Windows 和 Linux 在机制上有差异但这个类比很贴近。你可以把 libcrypto.so.10 理解成 Windows 里的某个 DLL把安装 Erlang 理解成运行某个软件时提示缺少 DLL。只不过 Linux 的依赖检查更严格在安装阶段就直接拦下来不会等你运行时报错。1.3 什么环境最容易踩到这个坑结合我自己的经历和网上大量求助帖最容易出这个报错的是下面几种场景在 CentOS Stream 8/9、RHEL 8/9 或其它新系统上直接安装 el7 的 Erlang rpm 包。系统 OpenSSL 版本是 1.1.1 或更高完全没有 libcrypto.so.10。CentOS 7 系统里的 OpenSSL 被第三方源升级到了 1.1.1。虽然有部分兼容库但老版本 Erlang 仍然找不到 OPENSSL_1.0.2 符号版本。CentOS 7 minimal 安装后 yum 源失效。想装 epel 或者 rabbitmq 的依赖结果源本身都起不来更别提装兼容库了。用 Docker 拉了 centos:7 镜像之后又额外拷贝了别的系统里的库文件。这种环境 I 见得太多了镜像里缺库但主机上又“看起来有”最后全乱套。如果你符合其中任何一种下面两章的内容应该能直接帮你解决问题。2. 从根上想办法恢复可用的 Yum 源比什么都重要2.1 为什么 CentOS 7 的源会集体失效CentOS 7 在 2024 年 6 月 30 日到达生命周期终点EOL之后官方在 mirror.centos.org 上就不再提供 7 的更新内容。如果你机器上还保留着默认的 CentOS-Base.repo里面用的是 mirrorlist...centos.org那么运行 yum 的时候就会收到Cannot find a valid baseurl for repo: base/7/x86_64这个报错的热度非常高因为大量老机器还在跑 CentOS 7。解决思路很简单把源地址从 mirrorlist 改成 vault.centos.org也就是 CentOS 的版本存档仓库。vault 里的包会一直保留不会因为 EOL 就消失。2.2 一套可用的 vault 源配置方案直接把 /etc/yum.repos.d/CentOS-Base.repo 改成下面这样是最稳妥的做法。我建议先备份原文件cp /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.bak然后用你熟悉的编辑器打开改成[base] nameCentOS-$releasever - Base baseurlhttps://vault.centos.org/7.9.2009/os/$basearch/ gpgcheck1 gpgkeyfile:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7 [updates] nameCentOS-$releasever - Updates baseurlhttps://vault.centos.org/7.9.2009/updates/$basearch/ gpgcheck1 gpgkeyfile:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7 [extras] nameCentOS-$releasever - Extras baseurlhttps://vault.centos.org/7.9.2009/extras/$basearch/ gpgcheck1 gpgkeyfile:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7这里有个细节要提醒不要用 CentOS Stream 9 的 baseos 地址来填。网络上一些教程会直接写 mirrors.tuna.tsinghua.edu.cn/centos-stream/9-stream/baseos/x86_64 这样的路径如果你把这种地址塞给 CentOS 7yum 虽然能连上服务器但拿到的包版本、GPG key 都和 7 不匹配最后会引发更多依赖问题。vault 目录下的 7.9.2009 才是 7 系的存档路径不能混。改完后还要处理一下 SCL 源。很多 CentOS 7 机器上有 centos-sclo-rh 和 centos-sclo 这两个源文件EOL 之后它们也跟着失效报错就是Cannot find a valid baseurl for repo: centos-sclo-rh/x86_64这个源和我们要装的 compat-openssl10 没关系直接禁用最省心sed -i s/enabled1/enabled0/ /etc/yum.repos.d/CentOS-SCLo-scl.repo /etc/yum.repos.d/CentOS-SCLo-scl-rh.repo最后清理缓存让 yum 重新拉取元数据yum clean all yum makecachemakecache 成功输出“Loaded plugins... base/7/x86_64 ... 157 MB”之类的内容就说明源已经活了。这一步虽然不直接解决 OpenSSL 报错但它是所有后续操作的基础。没有可用源后面全白搭。2.3 顺带验证一下系统现状在动手装任何东西之前先花一分钟确认系统状态。这几条命令我每次都会敲一遍属于基本操作cat /etc/os-release uname -m rpm -qa | grep openssl ldconfig -p | grep libcrypto如果是 x86_64 架构输出里应该是 openssl-libs、openssl 等包。如果 ldconfig 的输出里只有 libcrypto.so.1.1 或 libcrypto.so.3没有 libcrypto.so.10那结论就很清晰系统里缺少 OpenSSL 1.0.x 兼容库。3. 安装 compat-openssl10让你少折腾 90% 的首选方案3.1 三行命令搞定 yum 安装流程源修好之后最省事的做法是直接用 yum 安装 compat-openssl10 这个包。它在 CentOS 7 官方源里一直存在用途就是提供 OpenSSL 1.0.x 的兼容库让老软件能继续跑。yum -y install compat-openssl10这个包安装完成后会往系统里放两个关键文件/usr/lib64/libcrypto.so.10/usr/lib64/libssl.so.10注意不要自己去网上随便下载“openssl-1.0.2k”之类的源码包去编译。虽然编译也能得到 libcrypto.so.10但你在 CentOS 7 上手动编译 OpenSSL 1.0.2 会有另一个坑它默认安装到 /usr/local/ssl而且一堆老补丁没有打上编译参数也未必和 rpm 一致后面很容易出现版本符号对不上的诡异问题。用官方 compat 包是最干净的。如果你执行 yum install 之后提示“No package compat-openssl10 available”多数情况下就是源没有刷成功。先跑一遍 yum clean all yum makecache确认 makecache 没有报错再装一次。如果还不行用 yum search openssl10 看看源里有哪些包可用。3.2 验证库文件是否真正到位安装完不要急着装 Erlang先验证库是否真的生效。这是很多人跳过的步骤跳过之后就得来回折腾排查。ls -l /usr/lib64/libcrypto.so.10这一步确认文件存在。接着用 rpm 确认它属于哪个包rpm -qf /usr/lib64/libcrypto.so.10输出应该是 compat-openssl10-1.0.2o-3.el7_9.x86_64 之类的包名。再深入一层检查符号版本列表里有没有 OPENSSL_1.0.2strings /usr/lib64/libcrypto.so.10 | grep OPENSSL_1.0.2如果你看到 OPENSSL_1.0.2 这行输出说明符号版本没问题。这个验证非常重要因为我见过有人系统里同时存在多个 OpenSSL 库文件结果 yum 装的是老库Erlang 运行时加载的却是别的路径下的新库。这种混乱状态要用 ldconfig -p | grep libcrypto 来看全局搜索路径下到底有哪些库。3.3 再把 Erlang 装上完整复现过程库就位后回到最初的报错场景。假设你已经下载了 erlang-22.0.7-1.el7.x86_64.rpm 这个文件建议用 yum 而不是 rpm 来安装让 yum 自动解析剩余的依赖yum -y install ./erlang-22.0.7-1.el7.x86_64.rpm注意我写的是 ./erlang-22.0.7-1.el7.x86_64.rpm这样 yum 会把它当成一个本地文件包来解析。如果还缺别的依赖yum 会从前面修好的 vault 源里自动拉取。安装成功后验证 Erlang 能否正常加载 OpenSSL 相关模块erl -version如果想更严格一点可以用一个简单的 Erlang 表达式测试加密模块erl -eval io:format(~s~n, [erlang:system_info(otp_release)]), halt().如果输出 22说明 Erlang 22 已经能正常跑起来。这里有个容易被忽略的点Erlang 的加密模块 crypto 在启动时会动态加载 libcrypto.so.10如果加载失败erl 虽然能启动但调用 crypto 模块时会报 undef。所以最好连 crypto 模块一起测erl -eval io:format(~p~n, [crypto:supports()]), halt().能输出一个包含 ciphers、hashes 等信息的 map才算真的万事大吉。4. 源彻底不可用时手工下载 rpm 的兜底路线4.1 从哪里找对的 rpm 包有时候场景比较极端机器不能联网访问 vault或者公司内网只有指定镜像可用。这种情况下手工下载 rpm 包再本地安装就是必须掌握的一招。compat-openssl10 对应 rpm 包的官方存档地址是https://vault.centos.org/7.9.2009/os/x86_64/Packages/compat-openssl10-1.0.2o-3.el7_9.x86_64.rpm如果你在清华镜像或者阿里云镜像上找路径类似但要注意目录层级。以清华镜像为例https://mirrors.tuna.tsinghua.edu.cn/centos-vault/7.9.2009/os/x86_64/Packages/compat-openssl10-1.0.2o-3.el7_9.x86_64.rpm下载命令wget https://vault.centos.org/7.9.2009/os/x86_64/Packages/compat-openssl10-1.0.2o-3.el7_9.x86_64.rpm下载完以后用 rpm -ivh 或者 yum localinstall 安装都行。我个人更推荐 yum localinstall因为它会自动检查并尝试解析缺失的依赖yum localinstall ./compat-openssl10-1.0.2o-3.el7_9.x86_64.rpm如果你的系统上还缺其它基础依赖yum 会一并告诉你你只要继续用 vault 源补齐就行。4.2 先看依赖再动手别等到最后一步才发现缺包这里分享一个我踩过几次坑之后养成的习惯无论安装哪个 rpm 包先查它的依赖再安。尤其是老包依赖往往不止一个。rpm -qpR erlang-22.0.7-1.el7.x86_64.rpm这条命令会列出这个包所依赖的所有文件、库和包名。输出里你会看到除了 libcrypto.so.10(OPENSSL_1.0.2)(64bit) 之外还可能有一堆 libstdc.so.6、libncurses.so.5 之类的依赖。提前知道就能一次性把该装的装齐不用等 rpm 报一个错再装一次。如果只想检查某一个依赖项是否被满足可以用rpm -q --whatprovides libcrypto.so.10(OPENSSL_1.0.2)(64bit)有输出说明系统里已经有包可以满足这个依赖没输出就说明还缺。这个命令在排查“我明明装了 compat 包为什么还报错”的问题时特别好用。4.3 为什么不能随便用软链接糊弄过去网上有一种“野路子”让人直接把新版库软链成老库名字ln -s /usr/lib64/libcrypto.so.1.1 /usr/lib64/libcrypto.so.10我必须说这条路十有八九走不通而且会让问题更隐蔽。原因还是回到前面说的符号版本。OpenSSL 1.1.x 的库文件里符号版本名称是 OPENSSL_1_1_0、OPENSSL_1_1_1 这些没有 OPENSSL_1.0.2。你拿 libcrypto.so.1.1 去冒充 libcrypto.so.10文件是有了rpm 依赖检查这一关也可能蒙混过去但 Erlang 一启动动态加载器找 OPENSSL_1.0.2 符号版本时就会直接报version OPENSSL_1.0.2 not found这是运行时错误比安装时报错更难排查。我帮人处理过一个这样的案例对方软链完以后 Erlang 能安装成功但一跑 RabbitMQ 就崩溃排查了两天才发现问题在软链上。所以我的建议是除非只是临时验证否则绝对不要用软链接代替真正的兼容库包。你要的是 compat-openssl10 提供的那个带 OPENSSL_1.0.2 符号版本的真库不是一个同名空壳。5. 实测中经常翻车的几个细节5.1 32 位和 64 位依赖混装前面提到过 64bit 这个关键词这里展开讲一下。CentOS/RHEL 的库目录分两个/usr/lib 放 32 位库/usr/lib64 放 64 位库。如果你装了一个 i686 的 compat-openssl10文件会落在 /usr/lib/libcrypto.so.10而 Erlang 找的是 /usr/lib64/libcrypto.so.10位置不对一样报错。排查命令很简单ls -l /usr/lib/libcrypto.so.10 /usr/lib64/libcrypto.so.10如果你看到 i686 的包装到了系统里卸载掉重新装对架构rpm -qa | grep compat-openssl rpm -e compat-openssl10-1.0.2o-3.el7_9.i686然后重新安装 x86_64 版本。这个坑在 Docker 镜像里特别常见因为有些基础镜像为了兼容性会默认带上 32 位库。5.2 装完兼容库依然报错的排查清单我自己调试这类问题的时候会按一套固定的流程走这里整理成一张速查表方便你对照排查。现象可能原因排查方法解决方式yum install compat-openssl10 提示无此包yum 源没生效或缓存过期yum clean all yum makecache重新配置 vault 源后重试报 base/7/x86_64 找不到 baseurlCentOS 7 源失效cat /etc/yum.repos.d/CentOS-Base.repo改用 vault.centos.org 地址报 centos-sclo-rh/x86_64 找不到SCL 源失效ls /etc/yum.repos.d/删除或禁用 sclo 相关 repo安装后仍提示需要 libcrypto.so.10装了 i686 库或文件路径不对ls /usr/lib64/libcrypto.so.10卸载 i686 包装 x86_64 包Erlang 启动报 OPENSSL_1.0.2 not found用过软链接或库符号版本不符strings /path/to/libcrypto.so.10 | grep OPENSSL_1.0.2卸载软链接安装官方 compat 包erlang 报其它缺失依赖老包依赖链长缺 libstdc 等rpm -qpR erlang...rpm用 yum install ./erlang...rpm 自动补齐yum makecache 卡住或速度慢网络限制访问 vault换国内镜像源使用清华、阿里镜像的 centos-vault 路径这张表基本覆盖了我见过的 90% 报错场景。如果你按表排查完还没解决大概率是系统里有多套 OpenSSL 共存导致的混乱建议用ldd直接看 Erlang 二进制实际加载的是哪个路径的库ldd /usr/lib64/erlang/bin/beam.smp | grep crypto输出里会明确显示加载的 libcrypto 路径如果指向了错误路径问题就很容易定位了。5.3 不要一上来就 --nodeps 强装还有一个非常常见的错误操作是看到依赖报错后直接 rpm -ivh --nodeps erlang-22.0.7-1.el7.x86_64.rpm 强装。我理解这种操作的冲动但强烈建议别这么干。--nodeps 会绕过依赖检查让包安装成功但系统里的依赖问题并没有消失只是被推迟到了运行期。Erlang 装上以后crypto 模块加载失败RabbitMQ 起不来到时候报错信息更隐蔽排查成本更高。正确的操作顺序永远是先满足依赖再安装本体。依赖检查是保护机制不是故意给你添堵的。6. 另外几个我在生产环境里摸索出来的习惯这次写下来感觉最值得分享的不只是命令而是排查这类问题的思路。踩过几次坑之后我现在遇到安装报错第一反应永远是先看两样东西系统源状态和依赖树。很多人在网上盲目搜索“erlang 装不上”其实问题要么出在 yum 源失效要么出在缺少兼容库。把源修好再理清依赖关系剩下的事情就非常机械了。最后再分享一个小技巧。如果你是在容器环境里遇到同样的问题直接用带 OpenSSL 1.0.x 兼容层的基础镜像或者干脆在 Dockerfile 里加上RUN yum -y install compat-openssl10比每次进容器手工处理要省心得多。如果是 Ubuntu/Debian 系统被迫运行 el7 的包也可以找 libssl1.0.0 或 libssl1.0.2 这类老版本库来满足依赖思路是一样的。但在 x86_64 的 CentOS 系系统上compat-openssl10 依然是最省事、最干净的答案。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进