如何将应用程序打包到能够在 Kubernetes 中的 Spark 集群上运行的 docker 镜像中?

Posted

技术标签:

【中文标题】如何将应用程序打包到能够在 Kubernetes 中的 Spark 集群上运行的 docker 镜像中?【英文标题】:How to package an application in a docker image capable of running on a Spark cluster in Kubernetes? 【发布时间】:2020-12-29 11:21:05 【问题描述】:

我是在 Kubernetes 上运行 Spark 的新手,我正在尝试打包一个非常简单的应用程序,以便在我设置的 K8s 集群上的 Spark 中运行。我面临的挑战是如何打包我的应用程序以在 Spark 中运行?我从Spark Operator 在 K8 上安装了 Spark,我注意到示例使用了图像 gcr.io/spark-operator/spark:v3.0.0

我注意到 Spark documentation 提到了这个 docker-image-tool.sh 脚本来生成应用程序。但这看起来像是用于定制环境。我想要一个我的应用程序可以用来在 Spark 集群上运行的轻量级图像。不知道如何将它们联系在一起。

所以我从文档中看到了 2 个选项

    使用this docker file 作为基础镜像。 使用docker-image-tool.sh 脚本。

但我不确定我需要选择哪个选项或何时使用其中一个选项?为什么要使用一个而不是另一个?还有其他选择吗?是否有一个预构建的映像,我可以将我的应用程序复制到其中并使用它来运行?

【问题讨论】:

【参考方案1】:

Spark 的docker-image-tool.sh 是一个创建Spark 镜像的工具脚本。如果您想要一个轻量级的 docker 镜像,您可以调整项目附带的 Dockerfile 或编写自己的 - 不要忘记编辑 entrypoint.sh 脚本。

通常,将 Spark 应用程序导入 Kubernetes 的步骤如下:

    创建一个基础 spark 图像供您使用。 将其推送到 docker 注册表 - 如果您使用 minikube,则可以使用 -m 标志将其移动到 minikube 环境。 编写一个 Spark 应用程序,将其打包,然后运行spark-submit 命令。

注意: 如果你没有在 Kubernetes 上投入太多,只是想快速试用整个平台,你可以通过运行以下命令来代理 kube-api-server

kubectl proxy

它将开始在localhost:8001 上为 api 服务器提供服务,然后您可以通过运行类似的命令来提交您的 spark 应用程序

bin/spark-submit \
--master k8s://http:localhost:8001 \ #If you don't specify the protocol here, it'd default to https
--deploy-mode client \ #if you want to go for `cluster mode` then you'd have to set up a service account
--name sparkle \
--class edu.girdharshubham \ 
--conf spark.executor.instances=1 \ #Number of pods
--conf spark.kubernetes.container.image=<your-spark-image>
--conf spark.kubernetes.driver.pod.name="sparkle"
--conf spark.kubernetes.hadoop.configMapName="HADOOP_CONF_DIR"
--conf spark.kubernetes.executor.deleteOnTermination
path/to/jar

在客户端模式下运行的注意事项:

确保您正在运行上述命令的节点 - VM - 可从 pod 进行网络寻址 executor(pod) 将运行一个 JAVA 进程 默认 Dockerfile 使用 tini - 微小但对容器有效的 initspark.kubernetes.executor.deleteOnTermination - 如果你刚刚开始,这个 conf 应该是你的 conf,默认情况下,在失败或正常终止的情况下会删除 pod。这将帮助您快速调试 executor pod 的情况——无论它们是否失败。

【讨论】:

deleteOnTermination 标志非常有用,非常有用。 单独的问题 - 您打包应用程序的 docker 映像是否必须包含整个 spark 分发?看起来即使在docker-image-tool.sh 中也像示例一样打包了一些不必要的东西。我认为可能只有一些客户端库可以打包到 docker 映像中,而不是整个 spark 库。 我添加了一个关于使用基本 dockerfile 与 docker-image-tool.sh 脚本的附加问题 - 如果您对该问题有任何见解,请分享!谢谢 嗨 - 当您说“不要忘记编辑 entrypoint.sh 脚本时。” - 你什么意思?我们需要在该文件中编辑什么?【参考方案2】:

我想我让你有点困惑。准备 spark 发行版的镜像和打包你的应用程序是两件不同的事情。以下是使用 Kuberentes 作为调度程序部署应用程序的方法。

第 1 步:构建 Spark 的映像

./bin/docker-image-tool.sh -r asia.gcr.io/menace -t v3.0.0 build

第 2 步:将映像推送到 Docker 注册表

./bin/docker-image-tool.sh -r asia.gcr.io/menace -t v3.0.0 push

第 3 步:配置您的 Kubernetes 以能够拉取您的镜像,在大多数情况下,只需要设置 imagePullSecrets

Pull Images from a private registry

第 4 步:编写您的 Spark 应用

package edu.girdharshubham

import scala.math.random

import org.apache.spark.rdd.RDD
import org.apache.spark.sql.SparkSession


object Solution 
  def main(args: Array[String]) 
    val spark = SparkSession
      .builder
      .master("k8s://http://localhost:8001")
      .config("spark.submit.deployMode","client")
      .config("spark.executor.instances", "2")
      .config("spark.kubernetes.container.image", "asia.gcr.io/menace/spark:v3.0.0")
      .appName("sparkle")
      .getOrCreate()

    import spark.implicits._
    val someDF = Seq(
      (8, "bat"),
      (64, "mouse"),
      (-27, "horse")
    ).toDF("number", "word")


    println("========================================================")
    println(someDF.take(1).foreach(println))
    println("========================================================")

    spark.stop()
  

第 4 步:运行您的应用程序

sbt run

这将导致在您的集群上生成 executor pod。

第 5 步:打包您的应用程序

sbt package

第 6 步:使用 spark submit 命令运行您的应用 - 请参阅我的初始答案

现在来回答您关于打包 Spark 发行版的问题,请注意您打包的版本和您使用的依赖项。 Spark 对版本有点不确定。

【讨论】:

所以我的问题是关于打包我的应用程序,而不是 spark 分发。我从 spark-operator 安装了 Spark,并且需要我的应用程序是 docker 映像 哦!在这种情况下,您只需在清单中提供以下内容。基本图像将是您的火花分布。 ``` mainApplicationFile: local:///opt/spark/examples/jars/spark-examples_2.12-2.3.0.jar mainClass: org.apache.spark.examples.SparkPi ``` 或者如果你只是测试它out atm,你可以打包你的应用程序。将您的代码放在 spark 目录中,并将 Dockerfile 更改为在 spark 映像中也复制该应用程序 好的,我想我明白了。所以我仍然需要构建一个包含所有 spark 依赖项的图像吗?我需要更改docker-image-tool.sh 脚本以将我的新代码复制到其中吗?还是更改其中一个 docker 文件? 是的,您仍然需要构建 spark 基础镜像 - 除非您计划使用社区提供的镜像。在 kubernetes/dockerfiles/spark/Dockerfile 的原始 dockerfile 中添加 COPY 指令。之后,使用构建标志运行 docker 映像工具,然后使用推送标志

以上是关于如何将应用程序打包到能够在 Kubernetes 中的 Spark 集群上运行的 docker 镜像中?的主要内容,如果未能解决你的问题,请参考以下文章

同是容器管理系统,Kubernetes为什么那么火?

如何在Kubernetes 上部署安装PHP + Nginx 多容器应用

云原生时代的 Kubernetes 部署

如何将本地 Kubernetes 日志发送到 Stackdriver

从Docker到Kubernetes

如何将 PostgreSQL 卷附加到使用 SBT 本机打包程序生成的 Docker 映像?