前几天,因为node报错导致CI服务器无法自动编译vue,我进行一通操作,很不幸,我把服务器搞崩了。为了避免相同的悲剧再次发生,我把过程记录一下,仅供参考。
1. 起因
前几天遇到一件奇怪的事情。不知什么原因,突然配置的gitlab的前端自动编译CI环境报错了。
无论是执行node命令,还是npm命令,都会出现如下的错误提示:
node: relocation error: /lib64/libnode.so.93: symbol FIPS_selftest, version OPENSSL_1_1_0g not defined in file libcrypto.so.1.1
2. 过程
尝试一:对错误信息进行网络检索
通过对错误原文进行网络检索,得到的信息大多是升级openssl。我使用yum,对openssl进行了升级操作,不起作用。
yum update openssl
尝试二:服务重装
多番查找和尝试均不成功,于是我萌生了重新安装node和npm的想法。然而重装依然失败了。
yum remove node,npm
yum clear cache
yum install -y node,npm
尝试三:升级
考虑也许服务器上的node版本不够高或当前版本有错误导致,于是尝试升级nodejs和npm。
由于yum上nodejs的版本固定(16.15),想要升级就只能更新yum源或直接编译安装高版本的nodejs。可以访问nodejs官网下载源码进行编译安装。在此,我选择了18.3.0的版本。
编译安装过程:
wget https://nodejs.org/dist/v18.3.0/node-v18.3.0-linux-x64.tar.gz
tar -xvzf node-v18.3.0-linux-x64
cd node-v18.3.0-linux-x64
./configure --prefix=/usr/local/nodejs
make & make install
执行到这里,nodejs就安装到了/usr/local/nodejs里了。还需要做一件事情,就是给/usr/bin/node加上软链接。
cd /usr/local/bin
ln -s /usr/local/nodejs/bin/node node # 如果当前路径存在其他版本的node,需要先删除。
node -v
如果顺利,就能显示出版本号是18.3.0了。
升级之后,确实一开始的错误不见了。但是取而代之的是出现了新的错误:/lib64/libm.so.6: version `GLIBC_2.28' not found (required by node)
分析原因,是因为高版本的nodejs需要更高版本的glibc编译环境,目前我服务器centos7.5,对应的glibc最高只能支持到2.17。
参考网络上的文章,我开始着手升级glibc,选择了2.28版本的glibc。
然而升级glibc极度危险,我在这步也是栽了很大的跟头。
1. 升级glibc
升级glibc的工作极度不顺利。首先是提示gcc和make的版本太低了。
# 首先查看支持的glibc版本
strings /lib64/libc.so.6 | grep GLIBC -head 20
wget https://ftp.gnu.org/gnu/glibc/glibc-2.28.tar.gz
tar -xzvf glibc-2.28.tar.gz
cd glibc-2.28
# 创建临时文件
mkdir build && cd build
../configure --prefix=/usr --disable-profile --enable-add-ons --with-headers=/usr/include --with-binutils=/usr/bin
# 这一步时, 发生了错误, 提示大致为
These critical programs are missing or too old: make compiler
2. 升级gcc
# 查看gcc版本
gcc -v
wget http://ftp.gnu.org/gnu/gcc/gcc-11.2.0/gcc-11.2.0.tar.gz # http://ftp.gnu.org/gnu/gcc查看所有版本
tar -zxvf gcc-11.2.0.tar.gz
cd gcc-11.2.0
./contrib/download_prerequisites
mkdir build
cd build/
../configure -enable-checking=release -enable-languages=c,c++ -disable-multilib
make -j 4 # 这一步make时间很长,可以通过j选项进行同步编译,建议不超过cpu核心数的两倍。
make install
gcc -v # 再次确认版本。
# 如果gcc版本不对,可以使用命令which gcc,并查看相应位置的gcc的版本。之后替换成新编译的gcc即可。
3. 升级make
make -v # 查看版本
wget http://ftp.gnu.org/pub/gnu/make/make-4.3.tar.gz # 下载4.3版本。http://ftp.gnu.org/pub/gnu/make/ 查看所有版本
tar -zxvf make-4.3.tar.gz
cd make-4.3
./configure --prefix=/usr
type make
make check
make install
make -v # 再次确认版本
4. 继续升级glibc
一切顺利了之后,查看glibc文件的链接情况:
ll /lib64/libc.so.6
/lib64/libc.so.6 -> ./libc-2.17.so
可以看到,libc.so.6 还是指向的2.17版本。
此时需要更新软链到2.28。然而此步极其危险。因为如果你删除了libc.so.6这个软链,你会发现所有的基本命令都会出现错误提示。segmentation fault
此时需要执行:
LD_PRELOAD=/lib64/libc-2.28.so ln -s /lib64/libc-2.28.so /lib64/libc.so.6
5. 问题复盘
理论上没问题,现实情况是,我的2.28编译失败了,提示:all warnings being treated as errors
头铁的我,无视了报错信息,执行了强行编译。链接做完之后,ssh客户端立马被踢出,再次登录均显示连接拒绝。登录腾讯后台的VNC登录,发现服务器在无限重启。。。
后来只好和客服沟通,经过一番交涉和等待,终于服务器恢复正常。代价是服务器有大约1天无法正常使用。
尝试四:降级
虽然服务器恢复了,但是前端编译CI报错问题依旧,还是需要处理的。
既然升级不行,那要不试试降级?
再次网络上检索,发现有人升级node12.19.1版本时,需要升级glibc2.17。这不正好就是我服务器上的版本吗?于是我这次改成将服务器上的node16.15降级成12.19试试。以往的版本 | Node.js (nodejs.org)
按照和前面类似的方法,将node部署到/usr/local/nodejs中,运行/usr/local/nodejs/bin/node -v时,发现一切正常!这是一个非常好的信号。
接下来,重新按照npm。注意nodejs和npm是有版本关联的,否则会报错:npm does not support Node.js v12.19.1
nodejs和npm对应版本信息,可以在这里检查:以往的版本 | Node.js (nodejs.org)
接下来的升级,就可以由npm的命令行来执行了:
npm install -g npm@6.14.8
成功了之后,重新生成一下node_modules
rm -rf [project_path]/node_modules
npm install
最后一步,回到gitlab的CI页面,对错误的作业点击重试,终于大功告成!
3. 总结
- glibc升级很敏感,如果不是linux管理员或很有经验的人,千万慎重!
- 升级为最新版本未必是最好的解决方案,有时候降级反而是更好的选择!
- 只要决心大,困难不可怕。