问题场景

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,即与服务器上文件所属的用户一致。