Spark-Submit 和 K8S Operation For Spark

时间:2022-07-22
本文章向大家介绍Spark-Submit 和 K8S Operation For Spark,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

1 Overview

本文翻译自 Lightbend 的一篇文章,文章日期还比较新,2019/02/26。文章分为两部分,翻译也将分为两个部分。附上文章链接如下:

https://www.lightbend.com/blog/how-to-manage-monitor-spark-on-kubernetes-introduction-spark-submit-kubernetes-operator

2 译文

翻译开始

这两部分的博客系列里,我们将介绍如何使用 spark-submit 和 K8S 的 Operation for Spark。在 Part 1 中,我们会介绍到如何监控和管理部署在 K8S 的 Spark 集群。Part 2 里(译文也在第二部分),我们将深入了解 K8S 的原生的 Operator for Spark。

不久前,Spark 在 2.3 版本的时候已经将 K8S 作为原生的调度器实现了,这意味着我们可以按照官网的介绍,利用 spark-submit 来提交 Spark 作业到 K8S 集群,就像提交给 Yarn 和 Mesos 集群一样。

尽管通过这种方法,还是比较容易使用的,但是这里仍然有很多的诸如管理和监控的特性是用户比较关注的,而 spark-submit 暂时无法提供的。这就是为什么 K8S 会去做一个 Operator for Spark 出来了,因为通过 Operator,作业管理和监控都可以用更 K8S 的方式来原生实现,使用 Operator 会让使用 K8S 运行 Spark 作业更加容易。Operator for Spark 与其他 Operator 一样,扩展了 K8S API,实现了 CRD,也就是自定义资源类型 Custom Resource。

本文的目的就是去比较 spark-submit 和 Operator for Spark,在易用性和使用体验上的差异,也想为那些关注 Spark 和 K8S 生态的用户和开发者、架构师等,去了解这两种方式的一些利弊。以下是本文的一些 highlight。

关于 spark-submit

  • spark-submit 是 Apache Spark 项目的一部分
  • 在即将到来的 Spark 3.0,关于 Spark Pods 的配置上会跟 Operator 靠拢
  • 在管理 K8S 集群的 Spark 作业上有一定的局限性

关于 K8S 的 Operator for Spark

  • 一个将 Spark 作业提交给 K8S 集群的工具
  • 一个典型的基于 K8S Operator 模式的实现
  • 使用了 spark-submit 作为 hook
  • 支持定义 Spark Pods 的时候挂载 Volume 和 ConfigMap(Apache 2.4 并没有提供的功能)
  • 有专用的 CLI 来管理 Spark 作业

2.2 A Deeper Look At Spark-Submit

spark-submit 用来提交 Spark 作业到 K8S 集群,就像在 YARN 和 Mesos 集群都可以。它也允许用户传递一些可选的参数给 Spark Master。以下是一个典型的提交 Spark 作业到 K8S 集群的命令。

./spark-submit
--master  k8s://https://  
--deploy-mode cluster 
--name spark-pi 
--class org.apache.spark.examples.SparkPi 
--conf spark.kubernetes.namespace=spark 
--conf spark.kubernetes.authenticate.driver.serviceAccountName=spark-sa 
--conf spark.executor.instances=2 
--conf spark.kubernetes.container.image.pullPolicy=Always 
--conf spark.kubernetes.container.image=lightbend/spark:2.0.1-OpenShift-2.4.0-rh 
local:///opt/spark/examples/jars/spark-examples_2.11-2.4.0.jar

spark-submit 利用 pod watcher 来监控提交的过程,如果没问题的话,结束的时候输出如下图。

CLI 这种模式是比较容易实现的,只需要一个支持提交 K8S 集群的版本的 Spark 部署。但这种方案还是有点弊端的,比如说不能针对提交过的作业提供更多的管理方法,又或者不允许 spark-submit 来定制 Spark 的 Pods,此种需求可能还是有必要的。当然,这个问题会在 Spark 3.0 得到解决。

2.3 How Does Spark-Submit Work

在 Client 模式,spark-submit 直接将 Spark 作业通过 Spark 环境变量初始化了,这意味着,Spark 的 Driver 运行在了 spark-submit 端,而 Spark 的 Executor 是运行在 K8S 集群的。

在 Cluster 模式,spark-submit 代表了作业提交到 K8S 的带哦度后端,是因为其通过 K8S 集群创建了 Driver 的 Pod,然后 Pods 再被 K8S 集群调度作为 Executor 来运行 Spark 作业。

2.4 A Look At Kubernetes Operator For Apache Spark

关于 Spark 的 Operator 是由 Google 的 GCP 团队来做的,而且也已经开源了。Operator for Spark 实现了 Operator 的模式,将 Spark Application 的运行和管理封装在了自定义资源 custom resources,以及定义了自定义的控制器 custom controller。

Operator 定义了两个自定义资源,分别是 SparkApplication 和 ScheduledSparkApplication。他们是 Spark 作业为了运行在 K8S 上的一层抽象。通过自定义资源,可以与提交到 K8S 集群的 Spark 作业交互,并且使用原生的 K8S 工具,例如 kuberctl 来调控这些作业。

自定义资源就是让你存储和获取这些结构化的 Spark 作业。当和 custom controller 结合的时候,就会变成真正的解释式的 API,这样可以让你指定需要的 Spark 作业状态,以及尝试去匹配真实状态的 Spark 作业。

在上图中,你可以看到一旦作业被描述为 spark-pi.yaml 文件,并且通过 kubectl/sparkctl 提交到 K8S 的 API server,custom controller 就会将这个文件转化为 CRD 对象,也就是 SparkApplication 或者 ScheduledSparkApplication。

然后 K8S 的相关参数以及 spark-submit 的参数就会结合一起,提交给 API Server,然后就会像写 spark-submit 脚本一样,在 K8S 集群中创建 Driver Pod 以及 Executor Pod。

这里再比较一下 spark-submit 和 Operator for Spark 的一些异同点。

首先,当一个 Volume 或者 ConfigMap 在 Pod 被设置了,一个修改的确定 webhook 会拦截 Pod 的创建请求,并且在 Pods 被持久化之前进行修改。

然后就是 Operator 有一个组件叫做 pod event handler,可以检测 Spark Pods 的事件,以及根据 SparkAppclication 和 ScheduledSparkApplcation 的事件不断地更新自己的状态。

Spark 作业的另一个表现形式可以是 ConfigMap,但是在实现 Spark 作业的这种情况下,还是建议用 CRD,原因在于,如果希望将 Spark 作业更好的集成到 K8S 集群里,那么使用 CRD 这种方案,可以使用现成的 K8S 的工具栈,比如 kubectl,这些工具可以更方便的去构建或者更新一个 Spark 作业。

2.4 How Kubernetes Operator For Spark Works

SparkApplication 和 ScheduledSparkApplication 这些 CRD,可以用 YAML 文件来定义,并且被 K8S 解释式的执行。与 spark-submit 脚本不同的是,Operator 是需要安装的,Helm chart 是常用的工具,而已管理 K8S 的 charts 等资源。Helm chart 可以视为是一组文件,可以描述 K8S 相关的一些资源,并且可以作为一个单元来部署。

helm repo add incubator http://storage.googleapis.com/kubernetes-charts-incubator
helm install incubator/sparkoperator --namespace spark-operator

安装成功的输出如下图可见。

这会安装需要的 CRDs 和自定义的控制器,并且设置 RBAC,安装了可变的权限 webhook,并且配置了 Prometheus 来做监控。

pi.yaml:

apiVersion: "sparkoperator.k8s.io/v1beta1"
kind: SparkApplication
metadata:
  name: spark-pi
  namespace: spark
spec:
  type: Scala
  mode: cluster
  image: "lightbend/spark:2.0.0-OpenShift-2.4.0"
  imagePullPolicy: Always
  mainClass: org.apache.spark.examples.SparkPi
  mainApplicationFile: "local:///opt/spark/examples/jars/spark-examples_2.11-2.4.0.jar"
  sparkVersion: "2.4.0"
  restartPolicy:
    type: Never
  driver:
    cores: 0.1
    coreLimit: "200m"
    memory: "512m"
    labels:
      version: 2.4.0
    serviceAccount: spark-sa
  executor:
    cores: 1
    instances: 1
    memory: "512m"
    labels:
      version: 2.4.0

Spark Application 控制器负责监控 SparkApplication CRD 对象,以及提交 Spark Application。在 App 被提交之后,控制器的监视 Application 的状态,例如 SUBMITTED, RUNNING, COMPLETED 等等。

Application 的状态转移可以从 Operator 的 Pod 日志中提取出来。下面是 SUBMITEED -> RUNNING 的转移。

3 Summary

本文主要介绍了利用 Spark 官方对 K8S 的支持,利用 spark-submit 提交 Spark 作业到 K8S 集群的方式,以及利用 K8S (非官方)的 Operator for Spark 来运行 Spark 作业的异同点。

显然本文反复提示的,就是 spark-submit,也就是目前 spark 2.4 提供的功能中,是不能对 Spark 作业进行交互式的参数调整的,而 Operator 方案相比 spark-submit 则是天然地支持这种方式。