阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

mapred linuxtaskcontroller目录权限问题探究

384次阅读
没有评论

共计 6553 个字符,预计需要花费 17 分钟才能阅读完成。

今天发现测试环境的 kerberos Hadoop 的 hive 不能跑了,具体表现是 select * limit 这种不走 mapred 的 job 是 ok 的,走 mapred 的 job 就会报错,报的错比较奇怪(Unable to retrieve URL for Hadoop Task logs. Unable to find job tracker info port.)但是确认 jobtracker 是 ok 的,配置文件也是正常的,看来和 jobtracker 没有关系,进一步分析 tasktracker 的日志,发现如下错误。

2014-03-26 17:28:02,048 WARN org.apache.hadoop.mapred.TaskTracker: Exception while localization java.io.IOException: Job initialization failed (24) with output: File /home/test/platform must be owned by root, but is owned by 501

        at org.apache.hadoop.mapred.LinuxTaskController.initializeJob(LinuxTaskController.java:194)

        at org.apache.hadoop.mapred.TaskTracker$4.run(TaskTracker.java:1420)

        at java.security.AccessController.doPrivileged(Native Method)

        at javax.security.auth.Subject.doAs(Subject.java:396)

        at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1407)

        at org.apache.hadoop.mapred.TaskTracker.initializeJob(TaskTracker.java:1395)

        at org.apache.hadoop.mapred.TaskTracker.localizeJob(TaskTracker.java:1310)

        at org.apache.hadoop.mapred.TaskTracker.startNewTask(TaskTracker.java:2727)

        at org.apache.hadoop.mapred.TaskTracker$TaskLauncher.run(TaskTracker.java:2691)

Caused by: org.apache.hadoop.util.Shell$ExitCodeException:

        at org.apache.hadoop.util.Shell.runCommand(Shell.java:261)

        at org.apache.hadoop.util.Shell.run(Shell.java:188)

        at org.apache.hadoop.util.Shell$ShellCommandExecutor.execute(Shell.java:381)

        at org.apache.hadoop.mapred.LinuxTaskController.initializeJob(LinuxTaskController.java:187)

        … 8 more

其中 /home/test/platform 是 mapred 程序所在目录,通过更改 /home/test/platform 的属主为 root 解决,不过这个为什么需要是 root 用户呢
从调用栈信息看到,是在调用 LinuxTaskController 类(因为用到了 kerberos,taskcontroller 需要选择这个类)的 initializeJob 出错了。initializeJob 方法是对 job 做初始操作,传入 user,jobid,token,mapred 的 local dir 等参数,生成一个数组,并调用 ShellCommandExecutor 的构造方法进行实例化,最终调用 ShellCommandExecutor 类的 execute 方法。

public void initializeJob(String user, String jobid, Path credentials,

                          Path jobConf, TaskUmbilicalProtocol taskTracker,

                          InetSocketAddress ttAddr

                          ) throws IOException {

  List<String> command = new ArrayList<String>(

    Arrays.asList(taskControllerExe ,  //task-controller

                  user,

                  localStorage.getDirsString(),        //mapred.local.dir 

                  Integer. toString(Commands.INITIALIZE_JOB.getValue()),

                  jobid,

                  credentials.toUri().getPath().toString(),    //jobToken

                  jobConf.toUri().getPath().toString())); //job.xml

  File jvm =                                  // use same jvm as parent

    new File(new File(System.getProperty( “java.home”), “bin” ), “java” );

  command.add(jvm.toString());

  command.add(“-classpath”);

  command.add(System.getProperty(“java.class.path”));

  command.add(“-Dhadoop.log.dir=” + TaskLog.getBaseLogDir());

  command.add(“-Dhadoop.root.logger=INFO,console”);

  command.add(JobLocalizer.class.getName());  // main of JobLocalizer

  command.add(user);

  command.add(jobid);

  // add the task tracker’s reporting address

  command.add(ttAddr.getHostName());

  command.add(Integer.toString(ttAddr.getPort()));

  String[] commandArray = command.toArray( new String[0]);

  ShellCommandExecutor shExec = new ShellCommandExecutor(commandArray);

  if (LOG.isDebugEnabled()) {

    LOG.debug(“initializeJob: ” + Arrays.toString(commandArray));  //commandArray

  }

  try {

    shExec.execute();

    if (LOG.isDebugEnabled()) {

      logOutput(shExec.getOutput());

    }

  } catch (ExitCodeException e) {

    int exitCode = shExec.getExitCode();

    logOutput(shExec.getOutput());

    throw new IOException(“Job initialization failed (” + exitCode +

        “) with output: ” + shExec.getOutput(), e);

  }

}

通过打开 tasktracker 的 debug 日志,可以获取 commandArray 的具体信息:

2014-03-26 19:49:02,489 DEBUG org.apache.hadoop.mapred.LinuxTaskController: initializeJob:

[/home/test/platform/hadoop-2.0.0-mr1-cdh4.2.0/bin/../sbin/Linux-amd64-64/task-controller,

 hdfs, xxxxxxx, 0, job_201403261945_0002, xxxxx/jobToken, xxxx/job.xml, /usr/local/jdk1.6.0_37/jre/bin/java,

 -classpath,xxxxxx.jar, -Dhadoop.log.dir=/home/test/logs/hadoop/mapred, -Dhadoop.root.logger=INFO,console,

 org.apache.hadoop.mapred.JobLocalizer, hdfs, job_201403261945_0002, localhost.localdomain, 57536]

其中比较重要的是 taskControllerExe 这个参数,它代表了 taskcontroller 的可执行文件 (本例中是 /home/test/platform/hadoop-2.0.0-mr1-cdh4.2.0/bin/../sbin/Linux-amd64-64/task-controller)
而 execute 方法其实最终调用了 task-controller.
task-controller 的源码在 src/c++/task-controller 目录下。
在 configuration.c 中定义了对目录属主进行检查:

static int is_only_root_writable(const char *file) {

…….

  if (file_stat.st_uid != 0) {

    fprintf(LOGFILE, “File %s must be owned by root, but is owned by %d\n”,

            file, file_stat.st_uid);

    return 0;

  }

…….

如果检查的文件属主不是 root,则报错。
调用这个方法的代码:

int check_configuration_permissions(const char* file_name) {

  // copy the input so that we can modify it with dirname

  char* dir = strdup(file_name);

  char* buffer = dir;

  do {

    if (!is_only_root_writable(dir)) {

      free(buffer);

      return -1;

    }

    dir = dirname(dir);

  } while (strcmp(dir, “/”) != 0);

  free(buffer);

  return 0;

}

即 check_configuration_permissions 会调用 is_only_root_writable 方法对二进制文件所在目录向上递归做父目录属主的检查,如果有一个目录属主不为 root,就会出错。这就要求整个 chain 上的目录属主都需要是 root.
这其实是出于 taskcontroller 的安全考虑,在代码中定义了不少关于这个可执行文件的权限的验证,只要有一个地方设置不正确,tasktracker 都不会正常运行。
cloudra 官方文档对这个文件的权限描述如下:

The Task-controller program is used to allow the TaskTracker to run tasks under the Unix account of the user who submitted the job in the first place.

It is a setuid binary that must have a very specific set of permissions and ownership in order to function correctly. In particular, it must:

    1)Be owned by root

    2)Be owned by a group that contains only the user running the MapReduce daemons

    3)Be setuid

    4)Be group readable and executable

问题还没有结束,taskcontroller 有一个配置文件为 taskcontroller.cfg. 关于这个配置文件位置的获取比较让人纠结。
搜到有些文档说是通过设置 HADOOP_SECURITY_CONF_DIR 即可,但是在 cdh4.2.0 中,这个环境变量并不会生效,可以通过打 patch 来解决:
https://issues.apache.org/jira/browse/MAPREDUCE-4397

默认情况下,目录取值的方法如下:

#ifndef HADOOP_CONF_DIR    // 如果编译时不指定 HADOOP_CONF_DIR 的值,没调用 infer_conf_dir 方法。

  conf_dir = infer_conf_dir(argv[0]);

  if (conf_dir == NULL) {

    fprintf(LOGFILE, “Couldn’t infer HADOOP_CONF_DIR. Please set in environment\n”);

    return INVALID_CONFIG_FILE;

  }

#else

  conf_dir = strdup(STRINGIFY(HADOOP_CONF_DIR));

#endif

其中 infer_conf_dir 方法如下,即通过获取二进制文件的相对路径来得到配置文件的存放目录,比如我们线上执行文件的位置为 /home/test/platform/hadoop-2.0.0-mr1-cdh4.2.0/bin/../sbin/Linux-amd64-64/task-controller,配置文件的位置为
/home/test/platform/hadoop-2.0.0-mr1-cdh4.2.0/conf/taskcontroller.cfg:

char *infer_conf_dir(char *executable_file) {

  char *result;

  char *exec_dup = strdup(executable_file);

  char *dir = dirname(exec_dup);

  int relative_len = strlen(dir) + 1 + strlen(CONF_DIR_RELATIVE_TO_EXEC) + 1;

  char *relative_unresolved = malloc(relative_len);

  snprintf(relative_unresolved, relative_len, “%s/%s”,

          dir, CONF_DIR_RELATIVE_TO_EXEC);

  result = realpath(relative_unresolved, NULL);

  // realpath will return NULL if the directory doesn’t exist

…….

关于 taskcontrol 相关类的实现放在后面的文件讲解。

更多 Hadoop 相关信息见Hadoop 专题页面 http://www.linuxidc.com/topicnews.aspx?tid=13

正文完
星哥玩云-微信公众号
post-qrcode
 0
星锅
版权声明:本站原创文章,由 星锅 于2022-01-20发表,共计6553字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中

星哥玩云

星哥玩云
星哥玩云
分享互联网知识
用户数
4
文章数
19350
评论数
4
阅读量
7961256
文章搜索
热门文章
星哥带你玩飞牛NAS-6:抖音视频同步工具,视频下载自动下载保存

星哥带你玩飞牛NAS-6:抖音视频同步工具,视频下载自动下载保存

星哥带你玩飞牛 NAS-6:抖音视频同步工具,视频下载自动下载保存 前言 各位玩 NAS 的朋友好,我是星哥!...
星哥带你玩飞牛NAS-3:安装飞牛NAS后的很有必要的操作

星哥带你玩飞牛NAS-3:安装飞牛NAS后的很有必要的操作

星哥带你玩飞牛 NAS-3:安装飞牛 NAS 后的很有必要的操作 前言 如果你已经有了飞牛 NAS 系统,之前...
我把用了20年的360安全卫士卸载了

我把用了20年的360安全卫士卸载了

我把用了 20 年的 360 安全卫士卸载了 是的,正如标题你看到的。 原因 偷摸安装自家的软件 莫名其妙安装...
再见zabbix!轻量级自建服务器监控神器在Linux 的完整部署指南

再见zabbix!轻量级自建服务器监控神器在Linux 的完整部署指南

再见 zabbix!轻量级自建服务器监控神器在 Linux 的完整部署指南 在日常运维中,服务器监控是绕不开的...
飞牛NAS中安装Navidrome音乐文件中文标签乱码问题解决、安装FntermX终端

飞牛NAS中安装Navidrome音乐文件中文标签乱码问题解决、安装FntermX终端

飞牛 NAS 中安装 Navidrome 音乐文件中文标签乱码问题解决、安装 FntermX 终端 问题背景 ...
阿里云CDN
阿里云CDN-提高用户访问的响应速度和成功率
随机文章
在Windows系统中通过VMware安装苹果macOS15

在Windows系统中通过VMware安装苹果macOS15

在 Windows 系统中通过 VMware 安装苹果 macOS15 许多开发者和爱好者希望在 Window...
星哥带你玩飞牛NAS-13:自动追番、订阅下载 + 刮削,动漫党彻底解放双手!

星哥带你玩飞牛NAS-13:自动追番、订阅下载 + 刮削,动漫党彻底解放双手!

星哥带你玩飞牛 NAS-13:自动追番、订阅下载 + 刮削,动漫党彻底解放双手! 作为动漫爱好者,你是否还在为...
星哥带你玩飞牛NAS-11:咪咕视频订阅部署全攻略

星哥带你玩飞牛NAS-11:咪咕视频订阅部署全攻略

星哥带你玩飞牛 NAS-11:咪咕视频订阅部署全攻略 前言 在家庭影音系统里,NAS 不仅是存储中心,更是内容...
星哥带你玩飞牛NAS-16:不再错过公众号更新,飞牛NAS搭建RSS

星哥带你玩飞牛NAS-16:不再错过公众号更新,飞牛NAS搭建RSS

  星哥带你玩飞牛 NAS-16:不再错过公众号更新,飞牛 NAS 搭建 RSS 对于经常关注多个微...
安装并使用谷歌AI编程工具Antigravity(亲测有效)

安装并使用谷歌AI编程工具Antigravity(亲测有效)

  安装并使用谷歌 AI 编程工具 Antigravity(亲测有效) 引言 Antigravity...

免费图片视频管理工具让灵感库告别混乱

一言一句话
-「
手气不错
手把手教你,购买云服务器并且安装宝塔面板

手把手教你,购买云服务器并且安装宝塔面板

手把手教你,购买云服务器并且安装宝塔面板 前言 大家好,我是星哥。星哥发现很多新手刚接触服务器时,都会被“选购...
星哥带你玩飞牛NAS硬件 01:捡垃圾的最爱双盘,暴风二期矿渣为何成不老神话?

星哥带你玩飞牛NAS硬件 01:捡垃圾的最爱双盘,暴风二期矿渣为何成不老神话?

星哥带你玩飞牛 NAS 硬件 01:捡垃圾的最爱双盘,暴风二期矿渣为何成不老神话? 前言 在选择 NAS 用预...
每天一个好玩的网站-手机博物馆-CHAZ 3D Experience

每天一个好玩的网站-手机博物馆-CHAZ 3D Experience

每天一个好玩的网站 - 手机博物馆 -CHAZ 3D Experience 一句话介绍:一个用 3D 方式重温...
星哥带你玩飞牛 NAS-10:备份微信聊天记录、数据到你的NAS中!

星哥带你玩飞牛 NAS-10:备份微信聊天记录、数据到你的NAS中!

星哥带你玩飞牛 NAS-10:备份微信聊天记录、数据到你的 NAS 中! 大家对「数据安全感」的需求越来越高 ...
免费无广告!这款跨平台AI RSS阅读器,拯救你的信息焦虑

免费无广告!这款跨平台AI RSS阅读器,拯救你的信息焦虑

  免费无广告!这款跨平台 AI RSS 阅读器,拯救你的信息焦虑 在算法推荐主导信息流的时代,我们...