事情起因
发现有一台物理机只能连接同一个网段的公网,不能访问如百度,dns服务器也ping不通,我就想装个traceroute 看看是哪一步的原因,由于这台机器不能联网,于是就打算从隔壁机器下载deb包,到这个机器上安装。于是:
# 获取依赖,并下载
apt-rdepends traceroute | grep -v "^ " | xargs sudo apt-get download
# 打包
tar zcvf traceroute.tgz traceroute/
# 远程复制
scp <>
# 解压
tar zxvf traceroute.tgz
# 安装
cd traceroute&&dpkg -i *.deb
一气呵成,问题来了,所有命令都用不了了,报错/lib/x86_64-linux-gnu/libc.so.6: version 'GLIBC_2.30' not found (required by /lib/x86_64-linux-gnu/libselinux.so.1)
后来发现,隔壁机器跟这个机器不是同一个版本的操作系统,而且这些安装包里包含:gcc-6-base_6.0.1-0ubuntu1_amd64.deb libc6_2.23-0ubuntu11.3_amd64.deb libgcc1_1%3a6.0.1-0ubuntu1_amd64.deb traceroute_1%3a2.0.21-1_amd64.deb
。好好好。只能怨我眼瞎。犯了这么低级的错误。
更离谱的来了,因为我是刚来这家公司,发现这个k8s集群的部分woker节点情况如下:
OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
Ubuntu 18.04.1 LTS 4.15.0-147-generic docker://19.3.13
Ubuntu 16.04.3 LTS 4.4.0-210-generic docker://19.3.13
Ubuntu 16.04.2 LTS 4.4.0-210-generic docker://19.3.13
Ubuntu 16.04.3 LTS 4.4.0-210-generic docker://17.9.0
Ubuntu 16.04.3 LTS 4.4.0-210-generic docker://19.3.13
Ubuntu 16.04.2 LTS 4.4.0-210-generic docker://18.6.0
Ubuntu 16.04.2 LTS 4.4.0-62-generic docker://19.3.13
Ubuntu 16.04.2 LTS 4.4.0-62-generic docker://18.6.0
Ubuntu 16.04.3 LTS 4.4.0-91-generic docker://19.3.13
Ubuntu 18.04.4 LTS 4.15.0-192-generic docker://19.3.11
Ubuntu 18.04.4 LTS 4.15.0-156-generic docker://19.3.12
Ubuntu 20.04.5 LTS 5.4.0-125-generic containerd://1.6.12
Ubuntu 20.10 5.8.0-63-generic docker://20.10.6
Ubuntu 20.04.5 LTS 5.4.0-125-generic docker://20.10.18
好巧不巧,我操作的就是这个 ubuntu 20.10。这个版本从发布到中止维护仅有9个月的时间。都是前人挖的坑啊。
此情此景,我只能说 k8s 牛逼,不挑食。
言归正传。现在什么命令都用不了。
自救过程
现在已经打开的ssh是没有断开的,但是新的ssh已经连接不了了。根据网上的方法:
上传20.10用的glibc版本的 libc-2.32.so
LD_PRELOAD=/home/sysuser/libc-2.32.so ls
然而,并没有什么用。于此同时,我还手贱的打算复制一个ssh连接,好家伙,windterm
直接闪退。
那没有办法了,就只能去机房操作了。
首先了解一下这次操作到底都更新了哪些文件
这里使用docker的 layer 机制,就能很明显的看到那些文件发生了改变
# 运行一个ubuntu 20.10的容器
docker run -it --name ubunt-2010 -v /root:/data ubuntu:20.10 bash
# 安装相关的包
cd /data/traceroute
dpkg -i *.deb
# 发现问题与线上问题一致
root@ubuntu-2010:/data/traceroute# ls
ls: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.28' not found (required by ls)
ls: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.30' not found (required by /lib/x86_64-linux-gnu/libselinux.so.1)
root@ubuntu-2010:/data/traceroute# cp
cp: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.25' not found (required by cp)
cp: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.28' not found (required by cp)
cp: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.30' not found (required by /lib/x86_64-linux-gnu/libselinux.so.1)
接下来另起一个窗口:
docker inspect ubuntu-2010 --format '{{.GraphDriver.Data.UpperDir}}'
# cd 到这个目录
cd <上一步输出结果>
# 查看哪些文件夹发生了改变
tree
# 这里发现很多文件都改变了,于是只看看哪些目录
tree -d
.
├── data
├── etc
│ └── ld.so.conf.d
├── usr
│ ├── lib
│ │ ├── gcc
│ │ │ └── x86_64-linux-gnu
│ │ │ ├── 6
│ │ │ └── 6.0.0 -> 6
│ │ └── x86_64-linux-gnu
│ │ ├── audit
│ │ └── gconv
│ ├── lib64
│ └── share
│ ├── doc
│ │ ├── gcc-6-base
│ │ └── libc6
│ └── lintian
│ └── overrides
└── var
├── cache
│ └── debconf
├── lib
│ └── dpkg
│ ├── info
│ ├── triggers
│ └── updates
└── log
在启动一个新的ubuntu 20.10的容器,对比发现 /usr/lib/gcc/x86_64-linux-gnu
目录是新增的,新增一般影响不大。主要变动就是/usr/lib/x86_64-linux-gnu
。
解决思路就是把/usr/lib/x86_64-linux-gnu
备份一下,重新复制一份过去。
于是,在本地新建虚拟机,装上ubuntu 20.10的系统,模拟故障,使用ubuntu 20.10 desktop版本的live cd模式启动。把硬盘挂载到/mnt
目录,尝试恢复:
mv /mnt/usr/lib/x86_64-linux-gnu /mnt/usr/lib/x86_64-linux-gnubak
cp -rp /usr/lib/x86_64-linux-gnu /mnt/usr/lib
chroot /mnt
发现chroot不过去,怀疑是仍然有问题。于是,发现lib64下的ld-linux-x86-64.so.2文件也发生了变动。查看这个文件:
ll /lib64/ld-linux-x86-64.so.2
lrwxrwxrwx 1 root root 32 Sep 15 2020 /lib64/ld-linux-x86-64.so.2 -> /lib/x86_64-linux-gnu/ld-2.32.so*
把这个文件也复制回去,因为原来是个软连接,这里直接简单粗暴的把源文件复制过去了
cp /lib/x86_64-linux-gnu/ld-2.32.so /mnt/lib64/ld-linux-x86-64.so.2
chroot /mnt
根目录转化成功,实验命令可以正常执行。
于是去机房,关机、U盘启动,修复文件,搞定。
在运行过程中又发现,部分软件缺少文件,将/usr/lib/x86_64-linux-gnubak/
中的文件,复制但不替换回/usr/lib/x86_64-linux-gnu/
rsync -av --ignore-existing /usr/lib/x86_64-linux-gnubak/ /usr/lib/x86_64-linux-gnu/
当然,也可以在恢复/usr/lib/x86_64-linux-gnu/
时:
# 原来是mv,改为cp
cp -rp /mnt/usr/lib/x86_64-linux-gnu /mnt/usr/lib/x86_64-linux-gnubak
cp -rp /usr/lib/x86_64-linux-gnu/* /mnt/usr/lib/x86_64-linux-gnu
这样,直接覆盖掉修改过的文件(没试过,盲猜的)
总结
- 将
/usr/lib/x86_64-linux-gnu
替换回原操作系统内容- 替换回
/lib64/ld-linux-x86-64.so.2
- 将后期增加的
/usr/lib/x86_64-linux-gnu
下的文件,增量复制回去- 执行命令前,一定要看一眼到底执行了什么。不要闭着眼操作
- 服务器能跑,不影响业务使用,就不要管他。