HDFS远程连接 客户端权限错误

本文介绍了在使用Windows上的Java客户端操作Hadoop集群HDFS文件时遇到的权限错误问题及解决方法,包括修改系统环境变量HADOOP_USER_NAME、使用特定方法获取FileSystem引用等。

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

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

搭建了一个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,不然可能不会生效。


解决办法

       其中,在 FileSystem 类中就有一个类方法是包含了指定用户名(hdfs上有权限的),由此可以获取远程hdfs的  FileSystem 引用。

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

1、FileSystem fs = FileSystem.get(new URI(outputpath), conf, "user_name");          //最佳方法,操作最简单

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

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

4、使用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>嗯,用户问的是如何在IntelliJ IDEA里连接HDFS。首先,我需要回忆一下相关的步骤。可能涉及到配置Hadoop的依赖,或者使用插件之类的。首先,用户可能需要安装Hadoop的客户端库,或者添加相关的依赖到项目里。我记得在Java项目里,通常需要引入hadoop-client这样的依赖,然后通过FileSystem API来连接HDFS。 接下来,用户可能需要配置core-site.xml和hdfs-site.xml,这些配置文件包含了HDFS的地址和端口信息,比如fs.defaultFS。这时候,用户需要确认他们的Hadoop集群的地址是否正确,是否有权限访问。如果是远程集群,可能需要网络可达,或者设置代理。 然后,用户可能会遇到权限问题,比如访问HDFS时出现权限被拒绝的错误。这时候需要检查Hadoop集群的权限设置,或者在代码中设置用户身份,比如使用UserGroupInformation或者System.setProperty("HADOOP_USER_NAME", "user")。 另外,可能有些用户更倾向于使用插件,比如Big Data Tools插件,这样可以图形化地操作HDFS,不需要写代码。这时候需要指导他们如何安装插件,配置连接信息,比如HDFS的地址和端口,以及认证方式,比如简单认证或者Kerberos。 还有可能用户的环境问题,比如Windows下需要winutils.exe和hadoop.dll,否则会报错。这时候需要提醒用户下载这些文件并配置环境变量HADOOP_HOME。 还有版本兼容性问题,Hadoop客户端版本和集群版本是否一致,否则可能会有不兼容的情况出现,导致连接失败。需要建议用户检查版本,并尽量保持一致。 另外,用户可能想通过代码示例来连接,这时候需要给出一个简单的Java示例,展示如何获取FileSystem实例,并测试连接是否成功。同时提醒异常处理,比如捕获IOException,处理连接超时等情况。 还需要考虑安全性,如果集群启用了Kerberos认证,那么配置会更复杂,需要用到UserGroupInformation的loginUserFromKeytab方法,或者配置krb5.conf和keytab文件的位置。这时候可能需要分情况说明,或者建议用户查阅更详细的安全认证文档。 总结下来,回答应该分步骤,先讲添加依赖,再讲配置文件,然后代码示例,接着可能的问题排查,比如权限、环境变量、版本兼容性,最后提到使用插件的方法作为另一种选择。这样用户可以根据自己的情况选择合适的方式。</think>在 IntelliJ IDEA 中连接 HDFS 的步骤如下: --- ### 一、环境准备 1. **Hadoop 依赖配置** 在项目的 `pom.xml` 中添加 Hadoop 客户端依赖(以 Maven 为例): ```xml <dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-client</artifactId> <version>3.3.6</version> <!-- 需与 Hadoop 集群版本一致 --> </dependency> ``` 2. **Hadoop 配置文件** 将 Hadoop 集群的 `core-site.xml` 和 `hdfs-site.xml` 复制到项目的 `resources` 目录下,确保包含以下关键配置: ```xml <!-- core-site.xml --> <property> <name>fs.defaultFS</name> <value>hdfs://namenode-host:8020</value> </property> ``` --- ### 二、代码连接 HDFS ```java import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FileSystem; import java.net.URI; public class HDFSConnector { public static void main(String[] args) { try { Configuration conf = new Configuration(); // 指定 HDFS 地址 FileSystem fs = FileSystem.get(new URI("hdfs://namenode-host:8020"), conf, "hadoop-user"); // 测试连接 if (fs.exists(new Path("/"))) { System.out.println("HDFS 连接成功!"); } fs.close(); } catch (Exception e) { e.printStackTrace(); } } } ``` --- ### 三、常见问题排查 1. **权限问题** 在代码中指定用户身份: ```java System.setProperty("HADOOP_USER_NAME", "your-username"); ``` 2. **Windows 环境问题** - 下载 `winutils.exe` 和 `hadoop.dll`(版本需匹配) - 设置环境变量: ```shell HADOOP_HOME=C:\path\to\hadoop-binaries ``` 3. **连接超时** 检查防火墙设置,确保端口 `8020`(NameNode RPC 端口)和 `9870`(Web UI)开放。 --- ### 四、通过插件连接(推荐) 1. **安装 Big Data Tools 插件** `File → Settings → Plugins` 搜索安装 "Big Data Tools" 2. **配置 HDFS 连接** - 点击右侧工具栏的 **Big Data Tools** - 选择 **HDFS** → **New Connection** - 填写参数: ``` Host: namenode-host Port: 9870 # WebHDFS 端口 User: hadoop-user ``` --- ### 五、验证连接 1. **代码验证** 运行示例代码,确认输出 `HDFS 连接成功!` 2. **插件验证** 在 Big Data Tools 界面浏览 HDFS 目录结构,上传/下载文件测试功能。 --- 通过上述步骤,可确保 IntelliJ IDEA 与 HDFS 的稳定连接。若需 Kerberos 认证等高级配置,需额外加载 `krb5.conf` 和 `keytab` 文件。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值