在Kubernetes上运行Spark

Spark可以在由 Kubernetes 管理的集群上运行。这个特性利用了已经被添加到Spark中的原生Kubernetes调度器。

安全

安全功能如身份验证默认情况下是未启用的。当部署一个开放的集群到互联网或不受信任的网络时,保护对集群的访问以防止未经授权的应用程序在集群上运行是很重要的。在运行Spark之前,请查看 Spark安全性 以及本文档中的具体安全部分。

用户身份

从项目提供的 Dockerfile 构建的镜像包含一个默认的 USER 指令,默认 UID 为 185 。这意味着生成的镜像将在容器内以此 UID 运行 Spark 进程。注重安全的部署应考虑提供自定义镜像,其中 USER 指令指定所需的无特权 UID 和 GID。生成的 UID 应包括根组在其附属组中,以便能够运行 Spark 可执行文件。使用提供的 docker-image-tool.sh 脚本构建自己镜像的用户可以使用 -u 选项来指定所需的 UID。

或者,可以使用 Pod 模板 功能为 Spark 提交的 pod 添加 安全上下文 ,其中包含 runAsUser 。这可以用来覆盖镜像中的 USER 指令。请注意,这需要用户的配合,因此可能不适合用于共享环境。如果集群管理员希望限制 pods 可以以哪些用户身份运行,应该使用 Pod 安全策略

卷挂载

如本文档后面在 使用Kubernetes卷 一节中所述,Spark在K8S上提供了配置选项,允许将某些卷类型挂载到驱动程序和执行程序的pod中。尤其是,它允许使用 hostPath 卷,正如Kubernetes文档中所描述的,这些卷存在已知的安全漏洞。

集群管理员应使用 Pod 安全策略 来限制在其环境中适当地挂载 hostPath 卷的能力。

先决条件

它是如何工作的

Spark 集群组件

spark-submit 可以直接用于向Kubernetes集群提交Spark应用程序。 提交机制如下:

请注意,在完成状态下,驱动程序 Pod 并 使用任何计算或内存资源。

驱动程序和执行程序 pod 的调度由 Kubernetes 处理。与 Kubernetes API 的通信通过 fabric8 完成。可以通过 节点选择器 使用配置属性,将驱动程序和执行程序 pods 调度到可用节点的子集上。未来的版本中将可能使用更高级的调度提示,例如 节点/pod 亲和性

向Kubernetes提交应用程序

Docker 镜像

Kubernetes要求用户提供可以部署到pod的容器中的镜像。这些镜像是为Kubernetes支持的容器运行时环境构建的。Docker是一个经常与Kubernetes一起使用的容器运行时环境。Spark(从版本2.3开始)附带一个可以用于此目的的Dockerfile,或者可以根据个别应用程序的需求进行定制。它可以在 kubernetes/dockerfiles/ 目录中找到。

Spark 还随附一个 bin/docker-image-tool.sh 脚本,可用于构建和发布 Docker 镜像,以便与 Kubernetes 后端一起使用。

示例用法为:

$ ./bin/docker-image-tool.sh -r  -t my-tag 构建
$ ./bin/docker-image-tool.sh -r  -t my-tag 推送

这将使用项目提供的默认 Dockerfiles 进行构建。要查看更多可用于自定义此工具行为的选项,包括提供自定义 Dockerfiles ,请使用 -h 标志运行。

默认情况下 bin/docker-image-tool.sh 构建用于运行 JVM 作业的 docker 镜像。您需要选择构建额外的语言绑定 docker 镜像。

示例用法是

# 构建额外的 PySpark docker 镜像
$ ./bin/docker-image-tool.sh -r  -t my-tag -p ./kubernetes/dockerfiles/spark/bindings/python/Dockerfile build

# 构建额外的 SparkR docker 镜像
$ ./bin/docker-image-tool.sh -r  -t my-tag -R ./kubernetes/dockerfiles/spark/bindings/R/Dockerfile build

您也可以直接使用 Apache Spark Docker镜像 (例如 apache/spark: )。

集群模式

要以集群模式启动 Spark Pi,

$ ./bin/spark-submit \
--master k8s://https://: \
--deploy-mode 集群 \
--name spark-pi \
--class org.apache.spark.examples.SparkPi \
--conf spark.executor.instances=5 \
--conf spark.kubernetes.container.image= \
local:///path/to/examples.jar

Spark 主节点可以通过将 --master 命令行参数传递给 spark-submit 或通过在应用程序的配置中设置 spark.master 来指定,必须是格式为 k8s:// : 的 URL。端口必须始终指定,即使是 HTTPS 端口 443。主节点字符串前面加上 k8s:// 将导致 Spark 应用程序在 Kubernetes 集群上启动,并且 API 服务器位于 api_server_url 。如果在 URL 中未指定 HTTP 协议,默认使用 https 。例如,将主节点设置为 k8s://example.com:443 相当于将其设置为 k8s://https://example.com:443 ,但要在不同端口上无 TLS 连接,则主节点应设置为 k8s://http://example.com:8080

在Kubernetes模式下,通过 spark.app.name 或者 --name 参数指定的Spark应用程序名称,将被默认用于命名创建的Kubernetes资源,如驱动程序和执行程序。因此,应用程序名称必须由小写字母数字字符、 - . 组成,并且必须以字母数字字符开始和结束。

如果您有一个 Kubernetes 集群设置,可以通过执行 kubectl cluster-info 来发现 apiserver 的 URL。

$ kubectl cluster-info
Kubernetes master 正在运行于 http://127.0.0.1:6443

在上面的示例中,可以通过将 spark-submit 的参数指定为 --master k8s://http://127.0.0.1:6443 来使用特定的 Kubernetes 集群。此外,使用身份验证代理 kubectl proxy 与 Kubernetes API 进行通信也是可能的。

本地代理可以通过以下方式启动:

$ kubectl proxy

如果本地代理在 localhost:8001 运行, --master k8s://http://127.0.0.1:8001 可以作为 spark-submit 的参数使用。最后,请注意,在上面的示例中,我们指定了一个具有 local:// 方案的特定 URI 的 jar。这个 URI 是已经在 Docker 镜像中的示例 jar 的位置。

客户端模式

从 Spark 2.4.0 开始,可以在客户端模式下在 Kubernetes 上运行 Spark 应用程序。当您的应用程序在客户端模式下运行时,驱动程序可以在 pod 内部或物理主机上运行。运行客户端模式应用程序时,建议考虑以下因素:

客户端模式网络

Spark 执行器必须能够通过可路由的主机名和端口连接到 Spark 驱动程序。Spark 在客户端模式下所需的具体网络配置会因设置而异。如果您在 Kubernetes Pod 内运行驱动程序,可以使用一个 无头服务 来允许您的驱动程序 Pod 通过稳定的主机名从执行器进行路由。当部署您的无头服务时,确保服务的标签选择器仅匹配驱动程序 Pod,而不匹配其他 Pod;建议为您的驱动程序 Pod 分配一个足够独特的标签,并在无头服务的标签选择器中使用该标签。通过 spark.driver.host 指定驱动程序的主机名,并将您的 Spark 驱动程序的端口指定为 spark.driver.port

客户端模式执行器Pod垃圾收集

如果您在一个 pod 中运行 Spark 驱动程序,强烈建议将 spark.kubernetes.driver.pod.name 设置为该 pod 的名称。 当设置此属性时,Spark 调度程序将以带有 OwnerReference 的方式部署执行器 pod,这反过来将确保一旦驱动程序 pod 从集群中删除,应用程序的所有执行器 pod 也将被删除。驱动程序将在由 spark.kubernetes.namespace 指定的命名空间中查找给定名称的 pod,并且将一个指向该 pod 的 OwnerReference 添加到每个执行器 pod 的 OwnerReferences 列表中。请小心避免将 OwnerReference 设置为实际上不是该驱动程序 pod 的 pod,否则当错误的 pod 被删除时,执行器可能会被过早终止。

如果您的应用程序没有在 pod 内运行,或者当您的应用程序实际上在 pod 内运行时未设置 spark.kubernetes.driver.pod.name ,请注意,在应用程序退出时,执行器 pod 可能无法从集群中正确删除。Spark 调度器会尝试删除这些 pod,但如果出于任何原因向 API 服务器的网络请求失败,这些 pod 将仍然保留在集群中。当执行器进程无法访问驱动程序时,它们应该退出,因此在您的应用程序退出后,执行器 pod 不应该消耗集群中的计算资源(CPU 和内存)。

您可以使用 spark.kubernetes.executor.podNamePrefix 完全控制执行器 pod 的名称。当设置此属性时,强烈建议在同一命名空间内使其在所有作业中保持唯一。

认证参数

在客户端模式中,使用确切的前缀 spark.kubernetes.authenticate 来配置Kubernetes认证参数。

IPv4 和 IPv6

从3.4.0开始,Spark支持通过 IPv4/IPv6双栈网络 功能在仅IPv6的环境中运行,该功能允许为Pods和Services分配IPv4和IPv6地址。 根据K8s集群的能力, spark.kubernetes.driver.service.ipFamilyPolicy spark.kubernetes.driver.service.ipFamilies 可以为 SingleStack PreferDualStack RequireDualStack 的其中一个,以及 IPv4 IPv6 IPv4,IPv6 IPv6,IPv4 的其中一个。 默认情况下,Spark使用 spark.kubernetes.driver.service.ipFamilyPolicy=SingleStack spark.kubernetes.driver.service.ipFamilies=IPv4

要仅使用 IPv6 ,您可以使用以下方式提交您的作业。

...
    --conf spark.kubernetes.driver.service.ipFamilies=IPv6 \

DualStack 环境中,您可能需要 java.net.preferIPv6Addresses=true 供 JVM 使用,以及 SPARK_PREFER_IPV6=true 供 Python 使用,以便使用 IPv6

依赖管理

如果您的应用程序的依赖项全部托管在远程位置,如 HDFS 或 HTTP 服务器,它们可能会通过相应的远程 URI 被引用。此外,应用程序依赖项可以预先挂载到自定义构建的 Docker 镜像中。这些依赖项可以通过引用它们的 local:// URI 和/或在您的 Dockerfile 中设置 SPARK_EXTRA_CLASSPATH 环境变量来添加到类路径中。在 spark-submit 中引用自定义构建的 Docker 镜像中的依赖项时,也需要使用 local:// 方案。我们支持使用 file:// 方案或不使用方案(采用完整路径)从提交客户端的本地文件系统获取依赖项,其中目标应为与 Hadoop 兼容的文件系统。使用 S3 的典型示例是通过传递以下选项:

...
--packages org.apache.hadoop:hadoop-aws:3.2.2
--conf spark.kubernetes.file.upload.path=s3a:///path
--conf spark.hadoop.fs.s3a.access.key=...
--conf spark.hadoop.fs.s3a.impl=org.apache.hadoop.fs.s3a.S3AFileSystem
--conf spark.hadoop.fs.s3a.fast.upload=true
--conf spark.hadoop.fs.s3a.secret.key=....
--conf spark.driver.extraJavaOptions=-Divy.cache.dir=/tmp -Divy.home=/tmp
file:///full/path/to/app.jar

应用程序的 jar 文件将被上传到 S3,随后当驱动程序启动时,它将被下载到驱动程序 pod 中并添加到其类路径。Spark 将在上传路径下生成一个随机名称的子目录,以避免与并行运行的 Spark 应用程序发生冲突。用户可以根据自己的需要管理创建的子目录。

客户端方案支持应用程序 jar,以及通过属性 spark.jars spark.files spark.archives 指定的依赖项。

重要提示:所有客户端依赖关系将以扁平目录结构上传到指定路径,因此文件名必须唯一,否则文件将被覆盖。同时,请确保在派生的 k8s 镜像中默认的 ivy 目录具有所需的访问权限,或者按照上述方式修改设置。如果您在集群模式下使用 --packages ,后者也是非常重要的。

密钥管理

Kubernetes 秘密 可以用来为 Spark 应用程序提供访问安全服务的凭据。要将用户指定的秘密挂载到驱动程序容器中,用户可以使用以下格式的配置属性 spark.kubernetes.driver.secrets.[SecretName]= 。类似地,格式为 spark.kubernetes.executor.secrets.[SecretName]= 的配置属性可用于将用户指定的秘密挂载到执行器容器中。请注意,假设要挂载的秘密与驱动程序和执行器 Pod 在同一个命名空间内。例如,要将名为 spark-secret 的秘密挂载到驱动程序和执行器容器中的路径 /etc/secrets ,请将以下选项添加到 spark-submit 命令中:

--conf spark.kubernetes.driver.secrets.spark-secret=/etc/secrets
--conf spark.kubernetes.executor.secrets.spark-secret=/etc/secrets

要通过环境变量使用秘密,请将以下选项添加到 spark-submit 命令中:

--conf spark.kubernetes.driver.secretKeyRef.ENV_NAME=name:key
--conf spark.kubernetes.executor.secretKeyRef.ENV_NAME=name:key

Pod 模板

Kubernetes允许通过 模板文件 定义pod。 Spark用户也可以使用模板文件来定义Spark配置不支持的驱动程序或执行程序pod配置。 为此,指定Spark属性 spark.kubernetes.driver.podTemplateFile spark.kubernetes.executor.podTemplateFile ,指向可以被 spark-submit 进程访问的文件。

--conf spark.kubernetes.driver.podTemplateFile=s3a://bucket/driver.yml
--conf spark.kubernetes.executor.podTemplateFile=s3a://bucket/executor.yml

为了让驱动程序 Pod 访问执行程序 Pod 模板文件,该文件在创建驱动程序 Pod 时会自动挂载到驱动程序 Pod 中的一个卷上。Spark 在反序列化这些模板文件后不会进行任何验证,而是依赖于 Kubernetes API 服务器进行验证。

需要注意的是,Spark 对某些 pod 配置有固定的意见,因此 pod 模板中的某些值将始终被 Spark 覆盖。因此,使用此功能的用户应注意,指定 pod 模板文件仅允许 Spark 在 pod 构建过程中以模板 pod 开始,而不是以空 pod 开始。有关详细信息,请参见 完整列表 ,其中列出了将被 spark 覆盖的 pod 模板值。

Pod 模板文件还可以定义多个容器。在这种情况下,您可以使用 spark 属性 spark.kubernetes.driver.podTemplateContainerName spark.kubernetes.executor.podTemplateContainerName 来指示哪个容器应该用作驱动程序或执行程序的基础。 如果未指定,或者容器名称无效,Spark 将假定列表中的第一个容器 将是驱动程序或执行程序容器。

使用Kubernetes卷

用户可以将以下类型的 Kubernetes 挂载到驱动程序和执行程序的 Pod 中:

注意: 请参见本文件的 安全 部分,以获取与卷挂载相关的安全问题。

要将上述任意类型的卷挂载到驱动程序Pod中,请使用以下配置属性:

--conf spark.kubernetes.driver.volumes.[VolumeType].[VolumeName].mount.path=<挂载路径>
--conf spark.kubernetes.driver.volumes.[VolumeType].[VolumeName].mount.readOnly=
--conf spark.kubernetes.driver.volumes.[VolumeType].[VolumeName].mount.subPath=<挂载子路径>

具体来说, VolumeType 可以是以下值之一: hostPath emptyDir nfs persistentVolumeClaim VolumeName 是您希望在 pod 规格的 volumes 字段下使用的卷的名称。

每种支持的卷类型可能具有一些特定的配置选项,这些选项可以使用以下形式的配置属性指定:

spark.kubernetes.driver.volumes.[卷类型].[卷名称].选项.[选项名称]=<值>

例如,一个名为 images nfs 的服务器和路径可以使用以下属性进行指定:

spark.kubernetes.driver.volumes.nfs.images.options.server=example.com
spark.kubernetes.driver.volumes.nfs.images.options.path=/data

并且,可以使用以下属性指定具有卷名 checkpointpvc persistentVolumeClaim 的声明名称:

spark.kubernetes.driver.volumes.persistentVolumeClaim.checkpointpvc.options.claimName=check-point-pvc-claim

用于将卷挂载到执行器 pod 的配置属性使用前缀 spark.kubernetes.executor. 而不是 spark.kubernetes.driver.

例如,您可以通过使用 OnDemand 作为声明名称,并使用 storageClass sizeLimit 选项来为每个执行者挂载动态创建的持久卷声明,如下所示。这在 动态分配 的情况下非常有用。

spark.kubernetes.executor.volumes.persistentVolumeClaim.data.options.claimName=按需
spark.kubernetes.executor.volumes.persistentVolumeClaim.data.options.storageClass=gp
spark.kubernetes.executor.volumes.persistentVolumeClaim.data.options.sizeLimit=500Gi
spark.kubernetes.executor.volumes.persistentVolumeClaim.data.mount.path=/data
spark.kubernetes.executor.volumes.persistentVolumeClaim.data.mount.readOnly=false

有关每种支持的卷类型的可用选项的完整列表,请参阅下面的 Spark Properties 部分。

基于PVC的执行器Pod分配

由于磁盘是重要的资源类型之一,Spark驱动程序通过一组配置提供了细粒度的控制。例如,默认情况下,按需PVC由执行器拥有,PVC的生命周期与其拥有者执行器紧密耦合。然而,在Spark作业的生命周期内,按需PVC可以由驱动程序拥有,并在执行器之间重复使用,方法如下。这减少了PVC创建和删除的开销。

spark.kubernetes.driver.ownPersistentVolumeClaim=true
spark.kubernetes.driver.reusePersistentVolumeClaim=true

此外,自 Spark 3.4 起,Spark 驱动程序能够进行面向 PVC 的执行器分配,这意味着 Spark 计算作业可以拥有的 PVC 总数,并在驱动程序拥有最大 PVC 数量时推迟新的执行器创建。这有助于现有 PVC 从一个执行器过渡到另一个执行器。

spark.kubernetes.driver.waitToReusePersistentVolumeClaim=true

本地存储

Spark 支持在洗牌和其他操作期间使用卷来溢出数据。要将卷用作本地存储,卷的名称应以 spark-local-dir- 开头,例如:

--conf spark.kubernetes.driver.volumes.[VolumeType].spark-local-dir-[VolumeName].mount.path=<挂载路径>
--conf spark.kubernetes.driver.volumes.[VolumeType].spark-local-dir-[VolumeName].mount.readOnly=false

具体来说,如果作业在执行器中需要大的洗牌和排序操作,可以使用持久卷声明。

spark.kubernetes.executor.volumes.persistentVolumeClaim.spark-local-dir-1.options.claimName=按需
spark.kubernetes.executor.volumes.persistentVolumeClaim.spark-local-dir-1.options.storageClass=gp
spark.kubernetes.executor.volumes.persistentVolumeClaim.spark-local-dir-1.options.sizeLimit=500Gi
spark.kubernetes.executor.volumes.persistentVolumeClaim.spark-local-dir-1.mount.path=/data
spark.kubernetes.executor.volumes.persistentVolumeClaim.spark-local-dir-1.mount.readOnly=false

要通过内置的 KubernetesLocalDiskShuffleDataIO 插件启用洗牌数据恢复功能,我们需要满足以下条件。您可能还想额外启用 spark.kubernetes.driver.waitToReusePersistentVolumeClaim

spark.kubernetes.executor.volumes.persistentVolumeClaim.spark-local-dir-1.mount.path=/data/spark-x/executor-x
spark.shuffle.sort.io.plugin.class=org.apache.spark.shuffle.KubernetesLocalDiskShuffleDataIO

如果没有将卷设置为本地存储,Spark 在洗牌和其他操作期间会使用临时的临时空间将数据溢出到磁盘。当使用 Kubernetes 作为资源管理器时,Pods 将为 spark.local.dir 中列出的每个目录创建一个挂载了 emptyDir 卷的 Pod,或者使用环境变量 SPARK_LOCAL_DIRS 。如果没有显式指定目录,则会创建一个默认目录并进行适当配置。

emptyDir 卷使用了 Kubernetes 的临时存储功能,并且在 pod 的生命周期结束后不会持久化。

使用RAM进行本地存储

emptyDir 卷默认使用节点的后备存储作为临时存储,这种行为可能不适合某些计算环境。例如,如果您有无磁盘节点,并且通过网络挂载了远程存储,很多执行器对该远程存储进行IO操作实际上可能会降低性能。

在这种情况下,可能希望在您的配置中设置 spark.kubernetes.local.dirs.tmpfs=true ,这将导致 emptyDir 卷被配置为 tmpfs ,即基于 RAM 的卷。当以这种方式配置时,Spark 的本地存储使用量将计入您的 Pods 内存使用量,因此您可能希望通过增加 spark.{driver,executor}.memoryOverheadFactor 的值来适当地增加您的内存请求。

内省和调试

这些是你可以用来调查正在运行/已完成的 Spark 应用程序、监控进度以及采取行动的不同方式。

访问日志

可以使用Kubernetes API和 kubectl CLI访问日志。当Spark应用程序正在运行时,可以使用以下方式从应用程序流式传输日志:

$ kubectl -n=<命名空间> logs -f <驱动程序pod名称>

如果在集群上安装了 Kubernetes 仪表板 ,也可以通过相同的日志访问它。

当存在日志收集系统时,您可以在 Spark Driver Executors 选项卡 UI 中公开它。例如,

spark.executorEnv.SPARK_EXECUTOR_ATTRIBUTE_APP_ID='$(SPARK_APPLICATION_ID)'
spark.executorEnv.SPARK_EXECUTOR_ATTRIBUTE_EXECUTOR_ID='$(SPARK_EXECUTOR_ID)'
spark.ui.custom.executor.log.url='https://log-server/log?appId=&execId='

访问驱动程序用户界面

与任何应用程序相关的用户界面可以通过本地访问 kubectl port-forward

$ kubectl port-forward  4040:4040

然后,可以通过 http://localhost:4040 访问 Spark 驱动程序 UI。

调试

可能会有几种类型的失败。如果Kubernetes API服务器拒绝来自spark-submit的请求,或者出于其他原因拒绝连接,提交逻辑应指示所遇到的错误。然而,如果在应用程序运行过程中出现错误,通常,调查的最佳方法可能是通过Kubernetes CLI。

要获取有关驱动程序Pod周围的调度决策的一些基本信息,您可以运行:

$ kubectl describe pod 

如果容器遇到了运行时错误,可以通过以下方式进一步探测状态:

$ kubectl logs 

可以通过类似的方式检查失败的执行器 pod 的状态和日志。最后,删除驱动程序 pod 将清理整个 Spark 应用程序,包括所有执行器、相关服务等。驱动程序 pod 可以看作是 Spark 应用程序在 Kubernetes 中的表示。

Kubernetes 特性

配置文件

您的 Kubernetes 配置文件通常位于您的主目录下的 .kube/config 或由 KUBECONFIG 环境变量指定的位置。Spark on Kubernetes 将尝试使用此文件对用于与 Kubernetes 集群交互的 Kubernetes 客户端进行初始自动配置。提供了多种 Spark 配置属性,允许进一步自定义客户端配置,例如使用替代身份验证方法。

上下文

Kubernetes 配置文件可以包含多个上下文,以便在不同的集群和/或用户身份之间切换。 默认情况下,Spark 在 Kubernetes 上将使用您的当前上下文(可以通过运行 kubectl config current-context 来检查)进行 Kubernetes 客户端的初始自动配置。

为了使用替代上下文,用户可以通过 Spark 配置属性 spark.kubernetes.context 指定所需的上下文,例如 spark.kubernetes.context=minikube

命名空间

Kubernetes 有 命名空间 的概念。 命名空间是将集群资源分配给多个用户(通过资源配额)的一种方式。Kubernetes 上的 Spark 可以 利用命名空间来启动 Spark 应用程序。这可以通过 spark.kubernetes.namespace 配置来实现。

Kubernetes 允许使用 ResourceQuota 对单个命名空间中的资源、对象数量等设置限制。管理员可以将命名空间和 ResourceQuota 结合使用,以控制在运行 Spark 应用程序的 Kubernetes 集群中的共享和资源分配。

基于角色的访问控制

在启用 RBAC 的Kubernetes集群中,用户可以配置Kubernetes RBAC角色和服务账户,以便不同的Spark on Kubernetes组件访问Kubernetes API服务器。

Spark 驱动程序 Pod 使用 Kubernetes 服务账号访问 Kubernetes API 服务器,以创建和监视执行程序 Pod。驱动程序 Pod 使用的服务账号必须具有适当的权限,以便驱动程序能够完成其工作。具体来说,服务账号至少必须被授予一个 Role ClusterRole ,以允许驱动程序 Pod 创建 Pod 和服务。默认情况下,如果在 Pod 创建时未指定服务账号,驱动程序 Pod 将自动分配到 default 服务账号,该服务账号位于由 spark.kubernetes.namespace 指定的命名空间中。

根据部署的Kubernetes版本和设置,默认的 default 服务账户可能具有或不具有允许驱动程序pod在默认Kubernetes RBAC 策略下创建pod和服务的角色。有时用户可能需要指定一个拥有正确角色的自定义服务账户。Spark在Kubernetes上支持通过配置属性 spark.kubernetes.authenticate.driver.serviceAccountName= 指定用于驱动程序pod的自定义服务账户。例如,若要使驱动程序pod使用 spark 服务账户,用户只需将以下选项添加到 spark-submit 命令中:

--conf spark.kubernetes.authenticate.driver.serviceAccountName=spark

要创建一个自定义服务账号,用户可以使用 kubectl create serviceaccount 命令。例如,以下命令创建一个名为 spark 的服务账号:

$ kubectl create serviceaccount spark

要授予服务帐户一个 Role ClusterRole ,需要一个 RoleBinding ClusterRoleBinding 。要创建一个 RoleBinding ClusterRoleBinding ,用户可以使用 kubectl create rolebinding (或 clusterrolebinding 用于 ClusterRoleBinding )命令。例如,以下命令在 default 命名空间中创建一个 edit ClusterRole 并将其授予上面创建的 spark 服务帐户:

$ kubectl create clusterrolebinding spark-role --clusterrole=edit --serviceaccount=default:spark --namespace=default

请注意, Role 只能用于授予对单个命名空间内的资源(例如pods)的访问权限,而 ClusterRole 可以用于授予对集群范围内的资源(例如nodes)以及跨所有命名空间的命名空间资源(如pods)的访问权限。对于在Kubernetes上的Spark,由于驱动程序始终在同一命名空间中创建执行器pods,因此 Role 就足够了,尽管用户也可以使用 ClusterRole 。有关RBAC授权和如何为pods配置Kubernetes服务账户的更多信息,请参考 使用RBAC授权 为Pods配置服务账户

Spark 应用程序管理

Kubernetes通过spark-submit CLI工具在集群模式下提供简单的应用程序管理。用户可以通过提供在提交作业时打印的提交ID来终止作业。提交ID遵循格式 namespace:driver-pod-name 。如果用户省略命名空间,则使用当前k8s上下文中设置的命名空间。例如,如果用户设置了特定的命名空间,如下所示 kubectl config set-context minikube --namespace=spark ,则默认将使用 spark 命名空间。另一方面,如果特定上下文中没有添加命名空间,则默认考虑所有命名空间。这意味着操作将影响与给定提交ID匹配的所有Spark应用程序,而不考虑命名空间。此外,应用程序管理的spark-submit使用相同的后端代码,该代码用于提交驱动程序,因此可以重用相同的属性,如 spark.kubernetes.context 等。

例如:

$ spark-submit --kill spark:spark-pi-1547948636094-driver --master k8s://https://192.168.2.8:8443

用户还可以使用 --status 标志列出应用程序状态:

$ spark-submit --status spark:spark-pi-1547948636094-driver --master  k8s://https://192.168.2.8:8443

这两种操作都支持通配符模式。例如,用户可以运行:

$ spark-submit --kill spark:spark-pi* --master  k8s://https://192.168.2.8:8443

上述操作将终止所有具有特定前缀的应用程序。

用户可以通过 spark.kubernetes.appKillPodDeletionGracePeriod 属性指定 pod 终止的宽限期,使用 --conf 作为提供此属性的手段(所有 K8s pod 的默认值为 30 秒 )。

未来工作

目前正在开发或计划开发多个在Kubernetes上的Spark特性。这些特性预计最终将会纳入未来版本的spark-kubernetes集成中。

其中一些包括:

配置

请查看 配置页面 获取有关Spark配置的信息。以下配置是针对Kubernetes上的Spark特定的。

Spark 属性

属性名称 默认值 含义 自版本
spark.kubernetes.context (无) 用户 Kubernetes 配置文件中用于 Kubernetes 客户端库初始自动配置的上下文。当未指定时,将使用用户当前的上下文。 注意: 许多自动配置的设置可以通过使用其他 Spark 配置属性覆盖,例如 spark.kubernetes.namespace 3.0.0
spark.kubernetes.driver.master https://kubernetes.default.svc 用于驱动请求执行器的内部 Kubernetes 主控(API 服务器)地址,或者在仅驱动 pod 模式下使用 'local[*]'。 3.0.0
spark.kubernetes.namespace default 用于运行驱动和执行器 pod 的命名空间。 2.3.0
spark.kubernetes.container.image (无) 用于 Spark 应用程序的容器镜像。通常形式为 example.com/repo/spark:v1.0.0 。该配置是必需的,用户必须提供,除非为每种不同的容器类型提供了明确的镜像。 2.3.0
spark.kubernetes.driver.container.image (spark.kubernetes.container.image 的值) 用于驱动的自定义容器镜像。 2.3.0
spark.kubernetes.executor.container.image (spark.kubernetes.container.image 的值) 用于执行器的自定义容器镜像。 2.3.0
spark.kubernetes.container.image.pullPolicy IfNotPresent 在 Kubernetes 中拉取镜像时使用的容器镜像拉取策略。有效值包括 Always Never IfNotPresent 2.3.0
spark.kubernetes.container.image.pullSecrets 用于从私有镜像注册中心拉取镜像的 Kubernetes 密钥的逗号分隔列表。 2.4.0
spark.kubernetes.allocation.batch.size 5 每轮执行器 pod 分配时一次性启动的 pod 数量。 2.3.0
spark.kubernetes.allocation.batch.delay 1s 每轮执行器 pod 分配之间等待的时间。指定小于 1 秒的值可能导致 Spark 驱动程序的 CPU 使用过高。 2.3.0
spark.kubernetes.authenticate.submission.caCertFile (无) 启动驱动时通过 TLS 连接到 Kubernetes API 服务器的 CA 证书文件的路径。此文件必须位于提交机器的磁盘上。指定此路径而不是 URI(即不提供方案)。在客户端模式下,使用 spark.kubernetes.authenticate.caCertFile 代替。 2.3.0
spark.kubernetes.authenticate.submission.clientKeyFile (无) 启动驱动时用于向 Kubernetes API 服务器进行身份验证的客户端密钥文件的路径。此文件必须位于提交机器的磁盘上。指定此路径而不是 URI(即不提供方案)。在客户端模式下,使用 spark.kubernetes.authenticate.clientKeyFile 代替。 2.3.0
spark.kubernetes.authenticate.submission.clientCertFile (无) 启动驱动时用于向 Kubernetes API 服务器进行身份验证的客户端证书文件的路径。此文件必须位于提交机器的磁盘上。指定此路径而不是 URI(即不提供方案)。在客户端模式下,使用 spark.kubernetes.authenticate.clientCertFile 代替。 2.3.0
spark.kubernetes.authenticate.submission.oauthToken (无) 启动驱动时用于向 Kubernetes API 服务器进行身份验证的 OAuth 令牌。请注意,与其他身份验证选项不同,预期这将是用于身份验证的确切字符串值。在客户端模式下,使用 spark.kubernetes.authenticate.oauthToken 代替。 2.3.0
spark.kubernetes.authenticate.submission.oauthTokenFile (无) 启动驱动时用于向 Kubernetes API 服务器进行身份验证的 OAuth 令牌文件的路径。此文件必须位于提交机器的磁盘上。指定此路径而不是 URI(即不提供方案)。在客户端模式下,使用 spark.kubernetes.authenticate.oauthTokenFile 代替。 2.3.0
spark.kubernetes.authenticate.driver.caCertFile (无) 在请求执行器时从驱动 pod 通过 TLS 连接到 Kubernetes API 服务器的 CA 证书文件的路径。此文件必须位于提交机器的磁盘上,并将上传到驱动 pod。指定此路径而不是 URI(即不提供方案)。在客户端模式下,使用 spark.kubernetes.authenticate.caCertFile 代替。 2.3.0
spark.kubernetes.authenticate.driver.clientKeyFile (无) 从驱动 pod 请求执行器时用于向 Kubernetes API 服务器进行身份验证的客户端密钥文件的路径。此文件必须位于提交机器的磁盘上,并将作为 Kubernetes 密钥上传到驱动 pod。指定此路径而不是 URI(即不提供方案)。在客户端模式下,使用 spark.kubernetes.authenticate.clientKeyFile 代替。 2.3.0
spark.kubernetes.authenticate.driver.clientCertFile (无) 从驱动 pod 请求执行器时用于向 Kubernetes API 服务器进行身份验证的客户端证书文件的路径。此文件必须位于提交机器的磁盘上,并将作为 Kubernetes 密钥上传到驱动 pod。指定此路径而不是 URI(即不提供方案)。在客户端模式下,使用 spark.kubernetes.authenticate.clientCertFile 代替。 2.3.0
spark.kubernetes.authenticate.driver.oauthToken (无) 从驱动 pod 请求执行器时用于向 Kubernetes API 服务器进行身份验证的 OAuth 令牌。请注意,与其他身份验证选项不同,必须是用于身份验证的确切字符串值。此令牌值作为 Kubernetes 密钥上传到驱动 pod。在客户端模式下,使用 spark.kubernetes.authenticate.oauthToken 代替。 2.3.0
spark.kubernetes.authenticate.driver.oauthTokenFile (无) 从驱动 pod 请求执行器时用于向 Kubernetes API 服务器进行身份验证的 OAuth 令牌文件的路径。请注意,与其他身份验证选项不同,此文件必须包含用于身份验证的确切字符串值。此令牌值作为密钥上传到驱动 pod。在客户端模式下,使用 spark.kubernetes.authenticate.oauthTokenFile 代替。 2.3.0
spark.kubernetes.authenticate.driver.mounted.caCertFile (无) 在请求执行器时从驱动 pod 通过 TLS 连接到 Kubernetes API 服务器的 CA 证书文件的路径。该路径必须从驱动 pod 可访问。指定此路径而不是 URI(即不提供方案)。在客户端模式下,使用 spark.kubernetes.authenticate.caCertFile 代替。 2.3.0
spark.kubernetes.authenticate.driver.mounted.clientKeyFile (无) 从驱动 pod 请求执行器时用于向 Kubernetes API 服务器进行身份验证的客户端密钥文件的路径。该路径必须从驱动 pod 可访问。指定此路径而不是 URI(即不提供方案)。在客户端模式下,使用 spark.kubernetes.authenticate.clientKeyFile 代替。 2.3.0
spark.kubernetes.authenticate.driver.mounted.clientCertFile (无) 从驱动 pod 请求执行器时用于向 Kubernetes API 服务器进行身份验证的客户端证书文件的路径。该路径必须从驱动 pod 可访问。指定此路径而不是 URI(即不提供方案)。在客户端模式下,使用 spark.kubernetes.authenticate.clientCertFile 代替。 2.3.0
spark.kubernetes.authenticate.driver.mounted.oauthTokenFile (无) 包含用于从驱动 pod 向 Kubernetes API 服务器进行身份验证的 OAuth 令牌的文件的路径。该路径必须从驱动 pod 可访问。请注意,与其他身份验证选项不同,此文件必须包含用于身份验证的确切字符串值。在客户端模式下,使用 spark.kubernetes.authenticate.oauthTokenFile 代替。 2.3.0
spark.kubernetes.authenticate.driver.serviceAccountName default 运行驱动 pod 时使用的服务帐户。驱动 pod 在从 API 服务器请求执行器 pod 时使用此服务帐户。请注意,无法与 CA 证书文件、客户端密钥文件、客户端证书文件和/或 OAuth 令牌一起指定。在客户端模式下,使用 spark.kubernetes.authenticate.serviceAccountName 代替。 2.3.0
spark.kubernetes.authenticate.executor.serviceAccountName (spark.kubernetes.authenticate.driver.serviceAccountName 的值) 运行执行器 pod 时使用的服务帐户。如果未设置此参数,回退逻辑将使用驱动的服务帐户。 3.1.0
spark.kubernetes.authenticate.caCertFile (无) 在客户端模式下,连接到 Kubernetes API 服务器的 CA 证书文件路径,以请求执行器。指定此路径而不是 URI(即不提供方案)。 2.4.0
spark.kubernetes.authenticate.clientKeyFile (无) 在客户端模式下,用于向 Kubernetes API 服务器进行身份验证的客户端密钥文件的路径,以请求执行器。指定此路径而不是 URI(即不提供方案)。 2.4.0
spark.kubernetes.authenticate.clientCertFile (无) 在客户端模式下,用于向 Kubernetes API 服务器进行身份验证的客户端证书文件的路径,以请求执行器。指定此路径而不是 URI(即不提供方案)。 2.4.0
spark.kubernetes.authenticate.oauthToken (无) 在客户端模式下,用于向 Kubernetes API 服务器进行身份验证的 OAuth 令牌,以请求执行器。请注意,与其他身份验证选项不同,必须是用于身份验证的确切字符串值。 2.4.0
spark.kubernetes.authenticate.oauthTokenFile (无) 在客户端模式下,用于向 Kubernetes API 服务器进行身份验证的 OAuth 令牌的文件路径,以请求执行器。 2.4.0
spark.kubernetes.driver.label.[标签名] (无) 标签名 指定的标签添加到驱动 pod。例如, spark.kubernetes.driver.label.something=true 。请注意,Spark 还会为驱动 pod 添加自己的标签以供账务管理。 2.3.0
spark.kubernetes.driver.annotation.[注解名称] (无) 将 Kubernetes 注解 添加到驱动 pod,指定为 注解名称 。例如, spark.kubernetes.driver.annotation.something=true 2.3.0
spark.kubernetes.driver.service.label.[标签名] (无) 将 Kubernetes 标签 添加到驱动服务,指定为 标签名 。例如, spark.kubernetes.driver.service.label.something=true 。请注意,Spark 还会为驱动服务添加自己的标签以供账务管理。 3.4.0
spark.kubernetes.driver.service.annotation.[注解名称] (无) 将 Kubernetes 注解 添加到驱动服务,指定为 注解名称 。例如, spark.kubernetes.driver.service.annotation.something=true 3.0.0
spark.kubernetes.executor.label.[标签名] (无) 标签名 指定的标签添加到执行器 pods。例如, spark.kubernetes.executor.label.something=true 。请注意,Spark 还会为执行器 pod 添加自己的标签以供账务管理。 2.3.0
spark.kubernetes.executor.annotation.[注解名称] (无) 将 Kubernetes 注解 添加到执行器 pods,指定为 注解名称 。例如, spark.kubernetes.executor.annotation.something=true 2.3.0
spark.kubernetes.driver.pod.name (无) 驱动 pod 的名称。在集群模式下,如果未设置,将驱动 pod 名称设置为 "spark.app.name",后缀为当前时间戳,以避免名称冲突。在客户端模式下,如果应用程序在 pod 内运行,强烈建议将其设置为驱动所在 pod 的名称。在客户端模式下设置此值使驱动成为其执行器 pods 的所有者,进而允许执行器 pods 被集群垃圾回收。 2.3.0
spark.kubernetes.executor.podNamePrefix (无) 用于执行器 pod 名称前缀。必须遵循 Kubernetes DNS 标签名称 的规则。该前缀将用于生成形式为 $podNamePrefix-exec-$id 的执行器 pod 名称,其中 `id` 是正整数值,因此 `podNamePrefix` 的长度需要小于或等于 47 (= 63 - 10 - 6)。 2.3.0
spark.kubernetes.submission.waitAppCompletion true 在集群模式下,是否在启动器进程退出之前等待应用程序完成。当更改为 false 时,启动器在启动 Spark 作业时具有 "fire-and-forget" 行为。 2.3.0
spark.kubernetes.report.interval 1s 集群模式下当前 Spark 作业状态报告之间的间隔。 2.3.0
spark.kubernetes.executor.apiPollingInterval 30s 对 Kubernetes API 服务器进行轮询以检查执行器状态之间的间隔。 2.4.0
spark.kubernetes.driver.request.cores (无) 指定驱动 pod 的 CPU 请求。值遵循 Kubernetes 的 约定 。示例值包括 0.1、500m、1.5、5 等,CPU 单位的定义在 CPU 单位 中有文档说明。如果设置,将优先于 spark.driver.cores 用于指定驱动 pod 的 CPU 请求。 3.0.0
spark.kubernetes.driver.limit.cores (无) 为驱动 pod 指定一个硬 CPU 限制 2.3.0
spark.kubernetes.executor.request.cores (无) 为每个执行器 pod 指定 CPU 请求。值遵循 Kubernetes 的 约定 。示例值包括 0.1、500m、1.5、5 等,CPU 单位的定义在 CPU 单位 中有文档说明。此值与 spark.executor.cores 是不同的:它仅在设置时用于并优先于 spark.executor.cores 来指定执行器 pod 的 CPU 请求。任务并行性,例如,执行器可以同时运行的任务数不受此影响。 2.4.0
spark.kubernetes.executor.limit.cores (无) 为 Spark 应用程序启动的每个执行器 pod 指定一个硬 CPU 限制 2.3.0
spark.kubernetes.node.selector.[labelKey] (无) labelKey 作为键和值添加到驱动 pod 和执行器 pod 的节点选择器中。例如,设置 spark.kubernetes.node.selector.identifier myIdentifier 将导致驱动和执行器具有键为 identifier 且值为 myIdentifier 的节点选择器。通过使用此前缀设置多个配置可以添加多个节点选择器键。 2.3.0
spark.kubernetes.driver.node.selector.[labelKey] (无) labelKey 作为键和值添加到驱动 pod 的节点选择器中。例如,设置 spark.kubernetes.driver.node.selector.identifier myIdentifier 将导致驱动 pod 具有键为 identifier 且值为 myIdentifier 的节点选择器。通过使用此前缀设置多个配置可以添加多个驱动节点选择器键。 3.3.0
spark.kubernetes.executor.node.selector.[labelKey] (无) labelKey 作为键和值添加到执行器 pods 的节点选择器中。例如,设置 spark.kubernetes.executor.node.selector.identifier myIdentifier 将导致执行器具有键为 identifier 且值为 myIdentifier 的节点选择器。通过使用此前缀设置多个配置可以添加多个执行器节点选择器键。 3.3.0
spark.kubernetes.driverEnv.[环境变量名称] (无) 将由 环境变量名称 指定的环境变量添加到驱动进程中。用户可以指定多个这些来设置多个环境变量。 2.3.0
spark.kubernetes.driver.secrets.[密钥名称] (无) 将名为 密钥名称 Kubernetes 密钥 添加到驱动 pod 中指定的路径。例如, spark.kubernetes.driver.secrets.spark-secret=/etc/secrets 2.3.0
spark.kubernetes.executor.secrets.[密钥名称] (无) 将名为 密钥名称 Kubernetes 密钥 添加到执行器 pod 中指定的路径。例如, spark.kubernetes.executor.secrets.spark-secret=/etc/secrets 2.3.0
spark.kubernetes.driver.secretKeyRef.[环境变量名称] (无) 将作为名为 EnvName(大小写敏感)的环境变量添加到驱动容器中,其值由引用的 Kubernetes 密钥 中的密钥 key 引用的数据提供。例如, spark.kubernetes.driver.secretKeyRef.ENV_VAR=spark-secret:key 2.4.0
spark.kubernetes.executor.secretKeyRef.[环境变量名称] (无) 将作为名为 EnvName(大小写敏感)的环境变量添加到执行器容器中,其值由引用的 Kubernetes 密钥 中的密钥 key 引用的数据提供。例如, spark.kubernetes.executor.secrets.ENV_VAR=spark-secret:key 2.4.0
spark.kubernetes.driver.volumes.[卷类型].[卷名称].mount.path (无) 将名为 卷名称 Kubernetes 卷 类型为 卷类型 的卷添加到驱动 pod 中指定的路径。例如, spark.kubernetes.driver.volumes.persistentVolumeClaim.checkpointpvc.mount.path=/checkpoint 2.4.0
spark.kubernetes.driver.volumes.[卷类型].[卷名称].mount.subPath (无) 指定从卷中挂载到驱动 pod 的 子路径 spark.kubernetes.driver.volumes.persistentVolumeClaim.checkpointpvc.mount.subPath=checkpoint 3.0.0
spark.kubernetes.driver.volumes.[卷类型].[卷名称].mount.readOnly (无) 指定挂载的卷是否为只读。例如, spark.kubernetes.driver.volumes.persistentVolumeClaim.checkpointpvc.mount.readOnly=false 2.4.0
spark.kubernetes.driver.volumes.[卷类型].[卷名称].options.[选项名称] (无) 配置 Kubernetes 卷 选项,传递给 Kubernetes, 选项名称 作为键,具有指定的值,必须符合 Kubernetes 选项格式。例如, spark.kubernetes.driver.volumes.persistentVolumeClaim.checkpointpvc.options.claimName=spark-pvc-claim 2.4.0
spark.kubernetes.executor.volumes.[卷类型].[卷名称].mount.path (无) 将名为 卷名称 Kubernetes 卷 类型为 卷类型 的卷添加到执行器 pod 中指定的路径。例如, spark.kubernetes.executor.volumes.persistentVolumeClaim.checkpointpvc.mount.path=/checkpoint 2.4.0
spark.kubernetes.executor.volumes.[卷类型].[卷名称].mount.subPath (无) 指定从卷中挂载到执行器 pod 的 子路径 spark.kubernetes.executor.volumes.persistentVolumeClaim.checkpointpvc.mount.subPath=checkpoint 3.0.0
spark.kubernetes.executor.volumes.[卷类型].[卷名称].mount.readOnly false 指定挂载的卷是否为只读。例如, spark.kubernetes.executor.volumes.persistentVolumeClaim.checkpointpvc.mount.readOnly=false 2.4.0
spark.kubernetes.executor.volumes.[卷类型].[卷名称].options.[选项名称] (无) 配置 Kubernetes 卷 选项,传递给 Kubernetes, 选项名称 作为键,具有指定的值。例如, spark.kubernetes.executor.volumes.persistentVolumeClaim.checkpointpvc.options.claimName=spark-pvc-claim 2.4.0
spark.kubernetes.local.dirs.tmpfs false 配置用于支持 SPARK_LOCAL_DIRS emptyDir 卷,以便在 Spark 驱动和执行器 pods 中使用 tmpfs 支持,即 RAM。有关更多讨论,请参见本页面前面关于 本地存储 的内容。 3.0.0
spark.kubernetes.memoryOverheadFactor 0.1 此参数设置内存开销因子,用于为非 JVM 内存分配内存,包括堆外内存分配、非 JVM 任务、各种系统进程以及在 spark.kubernetes.local.dirs.tmpfs true 时基于 tmpfs 的本地目录。对于基于 JVM 的作业,此值默认设置为 0.10,对于非 JVM 作业设置为 0.40。这是因为非 JVM 任务需要更多的非 JVM 堆空间,这样的任务通常会因“内存开销超出限制”错误而失败。通过设置更高的默认值来预防此错误。此设置将被明确设置的 spark.driver.memoryOverheadFactor spark.executor.memoryOverheadFactor 的值覆盖。 2.4.0
spark.kubernetes.pyspark.pythonVersion "3" 此参数设置用于运行驱动和执行器容器的 Docker 镜像的主要 Python 版本。只能为 "3"。此配置自 Spark 3.1.0 起已被弃用,实际上无效。用户应设置 'spark.pyspark.python' 和 'spark.pyspark.driver.python' 配置或 'PYSPARK_PYTHON' 和 'PYSPARK_DRIVER_PYTHON' 环境变量。 2.4.0
spark.kubernetes.kerberos.krb5.path (无) 指定要安装在驱动程序和执行器上的 krb5.conf 文件的本地位置,以便进行 Kerberos 交互。需要注意的是,定义的 KDC 需要能在容器内部可见。 3.0.0
spark.kubernetes.kerberos.krb5.configMapName (无) 指定包含 krb5.conf 文件的 ConfigMap 的名称,以便在驱动程序和执行器上进行 Kerberos 交互。定义的 KDC 需要能在容器内部可见。ConfigMap 还必须位于驱动和执行器 pods 的同一命名空间中。 3.0.0
spark.kubernetes.hadoop.configMapName (无) 指定包含 HADOOP_CONF_DIR 文件的 ConfigMap 名称,以便在驱动程序和执行器上进行自定义 Hadoop 配置。 3.0.0
spark.kubernetes.kerberos.tokenSecret.name (无) 指定存储您现有授权令牌的密钥名称。这消除了作业用户在启动作业时提供任何 Kerberos 凭据的需要。 3.0.0
spark.kubernetes.kerberos.tokenSecret.itemKey (无) 指定存储您现有授权令牌的数据文件项键。这消除了作业用户在启动作业时提供任何 Kerberos 凭据的需要。 3.0.0
spark.kubernetes.driver.podTemplateFile (无) 指定包含驱动 pod 模板 的本地文件。例如, spark.kubernetes.driver.podTemplateFile=/path/to/driver-pod-template.yaml 3.0.0
spark.kubernetes.driver.podTemplateContainerName (无) 指定要在给定 pod 模板 中用作驱动基础的容器名称。例如, spark.kubernetes.driver.podTemplateContainerName=spark-driver 3.0.0
spark.kubernetes.executor.podTemplateFile (无) 指定包含执行器 pod 模板 的本地文件。例如, spark.kubernetes.executor.podTemplateFile=/path/to/executor-pod-template.yaml 3.0.0
spark.kubernetes.executor.podTemplateContainerName (无) 指定要在给定 pod 模板 中用作执行器基础的容器名称。例如, spark.kubernetes.executor.podTemplateContainerName=spark-executor 3.0.0
spark.kubernetes.executor.deleteOnTermination true 指定在失败或正常终止的情况下,执行器 pods 是否应被删除。 3.0.0
spark.kubernetes.executor.checkAllContainers false 指定在确定 pod 状态时,执行器 pods 是否应检查所有容器(包括侧车)或仅检查执行器容器。 3.1.0
spark.kubernetes.submission.connectionTimeout 10000 Kubernetes 客户端在启动驱动时使用的连接超时(毫秒)。 3.0.0
spark.kubernetes.submission.requestTimeout 10000 Kubernetes 客户端在启动驱动时使用的请求超时(毫秒)。 3.0.0
spark.kubernetes.trust.certificates false 如果设置为 true,则客户端可以仅凭令牌提交到 Kubernetes 集群。 3.2.0
spark.kubernetes.driver.connectionTimeout 10000 驱动程序中 Kubernetes 客户端在请求执行器时使用的连接超时(毫秒)。 3.0.0
spark.kubernetes.driver.requestTimeout 10000 驱动程序中 Kubernetes 客户端在请求执行器时使用的请求超时(毫秒)。 3.0.0
spark.kubernetes.appKillPodDeletionGracePeriod (无) 指定使用 spark-submit 删除 Spark 应用程序时的宽限期(秒)。 3.0.0
spark.kubernetes.dynamicAllocation.deleteGracePeriod 5s 在强制终止执行器之前,等待执行器优雅关闭的时间。 3.0.0
spark.kubernetes.file.upload.path (无) 在集群模式下,存储文件的路径。例如: spark.kubernetes.file.upload.path=s3a:// /path 文件应指定为 file://path/to/file 或绝对路径。 3.0.0
spark.kubernetes.executor.decommissionLabel (无) 应用于正在退出或被停用的 pods 的标签。旨在与 pod 中断预算、删除成本及类似用法一起使用。 3.3.0
spark.kubernetes.executor.decommissionLabelValue (无) 在启用 spark.kubernetes.executor.decommissionLabel 时与标签一起应用的值。 3.3.0
spark.kubernetes.executor.scheduler.name (无) 为每个执行器 pod 指定调度程序名称。 3.0.0
spark.kubernetes.driver.scheduler.name (无) 为驱动 pod 指定调度程序名称。 3.3.0
spark.kubernetes.scheduler.name (无) 为驱动和执行器 pods 指定调度程序名称。如果设置了 `spark.kubernetes.driver.scheduler.name` 或 `spark.kubernetes.executor.scheduler.name`,则将覆盖此值。 3.3.0
spark.kubernetes.configMap.maxSize 1572864 ConfigMap 的最大大小限制。根据 k8s 服务器端的 限制 可配置。 3.1.0
spark.kubernetes.executor.missingPodDetectDelta 30s 当注册的执行器的 POD 从 Kubernetes API 服务器的轮询 POD 列表中缺失时,此时间差被视为注册时间和轮询时间之间的接受时间。超过此时间后,将认为 POD 从集群中缺失,执行器将被删除。 3.1.1
spark.kubernetes.decommission.script /opt/decom.sh 用于优雅退役的脚本位置。 3.2.0
spark.kubernetes.driver.service.deleteOnTermination true 如果为 true,则在 Spark 应用程序终止时将删除驱动服务。如果为 false,则在删除驱动 pod 时将进行清理。 3.2.0
spark.kubernetes.driver.service.ipFamilyPolicy SingleStack 驱动服务的 K8s IP 家族策略。有效值为 SingleStack PreferDualStack RequireDualStack 3.4.0
spark.kubernetes.driver.service.ipFamilies IPv4 K8s 驱动服务的 IP 家族列表。有效值为 IPv4 IPv6 3.4.0
spark.kubernetes.driver.ownPersistentVolumeClaim true 如果为 true,则驱动 pod 成为按需持久卷声明的所有者,而不是执行器 pods。 3.2.0
spark.kubernetes.driver.reusePersistentVolumeClaim true 如果为 true,则驱动 pod 尝试重用已删除执行器 pods 的驱动拥有的按需持久卷声明(如果存在)。这可以通过跳过持久卷创建来减少执行器 pod 的创建延迟。请注意,处于 `Terminating` pod 状态的 pod 按定义不是被删除的 pod,因此它的资源(包括持久卷声明)尚不可重用。当不存在可重用时,Spark 将创建新的持久卷声明。换句话说,有时持久卷声明的总数可能大于运行中的执行器数量。此配置需要 spark.kubernetes.driver.ownPersistentVolumeClaim=true. 3.2.0
spark.kubernetes.driver.waitToReusePersistentVolumeClaim false 如果为 true,则驱动 pod 计算创建的按需持久卷声明的数量,并在数量大于或等于 Spark 作业可以拥有的卷的总数时等待。此配置要求同时设置 spark.kubernetes.driver.ownPersistentVolumeClaim=true spark.kubernetes.driver.reusePersistentVolumeClaim=true 3.4.0
spark.kubernetes.executor.disableConfigMap false 如果为 true,则禁用针对执行器的 ConfigMap 创建。 3.2.0
spark.kubernetes.driver.pod.featureSteps (无) 实现 `KubernetesFeatureConfigStep` 的额外驱动 pod 特性步骤的类名称。这是开发者 API。用逗号分隔。在所有 Spark 内部特性步骤之后运行。从 3.3.0 开始,您的驱动特性步骤可以实现 `KubernetesDriverCustomFeatureConfigStep`,届时驱动配置也可用。 3.2.0
spark.kubernetes.executor.pod.featureSteps (无) 实现 `KubernetesFeatureConfigStep` 的额外执行器 pod 特性步骤的类名称。这是开发者 API。用逗号分隔。在所有 Spark 内部特性步骤之后运行。从 3.3.0 开始,您的执行器特性步骤可以实现 `KubernetesExecutorCustomFeatureConfigStep`,届时执行器配置也可用。 3.2.0
spark.kubernetes.allocation.maxPendingPods Int.MaxValue 在为该应用程序分配执行器时,允许的最大待处理 POD 数量。这些新请求的执行器,Kubernetes 还未知道,也算在此限制内,因为它们会随着时间变化成待处理 POD。这一限制独立于资源配置文件,因为它限制所有使用的资源配置文件的分配总和。 3.2.0
spark.kubernetes.allocation.pods.allocator direct 用于 pods 的分配器。可能的值为 direct (默认)和 statefulset ,或实现 `AbstractPodsAllocator` 的类的完全类名。将来可能会添加 Job 或 replicaset。这是开发者 API,可能会随时更改或删除。 3.3.0
spark.kubernetes.allocation.executor.timeout 600s 在考虑超时并将新创建的执行器 POD 请求删除之前,等待的时间,该请求尚未达到 POD 待处理状态。 3.1.0
spark.kubernetes.allocation.driver.readinessTimeout 1s 在创建执行器 pods 之前,等待驱动 pod 准备就绪的时间。此等待仅在应用程序启动时发生。如果超时发生,执行器 pods 仍将被创建。 3.1.3
spark.kubernetes.executor.enablePollingWithResourceVersion false 如果为 true,则在调用 pod 列表 API 时将 `resourceVersion` 设置为 `0`,以允许 API 服务器端缓存。应谨慎使用此项。 3.3.0
spark.kubernetes.executor.eventProcessingInterval 1s 从 Kubernetes API 发送的执行器事件连续检查之间的间隔。 2.4.0
spark.kubernetes.executor.rollInterval 0s 执行器滚动操作之间的间隔。默认禁用,值为 `0s`。 3.3.0
spark.kubernetes.executor.minTasksPerExecutorBeforeRolling 0 执行器滚动前每个执行器的最小任务数。Spark 不会滚动任务总数小于该配置的执行器。默认值为零。 3.3.0
spark.kubernetes.executor.rollPolicy OUTLIER 执行器滚动策略:有效值为 ID、ADD_TIME、TOTAL_GC_TIME、TOTAL_DURATION、FAILED_TASKS 和 OUTLIER(默认)。当执行器滚动发生时,Spark 使用此策略选择一个执行器并进行停用。内置策略基于执行器摘要,新启动的执行器受 spark.kubernetes.executor.minTasksPerExecutorBeforeRolling 保护。ID 策略选择具有最小执行器 ID 的执行器。ADD_TIME 策略选择具有最小添加时间的执行器。TOTAL_GC_TIME 策略选择具有最大任务总 GC 时间的执行器。TOTAL_DURATION 策略选择具有最大任务总时间的执行器。AVERAGE_DURATION 策略选择具有最大平均任务时间的执行器。FAILED_TASKS 策略选择具有最多失败任务的执行器。OUTLIER 策略选择在平均任务时间、总任务时间、总任务 GC 时间和失败任务数中,与平均值相比,至少大于两个标准差的执行器。如果没有异常,它的行为就像 TOTAL_DURATION 策略一样。 3.3.0

Pod 模板属性

请查看下表以获取将被spark覆盖的pod规格的完整列表。

Pod 元数据

Pod 元数据键 修改后的值 描述
name 值为 spark.kubernetes.driver.pod.name 驱动程序 Pod 的名称将被配置的或默认的 spark.kubernetes.driver.pod.name 的值覆盖。执行器 Pod 名称将不受影响。
namespace 值为 spark.kubernetes.namespace Spark 对驱动程序和执行器的命名空间做出强假设。驱动程序和执行器的命名空间将被配置的或默认的 Spark 配置值替换。
labels 添加来自 spark.kubernetes.{driver,executor}.label.* 的标签 Spark 将添加由 Spark 配置指定的其他标签。
annotations 添加来自 spark.kubernetes.{driver,executor}.annotation.* 的注释 Spark 将添加由 Spark 配置指定的其他注释。

Pod 规范

Pod 规格键 修改后的值 描述
imagePullSecrets spark.kubernetes.container.image.pullSecrets 添加镜像拉取秘密 将从 Spark 配置中添加额外的拉取秘密到两个执行器 pod。
nodeSelector spark.kubernetes.node.selector.* 添加节点选择器 将从 Spark 配置中添加额外的节点选择器到两个执行器 pod。
restartPolicy "never" Spark 假定驱动程序和执行程序永不重启。
serviceAccount spark.kubernetes.authenticate.driver.serviceAccountName 的值 Spark 将仅在指定 Spark 配置的情况下,用 Spark 配置的值覆盖 serviceAccount ,仅适用于驱动程序 pod,执行器 pod 将不受影响。
serviceAccountName spark.kubernetes.authenticate.driver.serviceAccountName 的值 Spark 将仅在指定 Spark 配置的情况下,用 Spark 配置的值覆盖 serviceAccountName ,仅适用于驱动程序 pod,执行器 pod 将不受影响。
volumes spark.kubernetes.{driver,executor}.volumes.[VolumeType].[VolumeName].mount.path 添加卷 Spark 将按照 Spark 配置添加卷,以及传递 Spark 配置和 pod 模板文件所需的额外卷。

容器规范

以下内容会影响驱动程序和执行程序容器。其他在 pod 规格中的容器将不受影响。

容器规格键 修改值 描述
env spark.kubernetes.driverEnv.[EnvironmentVariableName] 添加环境变量 Spark 将从 spark.kubernetes.driverEnv.[EnvironmentVariableName] 添加驱动程序环境变量,并从 spark.executorEnv.[EnvironmentVariableName] 添加执行程序环境变量。
image 值为 spark.kubernetes.{driver,executor}.container.image 镜像将由 Spark 配置定义。
imagePullPolicy 值为 spark.kubernetes.container.image.pullPolicy Spark 将覆盖驱动程序和执行程序的拉取策略。
name 见描述 如果未由 Pod 模板定义,容器名称将由 Spark 分配(驱动程序容器的名称为 "spark-kubernetes-driver",每个执行程序容器的名称为 "spark-kubernetes-executor")。如果容器由模板定义,则将使用模板的名称。
resources 见描述 CPU 限制由 spark.kubernetes.{driver,executor}.limit.cores 设置。CPU 由 spark.{driver,executor}.cores 设置。内存请求和限制通过累加 spark.{driver,executor}.memory spark.{driver,executor}.memoryOverhead 的值来设置。 其他资源限制由 spark.{driver,executor}.resources.{resourceName}.* 配置设置。
volumeMounts spark.kubernetes.driver.volumes.[VolumeType].[VolumeName].mount.{path,readOnly} 添加卷 Spark 将根据 Spark 配置添加卷,以及为传递 Spark 配置和 Pod 模板文件而需要的额外卷。

资源分配与配置概述

请确保您已阅读 配置页面 上的自定义资源调度和配置概述部分。本节仅讲述与Kubernetes特定的资源调度相关的内容。

用户负责正确配置Kubernetes集群,以确保资源可用,并理想上为每个容器隔离每个资源,以便资源不会在多个容器之间共享。如果资源没有被隔离,用户需要负责编写发现脚本,以确保资源不在容器之间共享。有关如何使用 自定义资源 配置Kubernetes的详细信息,请参阅Kubernetes文档。

Spark 自动处理将 Spark 配置 spark.{driver/executor}.resource.{resourceType} 转换为 Kubernetes 配置,只要 Kubernetes 资源类型遵循 Kubernetes 设备插件格式 vendor-domain/resourcetype 。用户必须使用 spark.{driver/executor}.resource.{resourceType}.vendor 配置来指定供应商。如果您使用 Pod 模板,则用户无需显式添加任何内容。有关参考和示例,您可以查看 Kubernetes 文档以调度 GPUs 。Spark 仅支持设置资源限制。

Kubernetes 不会告诉 Spark 每个容器分配资源的地址。因此,用户必须指定一个发现脚本,该脚本在执行器启动时运行,以发现该执行器可用的资源。您可以在 examples/src/main/scripts/getGpusResources.sh 中找到示例脚本。该脚本必须具有执行权限,并且用户应设置权限以不允许恶意用户修改它。该脚本应向 STDOUT 写入以 ResourceInformation 类格式的 JSON 字符串。它包含资源名称和仅对该执行器可用的资源地址数组。

资源水平调度概述

Spark在Kubernetes上支持几种资源级调度特性。

优先级调度

Kubernetes 默认支持 Pod 优先级

Spark 在 Kubernetes 上允许通过 Pod 模板 定义作业的优先级。用户可以在驱动程序或执行者 Pod 模板 spec 部分中指定 priorityClassName 。下面是一个示例,展示如何指定它:

apiVersion: v1
Kind: Pod
metadata:
labels:
template-label-key: driver-template-label-value
spec:
# 在这里指定优先级
priorityClassName: system-node-critical
containers:
- name: test-driver-container
image: will-be-overwritten

针对Kubernetes上Spark的定制化Kubernetes调度器

Spark 允许用户指定自定义的 Kubernetes 调度器。

  1. 指定调度器名称。

    用户可以使用 spark.kubernetes.scheduler.name spark.kubernetes.{driver/executor}.scheduler.name 配置来指定自定义调度器。

  2. 指定与调度器相关的配置。

    要配置自定义调度器,用户可以使用 Pod 模板 ,添加标签 ( spark.kubernetes.{driver,executor}.label.* )、注解 ( spark.kubernetes.{driver/executor}.annotation.* ) 或特定于调度器的配置(例如 spark.kubernetes.scheduler.volcano.podGroupTemplateFile )。

  3. 指定调度器特性步骤。

    用户还可以考虑使用 spark.kubernetes.{driver/executor}.pod.featureSteps 来支持更复杂的需求,包括但不限于:

    • 为驱动程序/执行程序调度创建额外的 Kubernetes 自定义资源。
    • 根据配置或现有 Pod 信息动态设置调度器提示。

在Kubernetes上使用Volcano作为Spark的自定义调度器

先决条件
构建

要创建一个带有Volcano支持的Spark发行版,就像在Spark 下载页面 中分发的那样,更多信息请参见 “构建Spark” :

./dev/make-distribution.sh --name 自定义-spark --pip --r --tgz -Psparkr -Phive -Phive-thriftserver -Pkubernetes -Pvolcano
用法

Spark on Kubernetes 允许使用 Volcano 作为自定义调度器。用户可以使用 Volcano 来支持更高级的资源调度:队列调度、资源预留、优先级调度等。

要使用Volcano作为自定义调度器,用户需要指定以下配置选项:

# 指定火山调度器和 PodGroup 模板
--conf spark.kubernetes.scheduler.name=volcano
--conf spark.kubernetes.scheduler.volcano.podGroupTemplateFile=/path/to/podgroup-template.yaml
# 指定驱动程序/执行程序 VolcanoFeatureStep
--conf spark.kubernetes.driver.pod.featureSteps=org.apache.spark.deploy.k8s.features.VolcanoFeatureStep
--conf spark.kubernetes.executor.pod.featureSteps=org.apache.spark.deploy.k8s.features.VolcanoFeatureStep
火山特征步骤

火山功能步骤帮助用户创建一个火山 PodGroup,并设置驱动程序/执行器 pod 注解以链接此 PodGroup

请注意,目前在Volcano功能步骤中仅支持驱动程序/作业级别的PodGroup。

火山 PodGroup 模板

火山通过使用 CRD yaml 定义 PodGroup 规格。

类似于 Pod 模板 ,Spark 用户可以使用 Volcano PodGroup 模板来定义 PodGroup 规范配置。要做到这一点,请指定 Spark 属性 spark.kubernetes.scheduler.volcano.podGroupTemplateFile ,指向可被 spark-submit 进程访问的文件。以下是 PodGroup 模板的示例:

apiVersion: scheduling.volcano.sh/v1beta1
kind: PodGroup
spec:
# 将 minMember 设置为 1 以创建驱动程序 Pod
minMember: 1
# 指定 minResources 以支持资源预留(驱动程序 Pod 资源和执行器 Pod 资源应予以考虑)
# 这对于确保可用资源满足 Spark 作业的最低要求以及避免
# 驱动程序已调度,但无法调度足够的执行器以实现进展的情况。
minResources:
cpu: "2"
memory: "3Gi"
# 指定优先级,帮助用户在调度时指定队列中的作业优先级。
priorityClassName: system-node-critical
# 指定队列,表示作业应提交到的资源队列
queue: default

在 Kubernetes 上使用 Apache YuniKorn 作为 Spark 的定制调度器

Apache YuniKorn 是一个 Kubernetes 的资源调度器,提供先进的批处理调度能力,例如作业排队、资源公平性、最小/最大队列容量和灵活的作业排序策略。有关可用的 Apache YuniKorn 功能,请参考 核心功能

先决条件

安装 Apache YuniKorn:

helm repo add yunikorn https://apache.github.io/yunikorn-release
helm repo update
helm 安装 yunikorn yunikorn/yunikorn --命名空间 yunikorn --版本 1.3.0 --创建命名空间 --设置 embedAdmissionController=false

上述步骤将在现有的Kubernetes集群上安装YuniKorn v1.3.0。

开始使用

提交 Spark 任务时可以使用以下额外选项:

--conf spark.kubernetes.scheduler.name=yunikorn
--conf spark.kubernetes.driver.label.queue=root.default
--conf spark.kubernetes.executor.label.queue=root.default
--conf spark.kubernetes.driver.annotation.yunikorn.apache.org/app-id={{APP_ID}}
--conf spark.kubernetes.executor.annotation.yunikorn.apache.org/app-id={{APP_ID}}

请注意,{{APP_ID}} 是一个内置变量,它将自动替换为 Spark 作业 ID。通过上述配置,作业将由 YuniKorn 调度器调度,而不是默认的 Kubernetes 调度器。

阶段级调度概述

在Kubernetes上支持阶段级调度: