Kubernetes环境下在Alluxio上运行Spark

Slack Docker Pulls GitHub edit source

Alluxio可以在Kubernetes上运行。本指南演示了如何在Kubernetes环境下运行的Alluxio上跑一个Spark作业。

概述

在Kubernetes上运行的Spark可以将Alluxio用作数据访问层。 本指南介绍了Kubernetes环境下在Alluxio上运行Spark作业示例。 本教程中使用的示例是一个计算一个文件中有多少行的作业。 在下文中,我们将此作业称为 count。

先决条件

  • Kubernetes集群(版本>=1.8)。
  • Alluxio已部署在Kubernetes集群上。有关如何部署Alluxio的说明,请参考 本页

基本设置

首先,我们准备一个Spark Docker镜像,其中包括Alluxio客户端和任何其他必需的jar文件。 在所有Kubernetes节点上都需提供此镜像。

下载二进制文件

下载所需的Spark版本。 对于spark-submit命令和使用Alluxio所含的Dockerfile编译Docker镜像 我们都使用预生成的二进制文件,。

注:下载为Hadoop预制的软件包

  1. $ tar -xf spark-2.4.4-bin-hadoop2.7.tgz
  2. $ cd spark-2.4.4-bin-hadoop2.7

编译Spark Docker镜像

从Alluxio Docker镜像中提取Alluxio客户端jar:

  1. $ id=$(docker create alluxio/alluxio:2.6.0)
  2. $ docker cp $id:/opt/alluxio/client/alluxio-2.6.0-client.jar \
  3. - > alluxio-2.6.0-client.jar
  4. $ docker rm -v $id 1>/dev/null

添加所需的Alluxio客户端jar并构建用于Spark驱动程序和执行程序pods的Docker镜像。 从Spark发行版目录运行以下命令以添加Alluxio客户端jar。

  1. $ cp <path_to_alluxio_client>/alluxio-2.6.0-client.jar jars/

注意:任何复制到jars目录的jar文件在编译时都会被包含到Spark Docker镜像中。

编译Spark Docker镜像

  1. $ docker build -t spark-alluxio -f kubernetes/dockerfiles/spark/Dockerfile .

注意:确保所有节点(spark-driver和spark-executor pods将运行的所在节点) 都有该镜像。

示例

本节说明如何使用编译的Docker镜像来发起一个以Alluxio作为数据源的Spark作业。

短路操作

短路访问使Spark执行器中的Alluxio客户端可以直接访问主机上的Alluxio worker存储。 因为不通过网络堆栈来与Alluxio worker通信,这样可以提高性能。

如果在部署Alluxio时未按照指令设置domain socket 本页,则 可以跳过将hostPath卷挂载到Spark执行器步骤。

如果在运行Alluxio worker进程的主机上将domain socket位置设置为 /tmp/alluxio-domain,并且Alluxio配置为alluxio.worker.data.server.domain.socket.address=/opt/domain,使用以下Spark 配置将/tmp/alluxio-domain挂载到Spark执行器pod中的/opt/domain。 下一节中的spark-submit命令包含这些属性。

取决于你的设置,Alluxio worker上的domain socket可以是hostPath卷或PersistententVolumeClaim两种之一。可以再此处找到有关如何配置Alluxio worker以使用短路操作的更多详细信息。 这两个选项的spark-submit参数将有所不同。 可以在以下Spark文档中找到有关如何将卷挂载到Spark执行器的更多信息

如果使用的是hostPath domain socket,则应将以下属性传递给Spark:

  1. spark.kubernetes.executor.volumes.hostPath.alluxio-domain.mount.path=/opt/domain
  2. spark.kubernetes.executor.volumes.hostPath.alluxio-domain.mount.readOnly=true
  3. spark.kubernetes.executor.volumes.hostPath.alluxio-domain.options.path=/tmp/alluxio-domain
  4. spark.kubernetes.executor.volumes.hostPath.alluxio-domain.options.type=Directory

如果使用的是PersistententVolumeClaim domain socket,则应将以下属性传递给Spark:

  1. spark.kubernetes.executor.volumes.persistentVolumeClaim.alluxio-domain.mount.path=/opt/domain \
  2. spark.kubernetes.executor.volumes.persistentVolumeClaim.alluxio-domain.mount.readOnly=true \
  3. spark.kubernetes.executor.volumes.persistentVolumeClaim.alluxio-domain.options.claimName=<domainSocketPVC name>

注意:

  • Spark中的卷支持是在2.4.0版中添加的。
  • 当不通过domain socket使用短路访问时,可能会观察到性能下降。

运行Spark作业

以下命令在Alluxio位置/LICENSE运行一个计字数作业样例。 可以在Spark驱动程序pod的日志中看到运行的输出和所花费的时间。更进一步说明参考Spark

创建服务帐户(可选)

如果没有可使用的服务帐户,可以按如下指令创建一个具有所需访问权限的服务账户来运行spark作业。

  1. $ kubectl create serviceaccount spark
  2. $ kubectl create clusterrolebinding spark-role --clusterrole=edit \
  3. --serviceaccount=default:spark --namespace=default

提交Spark作业

从Spark发行版目录运行Spark作业

  1. $ ./bin/spark-submit --master k8s://https://<kubernetes-api-server>:8443 \
  2. --deploy-mode cluster --name spark-alluxio --conf spark.executor.instances=1 \
  3. --class org.apache.spark.examples.JavaWordCount \
  4. --driver-memory 500m --executor-memory 1g \
  5. --conf spark.kubernetes.authenticate.driver.serviceAccountName=spark \
  6. --conf spark.kubernetes.container.image=spark-alluxio \
  7. --conf spark.kubernetes.executor.volumes.hostPath.alluxio-domain.mount.path=/opt/domain \
  8. --conf spark.kubernetes.executor.volumes.hostPath.alluxio-domain.mount.readOnly=true \
  9. --conf spark.kubernetes.executor.volumes.hostPath.alluxio-domain.options.path=/tmp/alluxio-domain \
  10. --conf spark.kubernetes.executor.volumes.hostPath.alluxio-domain.options.type=Directory \
  11. local:///opt/spark/examples/jars/spark-examples_2.11-2.4.4.jar \
  12. alluxio://<alluxio-master>:19998/LICENSE

注意:可以通过运行kubectl cluster-info找到Kubernetes API服务器地址。 您可以在Spark文档中找到更多详细信息。 你应该使用与你的domain socket卷类型相应的属性 [domain socket卷类型](../../en/compute/Spark-On-Kubernetes.html#short-circuit-operations。

故障排除

访问Alluxio客户端日志

可在Spark驱动和执行器日志中找到Alluxio客户端日志。 有关更多说明参考Spark文档

Kubernetes客户端上的HTTP 403

如果你的Spark作业因Kubernetes客户端中如下错误而失败:

  1. WARN ExecutorPodsWatchSnapshotSource: Kubernetes client has been closed
  2. ...
  3. ERROR SparkContext: Error initializing SparkContext.
  4. io.fabric8.kubernetes.client.KubernetesClientException

这可能是由于一个已知问题导致的,可以通过将kubernetes- client.jar升级至4.4.x来解决。 您可以在编译spark-alluxio镜像之前通过更新kubernetes-client-xxjar来修补docker镜像。

  1. rm spark-2.4.4-bin-hadoop2.7/jars/kubernetes-client-*.jar
  2. wget https://repo1.maven.org/maven2/io/fabric8/kubernetes-client/4.4.2/kubernetes-client-4.4.2.jar
  3. cp kubernetes-client-4.4.2.jar spark-2.4.4-bin-hadoop2.7/jars

然后编译spark-alluxio镜像,并分发到所有节点。

服务帐户没有访问权限

如果你看到类似以下某些操作被禁止的错误,这是因为用于Spark作业服务帐户没有足够的访问权限来执行操作引起的。

  1. ERROR Utils: Uncaught exception in thread main
  2. io.fabric8.kubernetes.client.KubernetesClientException: Failure executing: DELETE at: \
  3. https://kubernetes.default.svc/api/v1/namespaces/default/pods/spark-alluxiolatest-exec-1. \
  4. Message: Forbidden!Configured service account doesn't have access. Service account may have been revoked. \
  5. pods "spark-alluxiolatest-exec-1" is forbidden: User "system:serviceaccount:default:default" \
  6. cannot delete resource "pods" in API group "" in the namespace "default".

你应该参考[创建服务帐户](../../en/compute/Spark-On-Kubernetes.html#create-the-service-account-optional确保有正确访问权限。