2020-01-13 23:02:58 weixin_42305433 阅读数 14

Spark Demo过程中的常见问题(一)

executor在启动时总是拉不到镜像

kubelet在node上启动pod时,sparkApplication要有imagePullSecret的描述,这样才能连接到私仓获取,需要:

  1. 创建dockersecret

kubectl create secret docker-registry harborsecret --docker-server=harbor.demo.com.cn --docker-username=‘docker-admin’ --docker-password=‘pwd’ --docker-email=‘admin@demo.com’

  1. 指定applicationApplication的yaml中的imagePullSecret
imagePullSecrets: ["dockersecret"]

如何让Spark程序可以连接HDFS集群

等初步了解Spark基本原理后再详细写,暂时还不懂。

如何对hadoop的参数进行配置

官方推荐的配置方法有两种,简单粗暴的方式一种

先说官方的两种推荐方式:

  1. 创建一个hadoop的configMap,将所需要的配置参数包括hdfs-site/core-site等配置文件写进去,然后通过配置项hadoopConfigMap来传递给dirver和exector,官方描述如下:

Specifying Hadoop Configuration
There are two ways to add Hadoop configuration: setting individual Hadoop configuration properties using the optional field .spec.hadoopConf or mounting a special Kubernetes ConfigMap storing Hadoop configuration files (e.g. core-site.xml) using the optional field .spec.hadoopConfigMap. The operator automatically adds the prefix spark.hadoop. to the names of individual Hadoop configuration properties in .spec.hadoopConf. If .spec.hadoopConfigMap is used, additionally to mounting the ConfigMap into the driver and executors, the operator additionally sets the environment variable HADOOP_CONF_DIR to point to the mount path of the ConfigMap.
The following is an example showing the use of individual Hadoop configuration properties:

spec:
  hadoopConf:
    "fs.gs.project.id": spark
    "fs.gs.system.bucket": spark
    "google.cloud.auth.service.account.enable": true
    "google.cloud.auth.service.account.json.keyfile": /mnt/secrets/key.json

大意:如果通过hadoopConf配置,可以直接指定参数,比较多;如果通过configmap方式配置,operator在创建driver/executor pod的时候,会将configmap挂载给driver/executor,同时设置HADOOP_CONF_DIR到configMap挂载的路径下;
这里没说清,在下面又有一段:

Mounting a ConfigMap storing Hadoop Configuration Files
A SparkApplication can specify a Kubernetes ConfigMap storing Hadoop configuration files such as core-site.xml using the optional field .spec.hadoopConfigMap whose value is the name of the ConfigMap. The ConfigMap is assumed to be in the same namespace as that of the SparkApplication. The operator mounts the ConfigMap onto path /etc/hadoop/conf in both the driver and executors. Additionally, it also sets the environment variable HADOOP_CONF_DIR to point to /etc/hadoop/conf in the driver and executors.

大意:configMap必须和SparkApplication在同一个namespace下,operator会在driver/executor的pod上将configMap挂载到/etc/hadoop/conf目录,同时将HADOOP_CONF_DIR变量修改为/etc/hadoop/conf;
所以单看上面一段,可能还没整明白是啥意思就能配置了,其实就是在配置了hadoopConf的情况下,operator帮助我们做了两件事:

  • 将配置的configMap挂载到driver、executor的目录下,而且目录是: /etc/hadoop/conf
  • 修改环境变量HADOOP_CONF_DIR=/etc/hadoop/conf

如果不做hadoopConf的配置,原本要开发者自己来实现,开发者实现的方式也很简单:

  • 创建configMap(用–from-file之类的,参考创建configMap

  • 修改driver/executor的pod的yaml,将configMap挂载到pod的目录下(这里其实更自由一些,目录我们自己可以定)volume本身是支持很多类型资源的挂载的,configMap是其中之一,支持哪些类型可以参考:https://kubernetes.io/zh/docs/concepts/storage/volumes/

  • 修改pod的HADOOP_CONF_DIR=/etc/hadoop/conf的环境变量(这里也很自由,确保路径和文件放在哪儿一样就行)

除了官方推荐的这两种方式以外,还有更粗暴的办法,就是在制作spark-pi镜像的时候,直接将需要用到的配置文件打入镜像的固定目录,同时在spark-pi中用代码自己进行hadoop Configuration/sparkSession的初始化和创建,效果是一样的,而且能很好的解决kerberos的问题,这个也经过了验证;

唯一遇到的问题是,executor无法得到可用的资源,后续再讨论这个问题,不一定和这种简单粗暴的方式有关,可能是其他的问题。

2020-01-16更新,上面的问题似乎找到了解决办法,根因没有分析清楚。

之前出现的日志:
WARN TaskSchedulerImpl: Initial job has not accepted any resources; check your cluster UI to ensure that workers are registered and have sufficient resources
该问题在spark-pi代码中去掉了一个自研的组件依赖后,不再出现,可以正常执行;代码中仅保留hadoop-client的相关依赖内容;自研组件中的依赖太多了,没有识别出到底是哪一个jar包放里面会导致问题。

PS:如果不想通过打镜像这么粗暴的方法,也可以考虑使用增加一个initContainers,通过initContainers先下载相关的配置文件、依赖jar包等,然后再执行spark-pi的container,这种方式比较优雅灵活一些,除了能解决配置的问题,还能解决其他运行前的预处理准备场景;

如何让executor/driver集中部署在不同的node上

这个官方文档里好像也没咋找到,所以直接看了spark-on-kubernetes-operator的源码,可以看到在SparkApplicaiton的yaml定义中包含了nodeSelector的key,所以尝试按如下方式配置,可以按照预期执行:

  driver:
    volumeMounts:
      - name: "test-volume"
        mountPath: "/tmp"
    nodeSelector:
      type: drivers
    cores: 1
    coreLimit: "1200m"
    memory: "512m"
    labels:
      version: 2.4.4
    serviceAccount: spark
  executor:
    volumeMounts:
      - name: "test-volume"
        mountPath: "/tmp"
    nodeSelector:
      type: executors
    cores: 1
    instances: 2
    memory: "512m"
    labels:
      version: 2.4.4

如何配置driver/executor的环境变量

一般来说在pod下面通过如下配置即可生效:

    spec:
      containers:
      - env:
        - name: JAVA_OPTS
          value: -Xms4096m -Xmx5120m
        envFrom:
        - configMapRef:
            name: environment-profile

不过在spark-operator的源码里看到env的配置只有在driver/executor里才有:

                envSecretKeyRefs:
                  additionalProperties:
                    properties:
                      key:
                        type: string
                      name:
                        type: string
                    required:
                    - key
                    - name
                    type: object
                  type: object
                envVars:
                  additionalProperties:
                    type: string
                  type: object

按照官方的说法也是建议使用secret,所以就用secret了,其他方式没有尝试,估计不行;

kubectl create secret generic spark-environment --from-literal=principalName=xxxxxxx

如何配置spark的运行参数

和hadoop一样,官方文档中也提到了如果进行sparkConf的配置,推荐的方式也是一样一样的,原文如下:

Specifying Spark Configuration
There are two ways to add Spark configuration: setting individual Spark configuration properties using the optional field .spec.sparkConf or mounting a special Kubernetes ConfigMap storing Spark configuration files (e.g. spark-defaults.conf, spark-env.sh, log4j.properties) using the optional field .spec.sparkConfigMap. If .spec.sparkConfigMap is used, additionally to mounting the ConfigMap into the driver and executors, the operator additionally sets the environment variable SPARK_CONF_DIR to point to the mount path of the ConfigMap.

spec:
  sparkConf:
    "spark.ui.port": "4045"
    "spark.eventLog.enabled": "true"
    "spark.eventLog.dir": "hdfs://hdfs-namenode-1:8020/spark/spark-events"

一样的套路,只不过换了一个配置项的key而已,实现过程我理解和hadoop的configMap是一样的;由于对Spark暂时还不是很了解,所以也没有其他的内容可以写了。

关于kerberos

完成环境基本的搭建后,如果在K8S集群中想将Spark任务日志持久化到HDFS上,可以配置:

"spark.eventLog.dir": "hdfs://10.120.16.127:25000/spark-test/spark-events"

此处如果Hadoop集群有kerberos认证机制,得需要单独处理,处理思路可以是:

  1. 在用户的Spark jar包中自己完成kerberos认证,kerberos的认证过程在hadoop源码中可以看到是一个类静态变量,因此进程共享,任意一次kerberos都可以在不同的configuration/sparkContext生效
  2. 通过Spark的参数配置实现kerberos的认证,无需用户代码

方法一:经过测试可以通过,只需要将kerberos认证的krb5.conf、user.keytab通过docker镜像ADD或configMap volumeMount挂载目录的方式放入容器即可,此处还需要验证一下,kerberos认证是否只在driver上生效,Executor上仍存在问题

方法二:查阅资料应该是不行,原因是kerberos认证本质是需要:

UserGroupInformation.loginUserFromKeytab(principal, keytabFile);

来完成登陆认证的,所以需要再spark-submit之后执行这行语句来完成登陆认证

Spark 2.4.4有如下说明(gitub官方)

Spark supports automatically creating new tokens for these applications when running in YARN mode. 
Kerberos credentials need to be provided to the Spark application via the spark-submit command, 
using the --principal and --keytab parameters.

因此,即便是修改/etc/spark/conf中的properties文件或修改sparkCondfigMap(本质一样),也没有办法实现,因为keytab的入参并不是由–conf参数来指定的;

Spark 3.0有如下说明(gitub官方)

When talking to Hadoop-based services behind Kerberos, it was noted that Spark needs to 
obtain delegation tokens so that non-local processes can authenticate. These delegation 
tokens in Kubernetes are stored in Secrets that are shared by the Driver and its Executors. 
As such, there are three ways of submitting a Kerberos job:

1.Submitting with a $kinit that stores a TGT in the Local Ticket Cache:
/usr/bin/kinit -kt <keytab_file> <username>/<krb5 realm>
/opt/spark/bin/spark-submit \
    --deploy-mode cluster \
    --class org.apache.spark.examples.HdfsTest \
    --master k8s://<KUBERNETES_MASTER_ENDPOINT> \
    --conf spark.executor.instances=1 \
    --conf spark.app.name=spark-hdfs \
    --conf spark.kubernetes.container.image=spark:latest \
    --conf spark.kubernetes.kerberos.krb5.path=/etc/krb5.conf \
    local:///opt/spark/examples/jars/spark-examples_<VERSION>.jar \
    <HDFS_FILE_LOCATION>

2.Submitting with a local Keytab and Principal
    /opt/spark/bin/spark-submit \
    --deploy-mode cluster \
    --class org.apache.spark.examples.HdfsTest \
    --master k8s://<KUBERNETES_MASTER_ENDPOINT> \
    --conf spark.executor.instances=1 \
    --conf spark.app.name=spark-hdfs \
    --conf spark.kubernetes.container.image=spark:latest \
    --conf spark.kerberos.keytab=<KEYTAB_FILE> \
    --conf spark.kerberos.principal=<PRINCIPAL> \
    --conf spark.kubernetes.kerberos.krb5.path=/etc/krb5.conf \
    local:///opt/spark/examples/jars/spark-examples_<VERSION>.jar \
    <HDFS_FILE_LOCATION>

3.Submitting with pre-populated secrets, that contain the Delegation Token, already existing within the namespace
	/opt/spark/bin/spark-submit \
    --deploy-mode cluster \
    --class org.apache.spark.examples.HdfsTest \
    --master k8s://<KUBERNETES_MASTER_ENDPOINT> \
    --conf spark.executor.instances=1 \
    --conf spark.app.name=spark-hdfs \
    --conf spark.kubernetes.container.image=spark:latest \
    --conf spark.kubernetes.kerberos.tokenSecret.name=<SECRET_TOKEN_NAME> \
    --conf spark.kubernetes.kerberos.tokenSecret.itemKey=<SECRET_ITEM_KEY> \
    --conf spark.kubernetes.kerberos.krb5.path=/etc/krb5.conf \
    local:///opt/spark/examples/jars/spark-examples_<VERSION>.jar \
    <HDFS_FILE_LOCATION>

如果升级到Spark3.0版本,可以通过Option2修改spark参数来指定对应krb5以及keytab文件来实现;可惜用的2.4.4版本,所以这种方式在当前环境下没办法用起来,只能考虑方式一来实现kerberos认证;

2020-01-16更新,确认方法一可以解决kerberos认证的问题
还没确认executor是否在链接HDFS的时候是否会有问题,不过通过增加了configMap volume后,driver启动正常,Pi正常计算得到结果,代码中还list了一个HDFS目录,也是正常的,同时spark的log也持久化到了hdfs指定的目录下,这里需要注意的是:

  1. HADOOP_CONF_DIR这个环境只能配置/etc/hadoop/conf,似乎是spark-operator内部做的,没法改
  2. krb5的参数需要单独对JAVA_OPT参数设置,不然找不到该文件
"spark.driver.extraJavaOptions": "-Djava.security.krb5.conf=/etc/hadoop/conf/krb5.conf"
2018-08-13 14:23:51 chncaesar 阅读数 2584

有同事反馈,Livy Server启动的所有Spark AM失败。Livy启动的Spark AM默认会enableHiveSupport,且使用$LIVY_HOME/conf/livy.conf的如下配置作为spark.yarn.keytab和spark.yarn.kerberos。

livy.server.launch.kerberos.keytab

livy.server.launch.kerberos.principal

由于不知道报错信息,查看Spark AM log,有所发现:

Attempting to login to Kerberos using principal: ...

...

GSS initiate failed [Caused by GSSException: No valid credentials provided (Mechanism level: Failed to find any Kerberos tgt)]

说明spark.yarn.principal和spark.yarn.keytab已经设置,但是校验Kerberos ticket失败了。根据错误信息,对照Spark-Hive的代码HiveClientImpl.scala.

 

// Set up kerberos credentials for UserGroupInformation.loginUser within
// current class loader
if (sparkConf.contains("spark.yarn.principal") && sparkConf.contains("spark.yarn.keytab")) {
  val principalName = sparkConf.get("spark.yarn.principal")
  val keytabFileName = sparkConf.get("spark.yarn.keytab")
  if (!new File(keytabFileName).exists()) {
    throw new SparkException(s"Keytab file: ${keytabFileName}" +
      " specified in spark.yarn.keytab does not exist")
  } else {
      logInfo("Attempting to login to Kerberos" +
          s" using principal: ${principalName} and keytab: ${keytabFileName}")
      UserGroupInformation.loginUserFromKeytab(principalName, keytabFileName)
  }
}

 

UserGroupInformation.loginUserFromKeytab有如下方法调用。若isSecurityEnabled()返回false,跳过初始化。且loginUserFromKeytab会打印log:Login successful for user ... 。Spark AM日志未见此条Log。怀疑加载了默认Hadoop Configuration对象。

public static boolean isSecurityEnabled() {
  return !isAuthenticationMethodEnabled(AuthenticationMethod.SIMPLE);
}

private static boolean isAuthenticationMethodEnabled(AuthenticationMethod method) {
  ensureInitialized();
  return (authenticationMethod == method);
}

private static synchronized void ensureInitialized() {
  if (conf == null) 
    initialize(new Configuration(), false);
  }
}

于是询问该同事,是否有任何配置变更,最终确定有人变动了Hadoop *-site.xml的目录。于是修改HADOOP_CONF_DIR,重启Livy Server。问题解决。

总结:

1. 线上环境的任何变更,必须评估其影响面,且通知到相关同事。

2. 充分了解故障发生前的一些情况,有助于快速定位故障原因。

 

 

 

2019-04-30 20:35:37 yx_keith 阅读数 888

原创博客,转载请说明出处。

在kerberos集群上提交 spark任务复杂性远远高于非kerberos集群,提交spark任务分为两种模式:yarn-client和yarn-cluster模式。

1.yarn-client模式

使用yarn-client模式提交,提交任务的client节点作为spark driver,executor在yarn container中启动,运行日志和状态信息都可以在client节点上看到,一般测试和调试使用yarn client模式。
在这里插入图片描述

在kerberos集群中,使用yarn-client模式提交任务命令如下:
/usr/hdp/current/spark2-client/bin/spark-submit
–principal test_user@BIGDATA.COM
–keytab /home/test_user/test_user.keytab
–files /home/test_user/jaas.conf#jaas.conf,/home/test_user/test_user.keytab#test_user.ke
ytab
–conf “spark.executor.extraJavaOptions=-Djava.security.auth.login.config=/home/test_user/jaas.conf”
–driver-java-options “-Djava.security.auth.login.config=/home/test_user/jaas.conf”
–packages org.apache.spark:spark-streaming-kafka-0-10_2.11:2.3.0
–class com.streaming.StartTest
–queue default
–master yarn
–deploy-mode client
–driver-memory 2g
–executor-cores 2
–executor-memory 2g
–num-executors 8
/home/test_user/test-2.0-SNAPSHOT-shaded.jar

其中jaas.conf文件配置如下:
KafkaClient {
com.sun.security.auth.module.Krb5LoginModule required
useKeyTab=true
keyTab="/home/test_user/test_user.keytab"
storeKey=true
useTicketCache=false
serviceName=“kafka”
principal="test_user@BIGDATA.COM";
};

注意:这里的keytab和jaas.conf路径均是绝对路径,并且在所有nodemanager节点的相同路径上必须有和client节点相同的jaas.conf文件和test_user.keytab,否则提交任务一定会失败,其中:#后边的jaas.conf和keytab只是别名,路径上的jaas.conf文件和test_user.keytab只需要一份即可。

因为yarn-client模式,driver读到的jaas文件不在container中,这个jaas就只能指定一个本地目录来查找keytab,相应的executor中也要找本地目录的keytab,所以yarn-client模式下需要把jaas文件和keytab都放在driver和执行节点本地的目录。

2.yarn-cluster模式

yarn-cluster模式提交任务和yarn-client最大的不同就是driver端此时位于App master中,所以在client端无法看到日志,适合用于生产环境。
在这里插入图片描述

在kerberos集群中,使用yarn-cluster模式提交任务命令如下:
$SPARK_HOME/bin/spark-submit
–keytab test_user.keytab
–principal test_user@BIGDATA.FOSUN.COM
–files jaas.conf#jaas.conf,test_user.keytab.cp
–conf “spark.executor.extraJavaOptions=-Djava.security.auth.login.config=./jaas.conf”
–conf “spark.driver.extraJavaOptions=-Djava.security.auth.login.config=./jaas.conf”
–driver-java-options “-Djava.security.auth.login.config=./jaas.conf”
–packages org.apache.spark:spark-streaming-kafka-0-10_2.11:2.3.0
–queue fosuncloud_test
–master yarn
–deploy-mode cluster
–num-executors 2
–class test_user.test_userLuopan data-placement-1.0-SNAPSHOT.jar

在这里,keytab传了两次,也就是用户认证了两次。
第一次: --keytab test_user.keytab 和–principal test_user@BIGDATA.FOSUN.COM
是用于spark用户认证,认证通过后,才将任务提交到yarn集群,之后spark和yarn的交互都是使用yarn分发的token,当token过期后,spark会使用keytab和principal再次刷新,重新申请token,保证spark长时任务的运行。这里需要注意的是,如果在集群中节点提交,假如test_user已经刷新了keytab,即拿到了spark的ticket,就算不进行这次的认证,任务也可以提交成功,但是当token过期之后,任务会失败,因为不会重新刷新token。

第二次:–files jaas.conf#jaas.conf,test_user.keytab.cp,这里的test_user.keytab.cp只是test_user.keytab的别名,其实是同一个keytab,名称可以任意取,但是必须和test_user.keytab不一样,因为同一个keytab不能用两次。
–files是传给yarn 的container的,因为yarn cluster模式中spark driver和excuter均在container中,jaas.conf#jaas.conf 这两个jaas文件分别传给driver和excutor,所以这里也需要指定
–conf “spark.executor.extraJavaOptions=Djava.security.auth.login.config=./jaas.conf”
–conf “spark.driver.extraJavaOptions=Djava.security.auth.login.config=./jaas.conf” 用于指定传入的jaas文件的位置。
每一个container都会传入jaas.conf文件和test_user.keytab.cp,用于和kafka的交互时验证,如果spark任务不读kafka,理论上来讲,–files后边是可以不需要的,但是我没有试过。

jaas.conf文件配置如下:
KafkaClient {
com.sun.security.auth.module.Krb5LoginModule required
useKeyTab=true
keyTab=“test_user.keytab.cp”
storeKey=true
useTicketCache=false
serviceName=“kafka”
principal="test_user@BIGDATA.FOSUN.COM";
};

jaas文件中的keytab必须是test_user.keytab.cp。此时jaas文件和keytab均放在当前路径下,并且不需要将jaas文件和keytab在nodemanager上各放一份。因为cluster模式下,driver和executor都在container中,直接会从container中读取配置jaas和keytab。

2019-11-07 12:47:15 u013686990 阅读数 6


在上一篇文章里我们在Zeppelin中使用了local模式的Spark解释器,而在本文中,我们将学习如何在Zeppelin中连接启用了Kerberos认证的Spark on YARN,以及如何正确地配置用户模拟

Kerberized Spark

Kerberos是一种网络协议和软件,用来在非安全网络中对用户进行身份认证。它是目前Hadoop所支持的认证机制中最常见的一种。在Kerberos协议中,每个用户持有 keytabprincipal,其中 keytab 是一个文件,principal 是一个字符串,可以分别看做是密码和用户名,通过它们,Kerberos可以帮助Hadoop和Spark认证用户的身份。

Kerberized表示启用了Kerberos认证,在Kerberized的情况下,用户如果不进行认证是无法使用Spark的,会有如下报错:

19/11/06 11:20:52 WARN ipc.Client: Exception encountered while connecting to the server : javax.security.sasl.SaslException: GSS initiate failed [Caused by GSSException: No valid credentials provided (Mechanism level: Failed to find any Kerberos tgt)]
19/11/06 11:20:52 WARN security.UserGroupInformation: PriviledgedActionException as:iamabug (auth:KERBEROS) cause:java.io.IOException: javax.security.sasl.SaslException: GSS initiate failed [Caused by GSSException: No valid credentials provided (Mechanism level: Failed to find any Kerberos tgt)]

认证的方式有两种:

  1. 先在命令行执行 kinit -kt iamabug.keytab iamabug,然后再使用 spark-submit 或者 spark-shell

  2. 直接使用 spark-submit--keytab 参数和 --principal 参数:

    $ spark-submit --keytab iamabug.keytab --principal iamabug <其它参数>
    

Zeppelin连接Kerberized Spark

与上面的认证方式对应,Zeppelin连接Kerberized Spark来使用解释器也有两种方法,两种方法有些步骤是相同的,包括:

  • conf/zeppelin-env.sh 中配置 SPARK_HOME为Spark的安装路径,比如如果采用CDH安装的话,这个路径应当为 /opt/cloudera/parcels/SPARK2/libs/spark2(这里是Spark2,Spark1也是类似的),如果要使用HDFS相关的功能,还需要设置 HADOOP_CONF_DIR 环境变量为Hadoop的配置路径,比如 /etc/hadoop/conf,如下图所示

  • 在浏览器中通过Interpreter菜单设置Spark的运行模式为 yarn-client,并重启解释器(这里也可以设置为 yarn-cluster,那么上面的 HADOOP_CONF_DIR 环境变量则变成必须的):

两种方法的不同在于,如何提供认证凭据,即keytab文件:

  1. 在命令行执行 kinit -kt iamabug.keytab iamabug,然后再启动Zeppelin;

  2. 在页面配置Spark解释器,添加两个配置:

    spark.yarn.principal = iamabug/HOST1@iamabug.com
    # principal最好写完整,hostname和realm都带上
    spark.yarn.keytab = /Users/iamabug/iamabug.keytab
    

    然后在页面重启Spark解释器就可以使用,并且任务正常运行在YARN上:

用户模拟

虽然通过上面的两种方法都可以完成Kerberos认证,但是其实有一个问题:所有的任务都是以同一个用户的身份提交的,使用哪个用户的keytab,在YARN上看到的用户就是谁,带来的后果是,使用Zeppelin的所有人的数据权限和YARN资源池都是启动Zeppelin的用户的,这样显然是不行的,因此需要进行用户模拟。

用户模拟是HADOOP提供的一种安全机制,允许超级用户模拟成其它用户,以其它用户的身份运行各种任务,可以理解为Linux下的su,root用户或拥有sudo权限的用户可以随意切换成任何用户,并获得其它用户的身份权限。

我们期望通过用户模拟实现的是,每个用户在使用Spark解释器时,Zeppelin可以模拟成这个用户登录时所使用的身份向YARN提交任务,即每个用户通过Zeppelin在YARN上运行的任务都是属于自己的,而不属于启动Zeppelin的用户

具体步骤包括:

  1. 禁用Zeppelin的匿名登录,启用Shiro认证,从浏览器中获得登录用户的身份;
  2. 获得管理员的keytab或者新增管理员,以管理员的keytab运行Zeppelin;
  3. 配置Spark解释器的用户模拟;

配置用户认证

编辑 conf/zeppelin-site.xml,禁用匿名登录:

<property>
  <name>zeppelin.anonymous.allowed</name>
  <!--<value>true</value>-->
  <value>false</value>
  <description>Anonymous user allowed by default</description>
</property>

启用Shiro认证:

cp conf/shiro.ini.template conf/shiro.ini

并编辑 conf/shiro.ini,配置用户信息:

[users]
admin = password1, admin
user1 = password2, role1, role2
user2 = password3, role3
user3 = password4, role2
iamabug = iamabug, admin
# 用户名是iamabug,密码是iamabug,角色是admin,具有管理员权限

注意:Shiro支持多种认证方式,比如LDAP、PAM、SSO等,用户名密码的方式只适合用于测试,因为增删用户需要重启Zeppelin才能生效,如果要部署在生产环境,需要选择其它认证方式。

配置完成后通过 bin/zeppelin-daemon.sh restart 重启Zeppelin,可以发现页面右上角不再是Anonymous,而是:

点击会出现登录对话框,输入 conf/shiro.ini 中配置的用户名密码才可以登录:

获取超级管理员keytab

哪些用户具有用户模拟的权限呢?

查看hadoop的 core-site.xml 配置文件,凡是用户名在类似下面的配置项出现的用户都具有用户模拟权限:

  <property>
    <name>hadoop.proxyuser.hdfs.groups</name>
    <value>*</value>
  </property>
  <property>
    <name>hadoop.proxyuser.hdfs.hosts</name>
    <value>*</value>
  </property>

上面这两项配置的含义是,允许 hdfs 用户在任意主机上模拟任意组的用户,也就是可以模拟所有用户,除了 hdfs 用户以外,yarnmapredhive 等多个用户都具有这样的权限,我们可以直接使用这些用户的keytab,也可以在配置文件里添加新的配置,让新的用户成为管理员:

  <property>
    <name>hadoop.proxyuser.iamabug.groups</name>
    <value>*</value>
  </property>
  <property>
    <name>hadoop.proxyuser.iamabug.hosts</name>
    <value>*</value>
  </property>

注意:如果要使用用户模拟,之前所说的两种进行Kerberos认证的方式将只能选择kinit的方法,通过页面配置的方式将不可用,具体原因我们在下面说明。

配置用户模拟

在Zeppelin页面上编辑Spark解释器的配置,将Interpreter的运行模式从Globally in shared process修改为Per User in isolated process,然后再勾选上User Impersonate,保存并重启解释器。

这时候再使用Spark解释器执行任务,任务运行在YARN上的owner将是登录用户,而不是运行Zeppelin的用户

解释为什么只能使用kinit的方式进行认证,如果采用页面配置principal和keytab的方式,配置好用户模拟后执行任务时,会有如下报错:

Error: Only one of --proxy-user or --principal can be provided.

说到底,Zeppelin启动Spark解释器是调用了 spark-submit,这个命令本身可以传入 --proxy-user 参数,这个参数用来指明需要模拟成的用户,而它不能和 --principal 参数同时指定,所以只能采用kinit的方式进行Kerberos认证。

Troubleshoot

JAR包版本冲突

和连接local模式的Spark一样,连接Spark on YARN也会遇到JAR包冲突的问题,根据报错逐个替换Zeppelin的JAR包即可。经常报错的JAR包有:jackson-databind和netty。

Zeppelin重启后无法登录

如图所示,有时重启Zeppelin之后会遇到Login按钮左侧的状态标识一直是红的,上面写着“WebSocket Disconnected”,如果点击Login进行登录,即使输入正确的用户名和密码也会提示用户名密码不匹配,查看日志发现已经启动,尚不清楚原因,但一般再次重启就可以解决这个问题

没有安装Spark客户端

这是因为 zeppelin-site.xml 中配置的 SPARK_HOME 路径必须包含Spark的配置文件,比如 spark-env.shspark-defaults.conf等,如果使用的是CDH管理的Spark,确保在安装Zeppelin的节点上安装了Spark客户端,即分发了Spark的配置文件,这是在实际操作过程中遇到的问题,如果没有安装Spark的客户端,可能会报如下的错:

java.lang.RuntimeException: Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/hadoop/fs/FSDataInputStream
	at org.apache.spark.deploy.SparkSubmitArguments.handleUnknown(SparkSubmitArguments.scala:465)
	at org.apache.spark.launcher.SparkSubmitOptionParser.parse(SparkSubmitOptionParser.java:178)
	at org.apache.spark.deploy.SparkSubmitArguments.<init>(SparkSubmitArguments.scala:104)
	at org.apache.spark.deploy.SparkSubmit$.main(SparkSubmit.scala:112)
	at org.apache.spark.deploy.SparkSubmit.main(SparkSubmit.scala)
Caused by: java.lang.ClassNotFoundException: org.apache.hadoop.fs.FSDataInputStream

解决方法可以参考:Cloudera社区关于这个问题的答案

如何验证Spark解释器正常工作

目前我使用的方法是在解释器里执行下面的命令:

%spark.pyspark
sc.parallelize([1,2]).collect()

如果输出 [1, 2] 则说明解释器正常,并且可以在YARN的Web UI上看到对应的Spark任务。

总结

在本文中,我们学习了如何在Zeppelin中连接启用了Kerberos认证的Spark,并且进行用户模拟,并且分享了一些过程中可能遇到的问题和解决方法。

欢迎交流讨论,吐槽建议。

勤学似春起之苗,不见其增,日有所长
辍学如磨刀之石,不见其损,日有所亏
关注【大数据学徒】,用技术干货助你日有所长
PS:每鸽一天发100元红包,进群可致富

大数据学徒

2015-07-15 23:09:35 jsky_studio 阅读数 6714

我用的是 Spark Standalone集群,当运行kinit命令导入证书,并把CDH Hadoop集群的配置文件放入spark/conf/目录后,提交应用发现还是无法访问CDH Hadoop。

后来查了下官网资料,貌似Standalone模式的Spark集群不支持访问Kerberos认证的Hadoop,我们可以使用Yarn Client模式管理的的Spark集群。

假设你的Hadoop集群是带Kerberos认证的,则你需要部署Hadoop(以2.4.0为例)集群;

注意,不需要创建hdfs, 只是用Hadoop安装包中的 sbin/start-yarn.sh来启动YARN集群。在这个YARN集群里同样部署一个Spark集群。具体步骤就不写了。

提交Spark应用时,注意 --master参数的变化:   spark-submit  --master yarn-client   ...

最后发现Spark应用可以通过Kerberos认证。


没有更多推荐了,返回首页