问题场景
Oozie 启动 SHELL 节点,其中上传 HDFS 时出现权限异常,异常信息如下:
Permission denied: user=yarn, access=WRITE oozie shell action
问题原因
Hadoop分布式文件系统文件和目录的权限模型与POSIX系统权限模型相似。
每一个文件和目录有一个所有者(owner)和一个组(group);文件或目录对其所有者、同组的其余用户以及全部其余用户分别有不一样的权限。
对文件而言,当读取这个文件时须要有 r 权限,当写入或者追加到文件时须要有 w 权限。对目录而言,当列出目录内容时须要具备 r 权限,当新建或删除子文件或子目录时须要有 w 权限,当访问目录的子节点时须要有 x 权限。
每一个访问 HDFS 的用户进程的标识分为两个部分,分别是用户名和组名列表。每次用户进程访问一个文件或目录,HDFS都要对其进行权限检查:若用户是目录所有者,则所有者的访问权限 rwx;若是目录关联的组在组名列表中出现,则组用户的访问权限 r-x;否则目录其余用户的访问权限 r-x 。
yarn 和 spark 是同属一个组 hdfs , 对该文件具备 r-x 的权限,没有 w 权限,所以 yarn 用户出现 Permission denied 异常。
解决办法
设置 HADOOP_USER_NAME 环境变量,有以下三种方式可实现:
1、在系统环境变量或者 shell 脚本中增加 HADOOP_USER_NAME,其值为yarn;
export HADOOP_USER_NAME=yarn
2、通过程序动态添加,示例如下:
System.setProperty("HADOOP_USER_NAME", "yarn");
3、在 oozie 的 workflow.xml 配置文件中添加如下配置:
<env-var>HADOOP_USER_NAME=hdfs</env-var>
示例如下:
<workflow-app xmlns="uri:oozie:workflow:0.3" name="shell-wf">
<start to="shell-node"/>
<action name="shell-node">
<shell xmlns="uri:oozie:shell-action:0.1">
<job-tracker>${jobTracker}</job-tracker>
<name-node>${nameNode}</name-node>
<configuration>
<property>
<name>mapred.job.queue.name</name>
<value>${queueName}</value>
</property>
</configuration>
<exec>test.sh</exec>
<env-var>HADOOP_USER_NAME=hdfs</env-var>
<file>/user/root/test.sh</file>
<file>/path/script.sh#script.sh</file>
</shell>
<ok to="end"/>
<error to="fail"/>
</action>
<kill name="fail">
<message>Shell action failed, error message[${wf:errorMessage(wf:lastErrorNode())}]</message>
</kill>
<end name="end"/>
</workflow-app>
备注: <file> 标签语法: # 前边含义为要获取文件的 HDFS 地址,后边为文件拉取下来之后的文件名,相当于下载后在本地的重命名操作。
其他同类 Spark 问题扩展
扩展一:
由于 yarn 对 “/user/spark” 目录没有写入权限,导致异常的发生;开放hadoop中的HDFS目录的权限即可,示例如下:
sudo -u hdfs hdfs dfs -chmod -R 775 /user/spark
扩展二:
修改hadoop的配置文件:conf/hdfs-site.xml,修改 fs.permissions.umask-mode 的值。
<property>
<name>fs.permissions.umask-mode</name>
<value>002</value>
</property>
<property>
<name>dfs.permissions.superusergroup</name>
<value>hdfs</value>
</property>
hdfs创建文件和目录时使用的umask,默认值为八进制022(即755),每位数字对应了拥有者,组和其他用户。即: drwxr-xr-x
HDFS中超级用户与通常熟悉的Linux或Unix中的root用户不同,HDFS的超级用户是与NameNode进程有相同标示的用户。HDFS的超级用户不必是NameNode主机的超级用户。参数dfs.permissions.superusergroup设置了超级用户组,该组中的所有用户也为超级用户。超级用户在HDFS中可以执行任何操作,而针对超级用户的权限检查永远不会失败。
扩展三:
将各个提交程序的用户名称统一为 spark,即与服务器上文件所属的用户一致。