Hadoop 在Kerberized集群中读取Spark应用程序中的HDFS文件

Hadoop 在Kerberized集群中读取Spark应用程序中的HDFS文件,hadoop,apache-spark,hdfs,kerberos,keytab,Hadoop,Apache Spark,Hdfs,Kerberos,Keytab,我使用Hortonworks数据平台2.5设置了一个Hadoop集群,其中还包括Ambari 2.4、Kerberos、Spark 1.6.2和HDFS 例如,我为以下用户提供了Kerberos主体和密钥表: spark(由Ambari在启用Kerberos期间创建) hdfsuserA(由kadmin->add_原则创建) 用户spark需要在安全集群中运行spark submit命令,并且spark应用程序必须在HDFS目录/User/hdfsuserA/…中打开一些文件,该目录由hdf

我使用Hortonworks数据平台2.5设置了一个Hadoop集群,其中还包括Ambari 2.4、Kerberos、Spark 1.6.2和HDFS

例如,我为以下用户提供了Kerberos主体和密钥表:

  • spark(由Ambari在启用Kerberos期间创建)
  • hdfsuserA(由kadmin->add_原则创建)
用户
spark
需要在安全集群中运行
spark submit
命令,并且spark应用程序必须在HDFS目录
/User/hdfsuserA/…
中打开一些文件,该目录由hdfsuserA(700)拥有

由于启用了Kerberos,我的Spark应用程序将不再运行,它将失败,出现以下异常

[Stage 1:>     (0 + 92) / 162]Exception in thread "main" org.apache.spark.SparkException: Job aborted due to stage failure: Task 55 in stage 1.0 failed 4 times, most recent failure: Lost task 55.3 in stage 1.0 (TID 225, had-data1): org.apache.hadoop.security.AccessControlException: Permission denied: user=spark, access=EXECUTE, inode="/user/hdfsuserA/new/data/Export_PDM_Hadoop_05_2016.csv":hdfsuserA:hadoop:drwx------
        at org.apache.hadoop.hdfs.server.namenode.FSPermissionChecker.check(FSPermissionChecker.java:319)
        at org.apache.hadoop.hdfs.server.namenode.FSPermissionChecker.checkTraverse(FSPermissionChecker.java:259)
        at org.apache.hadoop.hdfs.server.namenode.FSPermissionChecker.checkPermission(FSPermissionChecker.java:205)
        at org.apache.hadoop.hdfs.server.namenode.FSPermissionChecker.checkPermission(FSPermissionChecker.java:190)
        at org.apache.hadoop.hdfs.server.namenode.FSDirectory.checkPermission(FSDirectory.java:1827)
        at org.apache.hadoop.hdfs.server.namenode.FSDirectory.checkPermission(FSDirectory.java:1811)
        at org.apache.hadoop.hdfs.server.namenode.FSDirectory.checkPathAccess(FSDirectory.java:1785)
        at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.getBlockLocationsInt(FSNamesystem.java:1862)
        at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.getBlockLocations(FSNamesystem.java:1831)
        at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.getBlockLocations(FSNamesystem.java:1744)
        at org.apache.hadoop.hdfs.server.namenode.NameNodeRpcServer.getBlockLocations(NameNodeRpcServer.java:693)
        at org.apache.hadoop.hdfs.protocolPB.ClientNamenodeProtocolServerSideTranslatorPB.getBlockLocations(ClientNamenodeProtocolServerSideTranslatorPB.java:373)
        at org.apache.hadoop.hdfs.protocol.proto.ClientNamenodeProtocolProtos$ClientNamenodeProtocol$2.callBlockingMethod(ClientNamenodeProtocolProtos.java)
        at org.apache.hadoop.ipc.ProtobufRpcEngine$Server$ProtoBufRpcInvoker.call(ProtobufRpcEngine.java:640)
        at org.apache.hadoop.ipc.RPC$Server.call(RPC.java:982)
        at org.apache.hadoop.ipc.Server$Handler$1.run(Server.java:2313)
        at org.apache.hadoop.ipc.Server$Handler$1.run(Server.java:2309)
        at java.security.AccessController.doPrivileged(Native Method)
        at javax.security.auth.Subject.doAs(Subject.java:422)
        at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1724)
        at org.apache.hadoop.ipc.Server$Handler.run(Server.java:2307)
问题是,我向用户
spark
进行了身份验证,以便能够启动spark应用程序,但在应用程序内部,我得到了一个异常,因为spark用户无法访问
/user/hdfsuserA
HDFS目录

当我使用user
hdfsuserA
运行spark submit命令时,我得到:

[hdfsuserA@had-job ~]$ kinit -kt /etc/security/keytabs/hdfsuserA.keytab hdfsuserA

[hdfsuserA@had-job ~]$ spark-submit --class spark.sales.TestAnalysis --master yarn --deploy-mode client /home/hdfsuserA/application_new.jar hdfs://had-job:8020/user/hdfsuserA/new/data/*
16/12/03 09:44:46 INFO Remoting: Starting remoting
16/12/03 09:44:46 INFO Remoting: Remoting started; listening on addresses :[akka.tcp://sparkDriverActorSystem@141.79.71.34:46996]
spark.yarn.driver.memoryOverhead is set but does not apply in client mode.
spark.driver.cores is set but does not apply in client mode.
16/12/03 09:44:49 INFO metastore: Trying to connect to metastore with URI thrift://had-job:9083
16/12/03 09:44:49 INFO metastore: Connected to metastore.
Exception in thread "main" org.apache.spark.SparkException: Yarn application has already ended! It might have been killed or unable to launch application master.
        at org.apache.spark.scheduler.cluster.YarnClientSchedulerBackend.waitForApplication(YarnClientSchedulerBackend.scala:122)
        at org.apache.spark.scheduler.cluster.YarnClientSchedulerBackend.start(YarnClientSchedulerBackend.scala:62)
        at org.apache.spark.scheduler.TaskSchedulerImpl.start(TaskSchedulerImpl.scala:144)
        at org.apache.spark.SparkContext.<init>(SparkContext.scala:530)
        at org.apache.spark.api.java.JavaSparkContext.<init>(JavaSparkContext.scala:59)
        at myutil.SparkContextFactory.createSparkContext(SparkContextFactory.java:34)
        at spark.sales.BasketBasedSalesAnalysis.main(BasketBasedSalesAnalysis.java:46)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.apache.spark.deploy.SparkSubmit$.org$apache$spark$deploy$SparkSubmit$$runMain(SparkSubmit.scala:731)
        at org.apache.spark.deploy.SparkSubmit$.doRunMain$1(SparkSubmit.scala:181)
        at org.apache.spark.deploy.SparkSubmit$.submit(SparkSubmit.scala:206)
        at org.apache.spark.deploy.SparkSubmit$.main(SparkSubmit.scala:121)
        at org.apache.spark.deploy.SparkSubmit.main(SparkSubmit.scala)
[hdfsuserA@had-作业~]$kinit-kt/etc/security/keytab/hdfsuserA.keytab hdfsuserA
[hdfsuserA@had-job~]$spark submit--class spark.sales.TestAnalysis--master thread--deploy mode client/home/hdfsuserA/application_new.jarhdfs://had-job:8020/user/hdfsuserA/new/data/*
16/12/03 09:44:46信息远程处理:开始远程处理
16/12/03 09:44:46信息远程处理:远程处理已开始;收听地址:[阿克卡。tcp://sparkDriverActorSystem@141.79.71.34:46996]
spark.Thread.driver.memoryOverhead已设置,但不适用于客户端模式。
已设置spark.driver.cores,但不适用于客户端模式。
16/12/03 09:44:49信息元存储:尝试使用URI连接到元存储thrift://had-job:9083
16/12/03 09:44:49信息元存储:已连接到元存储。
线程“main”org.apache.spark.SparkException中的异常:纱线应用程序已结束!它可能已被杀死或无法启动应用程序主机。
位于org.apache.spark.scheduler.cluster.YarnClientSchedulerBackend.waitForApplication(YarnClientSchedulerBackend.scala:122)
位于org.apache.spark.scheduler.cluster.YarnClientSchedulerBackend.start(YarnClientSchedulerBackend.scala:62)
位于org.apache.spark.scheduler.TaskSchedulerImpl.start(TaskSchedulerImpl.scala:144)
位于org.apache.spark.SparkContext(SparkContext.scala:530)
位于org.apache.spark.api.java.JavaSparkContext(JavaSparkContext.scala:59)
在myutil.SparkContextFactory.createSparkContext(SparkContextFactory.java:34)中
位于spark.sales.BasketBasedSalesAnalysis.main(BasketBasedSalesAnalysis.java:46)
在sun.reflect.NativeMethodAccessorImpl.invoke0(本机方法)处
位于sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
在sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)中
位于java.lang.reflect.Method.invoke(Method.java:498)
位于org.apache.spark.deploy.SparkSubmit$.org$apache$spark$deploy$SparkSubmit$$runMain(SparkSubmit.scala:731)
位于org.apache.spark.deploy.SparkSubmit$.doRunMain$1(SparkSubmit.scala:181)
位于org.apache.spark.deploy.SparkSubmit$.submit(SparkSubmit.scala:206)
位于org.apache.spark.deploy.SparkSubmit$.main(SparkSubmit.scala:121)
位于org.apache.spark.deploy.SparkSubmit.main(SparkSubmit.scala)

对于这样的问题,正确的解决方案是什么?例如,我可以为应用程序中的另一个用户使用kinit吗?

我发现了问题:这是一个用户问题!由于我仅在集群的NameNode主机上创建了
hdfsuserA
,我在该主机上运行
spark submit
命令,因此应用程序无法通过其他主机上的键表作为该用户进行身份验证

所以要解决这个问题:在集群的所有主机上添加相同的用户:

sudo useradd hdfsuserA
sudo passwd hdfsuserA

调用spark应用程序之后应该可以工作(使用
spark submit
中的
master warn
参数,使用
master local[x]
它始终可以工作)

spark用户需要访问这些文件,或者您需要以hdfsuserA身份运行应用程序。为什么不能对所有用户运行spark submit?在启用Kerberos之前,我一直可以运行spark submit脚本。我想知道为什么自从kerberizing集群后,这就不起作用了?当您以hdfsuserA身份运行时,会出现什么错误?您的提示非常有用:我只在集群的NameNode主机上创建了“hdfsuserA”用户。在所有主机上创建用户解决了这个问题,请参见下面我的答案。非常感谢你!