记一次NFS下的权限踩坑:从“Operation not permitted”到安装成功的折腾实录

记一次NFS下的权限踩坑:从"Operation not permitted"到安装成功的折腾实录

事情是这样开始的

上周五晚上,快下班的时候,同事在群里发了个截图,配文是"这数据库装不上了,帮忙瞅一眼"。

我点开一看,命令行界面躺着一串红色报错:

bash 复制代码
-bash-4.4$ sh setup.sh
-bash: /usr/bin/sh: Operation not permitted
-bash-4.4$ chmod -R 777 setup.sh
chmod: changing permissions of 'setup.sh': Read-only file system
-bash-4.4$ ./setup.sh
Now launch installer...
tee: .installer.log: Read-only file system

看到这几行,我心里大概有数了。不是脚本本身的问题,是环境的问题。

我问他:"你这个目录在哪儿?" "NFS挂的共享存储。"

果然。

先说说NFS是个什么情况

NFS这东西,说白了就是通过网络把一台机器上的目录"借"给另一台机器用。你在客户端看到的是本地文件夹,实际读写操作都要通过网络发到服务端去执行。

这种机制带来了一个挺隐蔽的问题:权限判断不是客户端说了算的。

你在本地执行chmod 777,这个命令会打包成网络请求发给服务端。服务端收到后,用自己那套规则来判断要不要执行。如果服务端那边挂载时配的是只读,那不管你本地怎么改,写操作都会被拒绝。

同事遇到的情况就是典型的例子。Read-only file system这个提示已经说得很明白了------文件系统是只读的,任何写入都不让干。

排查过程:一步步找问题

我先让同事确认了几件事。

第一步,看看挂载状态:

bash 复制代码
mount | grep cluster_nfs

输出里如果有ro这个标志,说明挂载的时候就是只读模式。如果没有ro而是rw,那可能是别的原因。

第二步,试试能不能写文件:

bash 复制代码
touch /home/test/pan/cluster_nfs/test.txt

这个命令直接报错的话,就坐实了只读的问题。

第三步,检查一下环境变量:

bash 复制代码
echo $PATH
which sh

同事执行完告诉我,/usr/bin/sh这个路径是存在的,但执行时就是报Operation not permitted。这个报错比普通的Permission denied更底层------普通权限问题系统会说"不允许",但Operation not permitted往往意味着操作被内核或安全模块拦截了。

问题到底出在哪儿

我把几个线索串起来想了想:

  1. 文件系统是只读的------这解释了为什么chmod改不了权限
  2. NFS挂载的------这解释了权限判断为什么绕弯子
  3. 执行sh setup.sh时报Operation not permitted------这比只读更奇怪,因为执行脚本本身是读操作,不是写操作

后来同事跟我说,执行了一下source .bashrc,然后就好了。

我愣了一下。就这么简单?

仔细想想,source .bashrc干的事情是重新加载当前用户的Shell配置。.bashrc这个文件里通常放着环境变量、别名、还有------自定义的NFS挂载参数

如果登录的时候.bashrc没被自动加载(这种情况很常见,比如su切用户或者某些非交互式登录),那NFS挂载可能用的是一套默认参数。重新加载之后,正确的参数(包括rw读写模式)才生效。

说白了,问题不是出在权限本身,而是出在环境没准备好

后来我整理了一份NFS环境下的检查清单

踩过一次坑,就得记住教训。我把这次遇到的问题和解决过程整理成了几条检查项,以后在NFS上装东西之前先过一遍。

第一项:确认挂载是读写的

bash 复制代码
mount | grep "你的目录" | grep -E "rw|ro"

看到rw才算正常。

第二项:实际测一下能不能写

bash 复制代码
touch 你的目录/test.txt && rm 你的目录/test.txt && echo "可以写"

能写入才能继续。

第三项:确认Shell环境是完整的

bash 复制代码
echo $PATH

如果PATH看起来不正常,执行一下source ~/.bashrc重新加载。

第四项:检查NFS挂载参数

bash 复制代码
cat /proc/mounts | grep nfs

这里能看到更详细的挂载参数。对于数据库安装这种场景,建议带上这些参数:

  • rw:读写
  • hard:硬挂载,出错了会持续重试
  • vers=3:用NFS版本3,比版本4更稳
  • tcp:用TCP协议
  • noatime:不记录文件访问时间,减少网络开销

第五项:检查用户ID是否一致

bash 复制代码
id

NFS环境下,客户端的UID需要和服务端匹配。不匹配的话,可能出现"明明是我创建的文件,系统却不认"的怪事。

顺手写了个预检脚本

被折腾过一次之后,我写了个小脚本,每次在NFS上装东西之前跑一遍,提前发现问题:

bash 复制代码
#!/bin/bash

echo "=== NFS环境预检 ==="

# 检查挂载状态
if mount | grep -q "nfs.*ro,"; then
    echo "[失败] 目录是只读挂载的,需要改成rw"
    exit 1
else
    echo "[通过] 目录是读写挂载"
fi

# 检查写入权限
if touch .test_$$ 2>/dev/null; then
    rm -f .test_$$
    echo "[通过] 可以正常写入"
else
    echo "[失败] 无法写入,请检查挂载状态或磁盘空间"
    exit 1
fi

# 检查磁盘空间
AVAIL=$(df --output=avail . | tail -1)
if [ $AVAIL -lt 10485760 ]; then
    echo "[警告] 磁盘空间不足10GB,只剩$((AVAIL/1024))MB"
else
    echo "[通过] 磁盘空间充足"
fi

echo "=== 预检完成 ==="

几个有用的排查命令

这些命令是平时积累下来的,遇到NFS相关的问题时基本都会用到:

bash 复制代码
# 看NFS统计信息,判断有没有丢包或重试
nfsstat -c

# 看服务端导出了哪些目录
showmount -e NFS服务器IP

# 看系统日志里的NFS报错
tail -f /var/log/messages | grep nfs

# 测试NFS读写速度
dd if=/dev/zero of=test.img bs=1M count=100

总结一下这次的经验

折腾了一圈,最后解决问题的就是一行source .bashrc。但这一行命令背后,折射出的是NFS环境的特殊性:

  1. 权限是两层判断------客户端和服务端共同决定,不能只看本地
  2. 环境变量要到位 ------很多自定义配置藏在.bashrc里,没加载就等于没用
  3. 挂载参数要正确 ------rwro差一个字,结果天差地别

数据库安装这种事情,很多时候问题不在安装包本身,而在环境准备。NFS、网络存储这类特殊环境,更容易出一些"本地想不到"的问题。

希望这篇踩坑记录能帮到遇到类似问题的人。下次在NFS上装东西之前,记得先跑一遍预检脚本,省得半夜还在排查。

相关推荐
妙蛙种子3112 小时前
【Java设计模式 | 创建者模式】 原型模式
java·开发语言·后端·设计模式·原型模式
阿聪谈架构2 小时前
第07章(下):LangGraph 工作流进阶 —— 检查点、人工介入与多 Agent 协作
人工智能·后端
希望永不加班2 小时前
SpringBoot 配置绑定:@ConfigurationProperties
java·spring boot·后端·spring
悟空码字2 小时前
MySQL性能优化的天花板:10条你必须掌握的顶级SQL分析技巧
java·后端·mysql
Soofjan2 小时前
Go interface 源码:iface、itab、getitab 与动态派发
后端
Soofjan2 小时前
Go interface:语法、接口值与常见坑
后端
写Cpp的小黑黑2 小时前
WebSocket 协议、帧结构与 MTU 详解
后端
white-persist2 小时前
【vulhub spring CVE-2018-1270】CVE-2018-1270 Spring Messaging 远程命令执行漏洞 完整复现详细分析解释
java·服务器·网络·数据库·后端·python·spring
神奇小汤圆3 小时前
Spring-Boot-泛型封装-这8个坑让我调了3天
后端