首页 > 解决方案 > 在 Kubernetes 上运行 Spark 以访问 kerberized Hadoop 集群时,如何解决执行程序上的“未启用简单身份验证”错误?

问题描述

我正在尝试在 Kubernetes 上运行 Spark,目的是处理来自 Kerberized Hadoop 集群的数据。我的应用程序由简单的 SparkSQL 转换组成。虽然我能够在单个驱动程序 pod 上成功运行该过程,但在尝试使用任何执行程序时我无法执行此操作。相反,我得到:

org.apache.hadoop.security.AccessControlException:未启用简单身份验证。可用:[令牌,KERBEROS]

由于 Hadoop 环境是 Kerberized,我提供了一个有效的 keytab,以及 core-site.xml、hive-site.xml、hadoop-site.xml、mapred-site.xml 和 yarn-site.xml,以及docker 镜像中的 krb5.conf 文件。

我使用以下方法设置环境设置:

trait EnvironmentConfiguration {

def configureEnvironment(): Unit = {
  val conf = new Configuration
  conf.set("hadoop.security.authentication", "kerberos")
  conf.set("hadoop.security.authorization", "true")
  conf.set("com.sun.security.auth.module.Krb5LoginModule", "required")
  System.setProperty("java.security.krb5.conf", ConfigurationProperties.kerberosConfLocation)    
  UserGroupInformation.loginUserFromKeytab(ConfigurationProperties.keytabUser, ConfigurationProperties.keytabLocation)
  UserGroupInformation.setConfiguration(conf)
}

我还通过以下方法传递 *-site.xml 文件:

trait SparkConfiguration {

  def createSparkSession(): SparkSession = {
    val spark = SparkSession.builder
    .appName("MiniSparkK8")
    .enableHiveSupport()
    .master("local[*]")
    .config("spark.sql.hive.metastore.version", ConfigurationProperties.hiveMetastoreVersion)
    .config("spark.executor.memory", ConfigurationProperties.sparkExecutorMemory)
    .config("spark.sql.hive.version", ConfigurationProperties.hiveVersion)
    .config("spark.sql.hive.metastore.jars",ConfigurationProperties.hiveMetastoreJars)
    spark.sparkContext.hadoopConfiguration.addResource(new Path(ConfigurationProperties.coreSiteLocation))
    spark.sparkContext.hadoopConfiguration.addResource(new Path(ConfigurationProperties.hiveSiteLocation))
    spark.sparkContext.hadoopConfiguration.addResource(new Path(ConfigurationProperties.hdfsSiteLocation))
    spark.sparkContext.hadoopConfiguration.addResource(new Path(ConfigurationProperties.yarnSiteLocation))
    spark.sparkContext.hadoopConfiguration.addResource(new Path(ConfigurationProperties.mapredSiteLocation))
  }
}

我使用以下 spark-submit 命令运行整个过程:

spark-submit ^
--master k8s://https://kubernetes.example.environment.url:8443 ^
--deploy-mode cluster ^
--name mini-spark-k8 ^
--class org.spark.Driver ^
--conf spark.executor.instances=2 ^
--conf spark.kubernetes.namespace=<company-openshift-namespace> ^
--conf spark.kubernetes.container.image=<company_image_registry.image> ^
--conf spark.kubernetes.driver.pod.name=minisparkk8-cluster ^
--conf spark.kubernetes.authenticate.driver.serviceAccountName=spark ^
local:///opt/spark/examples/target/MiniSparkK8-1.0-SNAPSHOT.jar ^
/opt/spark/mini-spark-conf.properties

以上配置足以让我的 spark 应用程序运行并成功连接到 Kerberized Hadoop 集群。虽然 spark submit 命令声明创建了两个执行器 pod,但这并没有发生,因为我已将 master 设置为local[*]. 因此,只创建了一个 pod,它设法连接到 Kerberized Hadoop 集群并成功地在 Hive 表上运行我的 Spark 转换。

但是,当我删除时.master(local[*]),会创建两个执行器 pod。我可以从日志中看到这些执行程序成功连接到驱动程序 pod,并且分配了任务。此后不久,它们都因上述错误而失败,从而导致失败的执行器 pod 被终止。尽管执行程序已经拥有所有必要的文件来成功连接到其映像中的 Kerberized Hadoop。我相信执行者没有使用 keytab,如果他们正在运行 JAR,他们会这样做。相反,他们正在运行驱动程序给他们的任务。

我可以从日志中看到,驱动程序设法使用用户的 keytab 正确验证自己,USER123

INFO SecurityManager:54 - SecurityManager:身份验证已禁用;ui acls 禁用;具有查看权限的用户:Set(spark, USER123);具有查看权限的组:Set();具有修改权限的用户:Set(spark, USER123); 具有修改权限的组:Set()

另一方面,您从执行程序的日志中得到以下信息,您可以看到该用户 USER123 未通过身份验证:

INFO SecurityManager:54 - SecurityManager:身份验证已禁用;ui acls 禁用;具有查看权限的用户:Set(spark);具有查看权限的组:Set();具有修改权限的用户:Set(spark);具有修改权限的组:Set()

我查看了各种来源,包括这里。它提到HIVE_CONF_DIR需要定义,但我可以从我的程序(打印环境变量)中看到这个变量不存在,包括当驱动程序 pod 设法对自己进行身份验证并正常运行 spark 进程时。

我尝试在前面的 spark-submit 命令中添加以下内容:

--conf spark.kubernetes.kerberos.enabled=true ^
--conf spark.kubernetes.kerberos.krb5.path=/etc/krb5.conf ^
--conf spark.kubernetes.kerberos.keytab=/var/keytabs/USER123.keytab ^
--conf spark.kubernetes.kerberos.principal=USER123@REALM ^

但这并没有什么不同。

我的问题是:我怎样才能让执行者使用他们在图像中拥有的密钥表来验证自己的身份?我希望这将使他们能够执行委派的任务。

标签: dockerapache-sparkkubernetesopenshiftkerberos

解决方案


首先使用以下命令从 hadoop 获取委托令牌。

  1. 使用您的密钥表和主体执行 kinit -kt
  2. 执行以下命令将 hdfs 委托令牌存储在 tmp 路径中 spark-submit --class org.apache.hadoop.hdfs.tools.DelegationTokenFetcher "" --renewer null /tmp/spark.token
  3. 通过添加此配置来提交您的实际火花。 --conf spark.executorEnv.HADOOP_TOKEN_FILE_LOCATION=/tmp/spark.token \

以上是纱线执行器的身份验证方式。对 kubernetes 执行器也做同样的事情。


推荐阅读