HDFS客户端的权限错误:Permission denied(转载)

本文记录了在使用Hadoop HDFS客户端时遇到的权限错误,通过修改系统环境变量HADOOP_USER_NAME来解决用户认证问题,并提供了问题解决的完整步骤和代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

HDFS客户端的权限错误:Permission denied

2013年07月18日 Java 评论 2 条 阅读 5,751 views 次

搭建了一个Hadoop的环境,Hadoop集群环境部署在几个Linux服务器上,现在想使用windows上的Java客户端来操作集群中的HDFS文件,但是在客户端运行时出现了如下的认证错误,被折磨了几天,问题终得以解决。以此文记录问题的解决过程。

如果想看最终解决问题的方法拉到最后,如果想看我的问题解决思路请从上向下看

问题描述

上传文件的代码:

  1.     private static void uploadToHdfs() throws FileNotFoundException,IOException {
  2.         //我的文件地址
  3.         String localSrc = "E:\\快盘\\技术文档\\hadoop\\HDFS初步研究.pdf";
  4.         //存放在云端的目的地址
  5.         String dest = "hdfs://192.168.2.156:9000/user/HDFS初步研究.pdf";
  6.         InputStream in = new BufferedInputStream(new FileInputStream(localSrc));
  7.         //得到配置对象
  8.         Configuration conf = new Configuration();
  9. //        conf.set("fs.default.name","hdfs://192.168.2.156:9000");
  10.         //文件系统
  11.         FileSystem fs = FileSystem.get(URI.create(dest), conf);
  12.         //输出流
  13.         OutputStream out = fs.create(new Path(dest), new Progressable() {
  14.             @Override
  15.             public void progress() {
  16.                 System.out.println("上传完一个设定缓存区大小容量的文件!");
  17.             }
  18.         });
  19.         //连接两个流,形成通道,使输入流向输出流传输数据
  20.         IOUtils.copyBytes(in, out, 4096true);
  21.     }

错误的详细描述如下:

org.apache.hadoop.security.AccessControlException: org.apache.hadoop.security .AccessControlException: Permission denied: user=Administrator, access=WRITE, inode="hadoop": hadoop:supergroup:rwxr-xr-x

其实这个错误的原因很容易看出来,用户Administator在hadoop上执行写操作时被权限系统拒绝.

解决问题的过程

看到这个错误的,第一步就是将这个错误直接入放到百度google里面进行搜索。找到了N多篇文章,但是主要的思路就如此篇文章所写的两个解决办法:http://www.cnblogs.com/acmy/archive/2011/10/28/2227901.html

1、在hdfs的配置文件中,将dfs.permissions修改为False

2、执行这样的操作 hadoop fs -chmod 777 /user/hadoop

对于上面的第一个方法,我试了行不通,不知道是自己设置错误还是其他原因,对我此法不可行,第二个方法可行。第二个方法是让我们来修改HDFS中相应文件夹的权限,后面的/user/hadoop这个路径为HDFS中的文件路径,这样修改之后就让我们的administrator有在HDFS的相应目录下有写文件的权限(所有的用户都是写权限)。

虽然上面的第二步可以解决问题了,上传之后的文件所有者为Administrator,但是总感觉这样的方法不够优雅,而且这样修改权限会有一定的安全问题,总之就是看着不爽,就在想有没有其他的办法?

问题分析

开始仔细的观察了这个错误的详细信息,看到user=Administrator, access=WRITE。这里的user其实是我当前系统(运行客户端的计算机的操作系统)的用户名,实际期望这里的user=hadoop(hadoop是我的HADOOP上面的用户名),但是它取的是当前的系统的用户名,很明显,如果我将当前系统的用户名改为hadoop,这个肯定也是可以行得通的,但是如果后期将开发的代码部署到服务器上之后,就不能方便的修改用户,此方法明显也不够方便。

现在就想着Configuration这个是一个配置类,有没有一个参数是可以在某个地方设置以哪个用户运行呢?搜索了半天,无果。没有找到相关的配置参数。

最终只有继续分析代码, FileSystem fs = FileSystem.get(URI.create(dest), conf);代码是在此处开始对HDFS进行调用,所以就想着将HADOOP的源码下下来,debug整个调用过程,这个user=Administator是在什么时间赋予的值。理解了调用过程,还怕找不到解决问题的办法么?

跟踪代码进入 FileSystem.get-->CACHE.get()-->Key key = new Key(uri, conf);到这里的时候发现key值里面已经有Administrator了,所以关键肯定是在new key的过程。继续跟踪UserGroupInformation.getCurrentUser()-->getLoginUser()-->login.login()到这一步的时候发现用户名已经确定了,但是这个方法是Java的核心源码,是一个通用的安全认证,但对这一块不熟悉,但是debug时看到subject里面有NTUserPrincipal:Administator,所以就想着搜索一下这个东西是啥,结果就找到了下面这一篇关键的文章:

http://www.udpwork.com/item/7047.html

在此篇文章里面作者分析了hadoop的整个登录过程,对于我有用的是其中的这一段:

2.login.login();
这个会调用HadoopLoginModule的login()和commit()方法。
HadoopLoginModule的login()方法是一个空函数,只打印了一行调试日志 LOG.debug("hadoop login");
commit()方法负责把Principal添加到Subject中。
此时一个首要问题是username是什么?
在使用了kerberos的情况下,从javax.security.auth.kerberos.KerberosPrincipal的实例获取username。
在未使用kerberos的情况下,优先读取HADOOP_USER_NAME这个系统环境变量,如果不为空,那么拿它作username。否则,读取HADOOP_USER_NAME这个java环境变量。否则,从com.sun.security.auth.NTUserPrincipal或者com.sun.security.auth.UnixPrincipal的实例获取username。
如果以上尝试都失败,那么抛出异常LoginException("Can’t find user name")。
最终拿username构造org.apache.hadoop.security.User的实例添加到Subject中。

看完这一段,我明白了执行login.login的时候调用了hadoop里面的HadoopLoginModule方法,而关键是在commit方法里面,在这里优先读取HADOOP_USER_NAME系统环境变量,然后是java环境变量,如果再没有就从NTUserPrincipal等里面取。关键代码为:

  1. if (!isSecurityEnabled() && (user == null)) {
  2.   String envUser = System.getenv(HADOOP_USER_NAME);
  3.   if (envUser == null) {
  4.     envUser = System.getProperty(HADOOP_USER_NAME);
  5.   }
  6.   user = envUser == null ? null : new User(envUser);
  7. }

OK,看到这里我的需求也就解决了,只要在系统的环境变量里面添加HADOOP_USER_NAME=hadoop(HDFS上的有权限的用户,具体看自己的情况),或者在当前JDK的变量参数里面添加HADOOP_USER_NAME这个Java变量即可。我的情况添加系统环境变量更方法。

如果是在Eclipse里面运行,修改完环境变量后,记得重启一下eclipse,不然可能不会生效。

解决办法

最终,总结下来解决办法大概有三种:

1、在系统的环境变量或java JVM变量里面添加HADOOP_USER_NAME,这个值具体等于多少看自己的情况,以后会运行HADOOP上的Linux的用户名。(修改完重启eclipse,不然可能不生效)

2、将当前系统的帐号修改为hadoop

3、使用HDFS的命令行接口修改相应目录的权限,hadoop fs -chmod 777 /user,后面的/user是要上传文件的路径,不同的情况可能不一样,比如要上传的文件路径为hdfs://namenode/user/xxx.doc,则这样的修改可以,如果要上传的文件路径为hdfs://namenode/java/xxx.doc,则要修改的为hadoop fs -chmod 777 /java或者hadoop fs -chmod 777 /,java的那个需要先在HDFS里面建立Java目录,后面的这个是为根目录调整权限。

<think>首先,用户的问题是:“我想解决运行bootstrap.sh脚本时遇到的权限不足问题 请问Permission denied when running bootstrap.sh script”。这是一个权限问题,具体是运行bootstrap.sh脚本时出现“Permission denied错误。 从系统级指令来看: - 所有行内数学表达式必须使用$...$格式。 - 独立公式使用$$...$$格式。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 在回答中引用的段落末尾添加引用标识,如[^1]。 用户提供的引用: - 引用[1]:错误涉及权限被拒绝访问文件,如“EACCES: permission denied”。 - 引用[2]:另一个权限被拒绝错误,涉及HDFS和HBase。 - 引用[3]:一个启动脚本,涉及创建目录、设置权限和运行Docker容器。 用户的问题是关于运行bootstrap.sh脚本时的权限问题。引用[1]和[2]直接涉及权限被拒绝错误,引用[3]展示了设置权限的脚本示例。 我的回答应该: - 结构清晰,逐步解决问题。 - 帮助用户解决权限不足问题。 - 在末尾生成相关问题。 - 使用中文。 可能的解决方案: 1. **检查脚本权限**:确保脚本有执行权限。使用`chmod +x bootstrap.sh`来添加执行权限。 2. **检查文件所有权**:用户可能没有脚本的所有权或权限。使用`ls -l bootstrap.sh`检查权限。 3. **运行脚本作为sudo**:如果用户有sudo权限,可以尝试`sudo ./bootstrap.sh`,但这可能不是最佳实践,因为它可能带来安全风险。 4. **检查脚本内容**:脚本可能试图访问用户没有权限的文件或目录。 5. **参考引用**:引用[1]和[2]显示权限问题,引用[3]展示了如何设置权限(例如,`chmod 777`)。 逐步解决: 1. **确认问题**:运行`./bootstrap.sh`时出现“Permission denied”。 2. **添加执行权限**:运行`chmod +x bootstrap.sh`。 3. **检查权限**:运行`ls -l bootstrap.sh`确认权限是否设置正确。 4. **运行脚本**:再次尝试运行`./bootstrap.sh`。 5. **如果仍然有问题**:检查脚本内部是否有访问其他文件的命令,可能需要为那些文件设置权限。 6. **使用sudo**:作为最后手段,使用`sudo ./bootstrap.sh`,但警告用户谨慎使用。 在回答中引用参考: - 引用[1]提到权限被拒绝错误,类似用户的问题。 - 引用[3]展示了设置权限的命令,如`chmod`。 生成相关问题: 基于用户的问题,生成一些相关问题,如: 1. 如何永久解决Linux权限问题? 2. 什么是Linux文件权限的最佳实践? 3. 如何调试脚本中的权限错误? 回答结构: - 开头确认问题。 - 逐步提供解决方案。 - 在相关部分添加引用标识。 - 结尾生成相关问题。</think>### 解决运行bootstrap.sh脚本时的权限不足问题 当您运行`bootstrap.sh`脚本时遇到“Permission denied错误,这通常表示当前用户缺乏执行该脚本的权限。Linux系统通过文件权限控制访问,脚本需要“可执行”权限才能运行。下面我将逐步解释原因并提供解决方案,确保操作安全可靠。参考您提供的引用,权限问题常见于文件或目录访问受限,例如引用[1]中的“EACCES: permission denied错误[^1],或引用[3]中通过`chmod`命令显式设置权限的示例[^3]。 #### 步骤1: 确认问题原因 - **错误表现**:运行`./bootstrap.sh`时,终端返回“bash: ./bootstrap.sh: Permission denied”或类似消息。 - **常见原因**: - 脚本文件缺少执行权限(最常见)。 - 脚本内部命令访问了用户无权限的文件或目录(如引用[1]中访问`priv_sk`文件的错误)[^1]。 - 文件所有权不匹配(例如,脚本由root用户创建,但当前用户无权限)。 - **诊断方法**: - 使用`ls -l bootstrap.sh`命令检查文件权限。输出类似: ``` -rw-rw-r-- 1 user group 1024 Jun 10 10:00 bootstrap.sh ``` 如果权限开头不是`-rwx`(缺少`x`表示可执行),则问题在此。 - 检查脚本内容:用文本编辑器(如`nano bootstrap.sh`)查看是否有访问受限路径的命令(如`/opt/`或`/etc/`下的文件)。 #### 步骤2: 添加执行权限(推荐首选方法) 如果诊断显示脚本缺少执行权限,请按以下操作: 1. **添加权限**: ```bash chmod +x bootstrap.sh # 为脚本添加可执行权限 ``` - `chmod +x` 是标准方法,使文件对所有用户可执行(权限变为`-rwxr-xr-x`)。 - **参考引用[3]**:该示例使用`sudo chmod 777`设置目录权限,但`chmod +x`更安全,避免过度开放权限[^3]。 2. **重新运行脚本**: ```bash ./bootstrap.sh # 正常执行脚本 ``` - 如果成功,问题解决。如果仍报错,继续下一步。 #### 步骤3: 处理脚本内部权限问题 如果添加权限错误依旧,可能脚本内部命令访问了受限资源: 1. **检查脚本内容**: - 打开脚本:`cat bootstrap.sh`。 - 查找可能引发权限错误的命令,例如: - 文件操作(如`touch /path/to/file` 或 `mkdir /protected/dir`)。 - 服务启动命令(如引用[2]中HBase启动时的权限问题)[^2]。 2. **修复内部权限**: - 为脚本内访问的目录或文件添加权限: ```bash sudo chmod -R 755 /path/to/directory # 递归设置目录权限(755是安全级别) ``` - 使用`sudo`仅当必要,避免滥用(如引用[3]中仅在必要时使用`sudo`)[^3]。 - 或修改脚本:将受限路径改为用户有权限的位置(如`~/mydir/`)。 3. **以更高权限运行(谨慎使用)**: - 如果脚本必须访问系统文件,临时使用`sudo`: ```bash sudo ./bootstrap.sh # 以root权限运行 ``` - **警告**:这可能有安全风险,仅在其他方法无效时使用。完成后撤销权限:`sudo chown user:group bootstrap.sh`。 #### 步骤4: 验证所有权和系统限制 - **检查文件所有权**: ```bash ls -l bootstrap.sh # 查看所有者和组 ``` - 如果所有者不是当前用户,使用`sudo chown $USER bootstrap.sh`修改。 - **系统级限制**: - 如果脚本涉及Docker或容器(如引用[3]),确保用户在有权限的组中(例如,运行`sudo usermod -aG docker $USER`后重新登录)。 - 检查SELinux或AppArmor:如果启用,它们可能阻止脚本执行。临时禁用:`sudo setenforce 0`(生产环境不推荐)。 #### 预防措施 - **最佳实践**: - 始终优先使用`chmod +x`而非`chmod 777`,以最小化安全风险[^3]。 - 在脚本开头添加权限检查,例如: ```bash #!/bin/bash if [ ! -x "$0" ]; then echo "Error: Script not executable. Run 'chmod +x $0' first." exit 1 fi ``` - **引用总结**:权限问题常源于文件系统限制(如引用[1][^1]和[2][^2]),通过正确设置权限可解决(如引用[3][^3])。 如果以上步骤仍无效,请提供更多细节(如脚本内容或完整错误日志),以便进一步分析。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值