本文翻译自 Lightbend 的一篇文章,文章日期还比较新,2019/02/26。文章分为两部分,翻译也将分为两个部分。附上文章链接如下:
https://www.lightbend.com/blog/how-to-manage-monitor-spark-on-kubernetes-introduction-spark-submit-kubernetes-operator
翻译开始
这两部分的博客系列里,我们将介绍如何使用 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
关于 K8S 的 Operator for Spark
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 得到解决。
在 Client 模式,spark-submit 直接将 Spark 作业通过 Spark 环境变量初始化了,这意味着,Spark 的 Driver 运行在了 spark-submit 端,而 Spark 的 Executor 是运行在 K8S 集群的。
在 Cluster 模式,spark-submit 代表了作业提交到 K8S 的带哦度后端,是因为其通过 K8S 集群创建了 Driver 的 Pod,然后 Pods 再被 K8S 集群调度作为 Executor 来运行 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 作业。
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 的转移。
本文主要介绍了利用 Spark 官方对 K8S 的支持,利用 spark-submit 提交 Spark 作业到 K8S 集群的方式,以及利用 K8S (非官方)的 Operator for Spark 来运行 Spark 作业的异同点。
显然本文反复提示的,就是 spark-submit,也就是目前 spark 2.4 提供的功能中,是不能对 Spark 作业进行交互式的参数调整的,而 Operator 方案相比 spark-submit 则是天然地支持这种方式。