NFS共享存储下数据库安装报错Operation not permitted排障实录与运维避坑指南

2 阅读2分钟

一、故障背景:一次"理所当然"的部署翻车

最近在帮一个政务客户做信创数据库迁移项目,需要把原来跑在商用数据库上的业务系统迁移到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 确认用户没问题
SELinuxsetenforce 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 一行命令的事。但能折腾我三个小时,是因为:

  1. 错误信息有误导性:NFS把"动态库加载失败"包装成了"Operation not permitted",让人下意识往权限方向排查
  2. 思维定式:看到权限错误就 chmod 777,看到执行不了就检查 SELinux,从来不会先看环境变量
  3. 小细节被忽略susu - 一个横杠的差别,.bashrc.bash_profile 加载时机的差别,这些细节平时没人会专门讲,但坑人的时候毫不留情

最后总结四条核心避坑要点:

  • 改完环境变量,当前 shell 必须 source 一次,新窗口也要重新加载
  • 切换数据库用户用 su - username,带横杠,永远带横杠
  • NFS 挂载参数里 exechardtcpsync 一个都不能少,UID/GID 全节点必须一致
  • 碰到 Operation not permitted 先别动权限,先 echo $PATHecho $LD_LIBRARY_PATH

NFS部署KES本身不是洪水猛兽,按规范配置完全可以稳定运行多年。把检查清单沉淀下来,把调试方法练成肌肉记忆,遇到问题才能快速定位、快速恢复。希望这篇排障实录能帮到正在做信创数据库部署的同行,少踩点不必要的坑。