一、故障背景:一次"理所当然"的部署翻车
最近在帮一个政务客户做信创数据库迁移项目,需要把原来跑在商用数据库上的业务系统迁移到KingbaseES(以下简称KES)上。客户那边的架构需求很明确:两节点高可用,主备共享数据,用现成的NFS共享存储,这样主节点出问题时备节点能直接挂载数据目录拉起服务,省去数据迁移的麻烦。
整套方案听起来稳得不能再稳,NFS服务端早就搭好了,万兆内网也配齐了,安装包、用户、权限按文档一步步配置,按理说就是个"常规操作"。结果一执行安装脚本,迎面就是一记闷棍:
-bash-4.4$ cd kingbase
-bash-4.4$ sh setup.sh
-bash: /usr/bin/sh: Operation not permitted
更骚的操作来了,我下意识觉得是权限问题,直接祭出运维三板斧:
-bash-4.4$ chmod 777 setup.sh
chmod: changing permissions of 'setup.sh': Read-only file system
文件系统居然变成只读的了?我刚才明明能 touch 新建文件啊。当时整个人就有点懵——这看起来像权限问题,但又透着一股"不像权限问题"的诡异。
二、排障过程:从瞎试到对症下药
2.1 第一轮:常规权限排查全部失效
碰到权限报错,先按经验走一遍:
| 排查方向 | 操作 | 结果 |
|---|---|---|
| 文件权限 | ls -l setup.sh 看是否有 x 位 | 权限正常,777都给了 |
| 用户身份 | whoami / id 确认 | 用户没问题 |
| SELinux | setenforce 0 临时关闭 | 报错依旧 |
| 防火墙 | systemctl stop firewalld | 没用 |
| 磁盘空间 | df -h 看是否撑爆 | 空间充足 |
每一项都打脸,常规手段全部失效。这时候我注意到一个细节——shell提示符是 -bash-4.4$ 而不是正常的 [user@host ~]$,这说明用户的 .bashrc 根本没被加载。
2.2 关键转折:环境变量没加载
为了验证猜测,我直接看环境变量:
-bash-4.4$ echo $PATH
/usr/local/bin:/usr/bin
-bash-4.4$ echo $LD_LIBRARY_PATH
果然,LD_LIBRARY_PATH 是空的,PATH 也只剩系统默认值。我之前用root身份编辑了 /home/kes/.bashrc,然后用 su kes(注意没带横杠)切换过来,根本没加载用户的配置文件。
抱着死马当活马医的心态执行:
source ~/.bashrc
./setup.sh
报错消失,安装顺利启动。
2.3 为什么NFS下这个错特别迷惑?
事后用 strace -f 跟踪了一遍调用过程,把这个坑的本质搞清楚了:
环境变量缺失导致系统去默认路径找动态库,找不到匹配版本时,本地文件系统通常会返回 cannot open shared object file: No such file or directory 这种明确的"文件找不到"错误。但NFS不一样,NFS协议层有一套自己的安全拦截机制,加上Linux对网络文件系统上可执行内存映射的额外保护,最终把"找不到正确库"的错误统一转换成了 Operation not permitted——这就误导了所有的排错方向,让人以为是NFS权限或挂载问题。
一句话总结根因:Shell环境变量未加载,导致动态库路径错误,NFS的安全拦截把这类错误统一报为权限错误。
三、KES安装前环境检查清单(Pre-Installation Checklist)
吃一堑长一智,我整理了一份KES安装前必做的检查清单,建议照着一项项过,能避开90%的安装期报错。
3.1 用户与Shell环境检查
# 1. 确认登录shell是bash
echo $SHELL
# 2. 确认环境变量已加载(核心!)
source ~/.bashrc
echo $PATH
echo $LD_LIBRARY_PATH
# 3. 确认用户身份和UID/GID
whoami
id
这里有几个新手最容易栽的细节:
- KES的环境变量一定要写到
~/.bashrc,不要只写到~/.bash_profile。前者交互式shell都会加载,后者只有登录shell才加载,脚本执行环境拿不到。 - 切换数据库用户必须用
su - kes(带横杠),不带横杠的su kes只切换身份不切换环境。 - 改完配置文件,当前会话必须 source 一次,新开的窗口也要重新加载。
3.2 依赖库与系统环境
# 检查动态库依赖完整性
cd $KES_HOME/bin
ldd initdb | grep "not found"
# 常见依赖包(RHEL系)
yum install -y libaio-devel glibc-devel openssl-devel zlib-devel readline-devel
# 检查glibc版本(KES V8 要求 >= 2.17)
ldd --version
3.3 内核参数与资源限制
# 文件句柄、进程数
ulimit -n 65535
ulimit -u 65535
# 永久生效写到 /etc/security/limits.conf
echo "kes soft nofile 65535" >> /etc/security/limits.conf
echo "kes hard nofile 65535" >> /etc/security/limits.conf
# 内核参数
sysctl -p
3.4 安全模块与防火墙
# SELinux 临时关闭
setenforce 0
# 永久关闭:编辑 /etc/selinux/config,SELINUX=disabled
# 防火墙放行端口(默认54321)
firewall-cmd --permanent --add-port=54321/tcp
firewall-cmd --reload
3.5 NFS挂载专项检查
# 查看挂载状态
mount | grep nfs
# 测试目标目录的读、写、执行权限
cd /data/kes_data
touch test_rw && rm test_rw
echo "echo ok" > test.sh && sh test.sh && rm test.sh
只要这三个测试都能通过,再开始安装数据库,基本不会中途翻车。
四、KES在NFS/共享存储环境的部署策略
NFS部署KES能不能用、稳不稳,是很多客户都关心的问题。说结论:用对了完全稳定,关键看场景选型和参数配置。
4.1 NFS服务端配置规范
/etc/exports 标准模板:
/kes_share 192.168.1.0/24(rw,sync,no_root_squash,insecure)
每个参数的含义:
rw:开放读写,必须sync:同步写入,保证数据一致性,绝对不要用 async,掉电容易丢数据no_root_squash:保留root权限映射,否则客户端root会被压缩成 nfsnobody,导致诡异权限问题insecure:允许客户端使用大于1024的高端口连接
4.2 客户端挂载参数推荐
mount -t nfs -o rw,exec,hard,intr,tcp,noatime,nodiratime,rsize=131072,wsize=131072,timeo=600 \
192.168.1.10:/kes_share /data/kes_data
写入 /etc/fstab 实现开机自动挂载:
192.168.1.10:/kes_share /data/kes_data nfs defaults,tcp,rw,exec,hard,intr,noatime,nodiratime 0 0
几个挂载参数必须重点关注:
| 参数 | 作用 | 备注 |
|---|---|---|
exec | 允许执行可执行文件 | 默认很多发行版会带 noexec,必须显式开启 |
hard | 服务端断开时进程一直重试 | 数据库必须用 hard,soft 容易出脏数据 |
intr | 允许中断卡住的NFS调用 | 避免NFS服务端宕机时整个系统僵死 |
tcp | 使用TCP传输 | 比UDP稳定,数据库场景必选 |
noatime | 不更新文件访问时间 | 减少无谓IO,性能提升明显 |
4.3 UID/GID一致性
NFS基于UID/GID鉴权,不是用户名。所有节点的 kes 用户必须保持完全一致的UID和GID:
# 服务端和所有客户端都执行
groupadd -g 1001 kes
useradd -u 1001 -g 1001 kes
不一致会出现"用户名对得上但权限不对"的奇葩问题。
4.4 共享存储方案选型对比
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| NFS | 部署简单、成本低、维护方便 | 性能受网络制约、并发能力有限 | 中小规模高可用、开发测试、冷数据归档 |
| iSCSI | 块设备、性能优于NFS、稳定性高 | 部署较复杂、容量管理麻烦 | 核心业务高可用 |
| Ceph RBD | 分布式、扩展性好 | 网络要求高、运维复杂 | 大规模分布式部署 |
| 本地SSD | 性能最好、延迟最低 | 不能共享、HA需迁移数据 | 单节点核心业务 |
特别提醒:硬件存储自带的"阉割版NFS"务必小心,部分厂商的实现砍掉了文件锁机制,KES启动时需要锁文件,没有锁会直接启动失败,这种坑非常隐蔽。
五、KES运维中的Shell脚本调试艺术
这次问题本质是Shell环境问题,做了这么多年DBA运维,分享几个排查环境类故障的核心技巧。
5.1 排查环境问题第一步永远是验证环境变量
碰到任何奇怪报错,先别急着搜错误信息、改配置,第一句命令永远是:
echo $PATH
echo $LD_LIBRARY_PATH
which initdb
10秒钟就能定位是不是环境变量的问题,别等折腾两小时才想起来。
5.2 用 strace 跟踪定位根因
Operation not permitted 这种模糊错误,靠猜永远猜不准,直接上 strace:
strace -f -o trace.log ./setup.sh
grep EACCES trace.log
grep EPERM trace.log
看输出最后几行,到底是哪个系统调用、访问哪个文件时报的错,一目了然。这次的问题用 strace 一跟就能看到是加载 NFS 上的动态库时被拦截,根本不会去瞎改NFS权限。
5.3 Shell 脚本调试三件套
#!/bin/bash
set -x # 打印每条执行的命令
set -e # 遇错即退出
set -u # 引用未定义变量报错
set -o pipefail # 管道中任一命令失败都算失败
写KES启停脚本、备份脚本时强烈建议加上,出问题能快速定位是哪一步、哪个变量值不对。
5.4 开机启动脚本必须显式加载环境
很多人开机启动KES失败,明明手动启动都正常,根因就是开机启动时是纯净环境,没加载用户的 .bashrc。所有systemd服务文件或启动脚本,开头都要显式加载:
#!/bin/bash
source /home/kes/.bashrc
$KES_HOME/bin/sys_ctl start -D $KES_DATA
systemd 服务单元也要明确指定环境:
[Service]
Type=forking
User=kes
EnvironmentFile=/home/kes/.kes_env
ExecStart=/home/kes/kingbase/bin/sys_ctl start -D /data/kes_data
5.5 Shell会话独立性陷阱
每个Shell窗口的环境是相互独立的。在A窗口source了配置文件,B窗口不会自动生效。多窗口操作时养成"先 source 再操作"的习惯,能避免一大堆灵异问题。
六、写在最后
回头看这次故障,技术上一点都不复杂,就是 source ~/.bashrc 一行命令的事。但能折腾我三个小时,是因为:
- 错误信息有误导性:NFS把"动态库加载失败"包装成了"Operation not permitted",让人下意识往权限方向排查
- 思维定式:看到权限错误就
chmod 777,看到执行不了就检查 SELinux,从来不会先看环境变量 - 小细节被忽略:
su和su -一个横杠的差别,.bashrc和.bash_profile加载时机的差别,这些细节平时没人会专门讲,但坑人的时候毫不留情
最后总结四条核心避坑要点:
- 改完环境变量,当前 shell 必须
source一次,新窗口也要重新加载 - 切换数据库用户用
su - username,带横杠,永远带横杠 - NFS 挂载参数里
exec、hard、tcp、sync一个都不能少,UID/GID 全节点必须一致 - 碰到
Operation not permitted先别动权限,先echo $PATH和echo $LD_LIBRARY_PATH
NFS部署KES本身不是洪水猛兽,按规范配置完全可以稳定运行多年。把检查清单沉淀下来,把调试方法练成肌肉记忆,遇到问题才能快速定位、快速恢复。希望这篇排障实录能帮到正在做信创数据库部署的同行,少踩点不必要的坑。