在 Kubernetes 上运行 Spark
Spark 可以在由 Kubernetes 管理的集群上运行。此功能利用了已添加到 Spark 中的原生 Kubernetes 调度器。
安全性
默认情况下不启用诸如认证之类的安全功能。当部署一个面向互联网或不可信网络的集群时,保护对集群的访问以防止未经授权的应用程序在集群上运行非常重要。在运行 Spark 之前,请参阅 Spark 安全性以及本文档中的特定安全部分。
用户身份
从项目提供的 Dockerfile 构建的镜像包含一个默认的 USER
指令,其默认 UID 为 185
。这意味着生成的镜像将在容器内以该 UID 运行 Spark 进程。注重安全性的部署应考虑提供带有 USER
指令的自定义镜像,指定所需的非特权 UID 和 GID。生成的 UID 应在其补充组中包含 root 组,以便能够运行 Spark 可执行文件。使用提供的 docker-image-tool.sh
脚本构建自己镜像的用户可以使用 -u <uid>
选项来指定所需的 UID。
或者,可以使用 Pod 模板 功能向 Spark 提交的 Pod 添加一个包含 runAsUser
的 安全上下文。这可以用于覆盖镜像本身中的 USER
指令。请注意,这需要用户的配合,因此可能不适合共享环境。如果集群管理员希望限制 Pod 可以运行的用户,他们应该使用 Pod 安全策略。
卷挂载
如本文档后面 使用 Kubernetes 卷 部分所述,Spark on K8S 提供了允许将某些卷类型挂载到驱动程序和执行器 Pod 中的配置选项。特别是,它允许使用 hostPath
卷,如 Kubernetes 文档所述,这些卷存在已知的安全漏洞。
集群管理员应使用 Pod 安全策略,根据其环境适当地限制挂载 hostPath
卷的能力。
先决条件
- 一个运行中且版本 >= 1.30 的 Kubernetes 集群,并且已使用 kubectl 配置了访问权限。如果您还没有一个可用的 Kubernetes 集群,可以使用 minikube 在本地机器上设置一个测试集群。
- 我们建议使用最新版本的 minikube 并启用 DNS 插件。
- 请注意,默认的 minikube 配置不足以运行 Spark 应用程序。我们建议使用 3 个 CPU 和 4g 内存,以便能够启动一个带有单个执行器的简单 Spark 应用程序。
- 检查您的 Spark 环境中 kubernetes-client 库 的版本,以及它与您的 Kubernetes 集群版本的兼容性。
- 您必须拥有足够的权限才能在集群中列出、创建、编辑和删除 Pod。您可以通过运行
kubectl auth can-i <list|create|edit|delete> pods
来验证您是否可以列出这些资源。- 驱动程序 Pod 使用的服务帐户凭据必须允许创建 Pod、服务和 ConfigMap。
- 您的集群中必须配置 Kubernetes DNS。
工作原理
spark-submit
可以直接用于向 Kubernetes 集群提交 Spark 应用程序。提交机制的工作原理如下:
- Spark 在 Kubernetes Pod 内创建一个 Spark 驱动程序。
- 驱动程序创建执行器,这些执行器也运行在 Kubernetes Pod 内并连接到它们,然后执行应用程序代码。
- 当应用程序完成后,执行器 Pod 会终止并被清理,但驱动程序 Pod 会保留日志并保持在 Kubernetes API 中的“已完成”状态,直到最终被垃圾回收或手动清理。
请注意,在“已完成”状态下,驱动程序 Pod 不使用任何计算或内存资源。
驱动程序和执行器 Pod 的调度由 Kubernetes 处理。与 Kubernetes API 的通信通过 fabric8 进行。可以通过配置属性使用 节点选择器 将驱动程序和执行器 Pod 调度到可用节点的一个子集上。在未来的版本中,将可以使用更高级的调度提示,例如 节点/Pod 亲和性。
向 Kubernetes 提交应用程序
Docker 镜像
Kubernetes 要求用户提供可以部署到 Pod 中容器的镜像。这些镜像旨在在 Kubernetes 支持的容器运行时环境中运行。Docker 是一个经常与 Kubernetes 一起使用的容器运行时环境。Spark(从版本 2.3 开始)附带一个 Dockerfile,可用于此目的,或根据单个应用程序的需求进行定制。它可以在 kubernetes/dockerfiles/
目录中找到。
Spark 还附带一个 bin/docker-image-tool.sh
脚本,可用于构建和发布要与 Kubernetes 后端一起使用的 Docker 镜像。
用法示例:
$ ./bin/docker-image-tool.sh -r <repo> -t my-tag build
$ ./bin/docker-image-tool.sh -r <repo> -t my-tag push
这将使用项目提供的默认 Dockerfiles
进行构建。要查看更多可用于自定义此工具行为的选项,包括提供自定义 Dockerfiles
,请使用 -h
标志运行。
默认情况下,bin/docker-image-tool.sh
构建用于运行 JVM 作业的 Docker 镜像。您需要选择构建额外的语言绑定 Docker 镜像。
用法示例:
# To build additional PySpark docker image
$ ./bin/docker-image-tool.sh -r <repo> -t my-tag -p ./kubernetes/dockerfiles/spark/bindings/python/Dockerfile build
# To build additional SparkR docker image
$ ./bin/docker-image-tool.sh -r <repo> -t my-tag -R ./kubernetes/dockerfiles/spark/bindings/R/Dockerfile build
您也可以直接使用 Apache Spark Docker 镜像(例如 apache/spark:<version>
)。
集群模式
要在集群模式下启动 Spark Pi,
$ ./bin/spark-submit \
--master k8s://https://<k8s-apiserver-host>:<k8s-apiserver-port> \
--deploy-mode cluster \
--name spark-pi \
--class org.apache.spark.examples.SparkPi \
--conf spark.executor.instances=5 \
--conf spark.kubernetes.container.image=<spark-image> \
local:///path/to/examples.jar
Spark Master,可以通过将 --master
命令行参数传递给 spark-submit
或在应用程序配置中设置 spark.master
来指定,必须是格式为 k8s://<api_server_host>:<k8s-apiserver-port>
的 URL。即使是 HTTPS 端口 443,也必须始终指定端口。在 master 字符串前加上 k8s://
将导致 Spark 应用程序在 Kubernetes 集群上启动,并与 api_server_url
处的 API 服务器联系。如果 URL 中未指定 HTTP 协议,则默认为 https
。例如,将 master 设置为 k8s://example.com:443
等同于设置为 k8s://https://example.com:443
,但要在不同端口上不使用 TLS 连接,master 将设置为 k8s://http://example.com:8080
。
在 Kubernetes 模式下,通过 spark.app.name
或 spark-submit
的 --name
参数指定的 Spark 应用程序名称,默认用于命名创建的 Kubernetes 资源,例如驱动程序和执行器。因此,应用程序名称必须由小写字母数字字符、-
和 .
组成,并且必须以字母数字字符开头和结尾。
如果您已经设置了 Kubernetes 集群,一种发现 apiserver URL 的方法是执行 kubectl cluster-info
。
$ kubectl cluster-info
Kubernetes master is running at http://127.0.0.1:6443
在上述示例中,可以通过将 --master k8s://http://127.0.0.1:6443
作为参数传递给 spark-submit 来使用特定的 Kubernetes 集群。此外,还可以使用认证代理 kubectl proxy
与 Kubernetes API 进行通信。
本地代理可以通过以下方式启动:
$ kubectl proxy
如果本地代理在 localhost:8001 运行,则可以将 --master k8s://http://127.0.0.1:8001
作为参数传递给 spark-submit。最后,请注意在上述示例中,我们指定了一个具有特定 URI 且方案为 local://
的 jar 包。此 URI 是 Docker 镜像中已存在的示例 jar 包的位置。
客户端模式
从 Spark 2.4.0 开始,可以在客户端模式下在 Kubernetes 上运行 Spark 应用程序。当您的应用程序在客户端模式下运行时,驱动程序可以运行在 Pod 内部或物理主机上。在客户端模式下运行应用程序时,建议考虑以下因素:
客户端模式网络
Spark 执行器必须能够通过 Spark 执行器可路由的主机名和端口连接到 Spark 驱动程序。Spark 在客户端模式下工作所需的具体网络配置会因设置而异。如果您在 Kubernetes Pod 内部运行驱动程序,可以使用 无头服务,通过一个稳定的主机名使驱动程序 Pod 可以从执行器进行路由。部署无头服务时,请确保服务的标签选择器只匹配驱动程序 Pod,而不匹配其他 Pod;建议为驱动程序 Pod 分配一个足够唯一的标签,并在无头服务的标签选择器中使用该标签。通过 spark.driver.host
指定驱动程序的主机名,并通过 spark.driver.port
指定 Spark 驱动程序的端口。
客户端模式执行器 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 环境,该功能允许为 Pod 和服务同时分配 IPv4 和 IPv6 地址。根据 K8s 集群的能力,spark.kubernetes.driver.service.ipFamilyPolicy
可以是 SingleStack
、PreferDualStack
和 RequireDualStack
之一,而 spark.kubernetes.driver.service.ipFamilies
可以是 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
环境变量来添加到类路径中。local://
方案在 spark-submit
中引用自定义构建的 Docker 镜像中的依赖项时也是必需的。我们支持使用 file://
方案或不带方案(使用完整路径)从提交客户端的本地文件系统获取依赖项,其中目标应该是 Hadoop 兼容的文件系统。一个使用 S3 的典型示例是通过传递以下选项:
...
--packages org.apache.hadoop:hadoop-aws:3.4.1
--conf spark.kubernetes.file.upload.path=s3a://<s3-bucket>/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 Secret 可用于为 Spark 应用程序访问安全服务提供凭证。要将用户指定的 Secret 挂载到驱动程序容器中,用户可以使用 spark.kubernetes.driver.secrets.[SecretName]=<mount path>
形式的配置属性。类似地,spark.kubernetes.executor.secrets.[SecretName]=<mount path>
形式的配置属性可用于将用户指定的 Secret 挂载到执行器容器中。请注意,假定要挂载的 Secret 与驱动程序和执行器 Pod 位于同一命名空间中。例如,要在驱动程序和执行器容器中的 /etc/secrets
路径上挂载名为 spark-secret
的 Secret,请将以下选项添加到 spark-submit
命令中:
--conf spark.kubernetes.driver.secrets.spark-secret=/etc/secrets
--conf spark.kubernetes.executor.secrets.spark-secret=/etc/secrets
要通过环境变量使用 Secret,请使用以下选项到 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 创建时自动挂载到一个卷上。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 中:
- hostPath:将主机节点文件系统中的文件或目录挂载到 Pod 中。
- emptyDir:当 Pod 分配给节点时创建的初始为空的卷。
- nfs:将现有 NFS(网络文件系统)挂载到 Pod 中。
- persistentVolumeClaim:将
PersistentVolume
挂载到 Pod 中。
注意: 有关卷挂载相关的安全问题,请参阅本文档的安全部分。
要将上述任何类型的卷挂载到驱动程序 Pod 中,请使用以下配置属性:
--conf spark.kubernetes.driver.volumes.[VolumeType].[VolumeName].mount.path=<mount path>
--conf spark.kubernetes.driver.volumes.[VolumeType].[VolumeName].mount.readOnly=<true|false>
--conf spark.kubernetes.driver.volumes.[VolumeType].[VolumeName].mount.subPath=<mount subPath>
具体来说,VolumeType
可以是以下值之一:hostPath
、emptyDir
、nfs
和 persistentVolumeClaim
。VolumeName
是您希望在 Pod 规范的 volumes
字段下用于卷的名称。
每种支持的卷类型都可能有一些特定的配置选项,可以使用以下形式的配置属性指定:
spark.kubernetes.driver.volumes.[VolumeType].[VolumeName].options.[OptionName]=<value>
例如,带有卷名称 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=OnDemand
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 属性部分。
面向 PVC 的执行器 Pod 分配
由于磁盘是重要的资源类型之一,Spark 驱动程序通过一组配置提供了细粒度的控制。例如,默认情况下,按需 PVC 归执行器所有,并且 PVC 的生命周期与其所属执行器紧密耦合。但是,按需 PVC 可以归驱动程序所有,并在 Spark 作业的生命周期内被其他执行器重用,通过以下选项实现。这减少了 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=<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=OnDemand
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 作为资源管理器时,Pod 将为 spark.local.dir
或环境变量 SPARK_LOCAL_DIRS
中列出的每个目录创建一个 emptyDir 卷。如果没有明确指定目录,则会创建一个默认目录并进行适当配置。
emptyDir
卷使用 Kubernetes 的临时存储功能,并且不会在 Pod 生命周期结束后持久存在。
使用 RAM 作为本地存储
emptyDir
卷默认使用节点的后端存储作为临时存储,这种行为可能不适用于某些计算环境。例如,如果您有无盘节点并挂载了通过网络连接的远程存储,那么大量的执行器对这种远程存储进行 IO 操作实际上可能会降低性能。
在这种情况下,可能需要将 spark.kubernetes.local.dirs.tmpfs=true
设置到您的配置中,这将导致 emptyDir
卷被配置为 tmpfs
,即内存支持的卷。当这样配置时,Spark 的本地存储使用量将计入您的 Pod 内存使用量,因此您可能需要酌情增加 spark.{driver,executor}.memoryOverheadFactor
的值以增加内存请求。
内省和调试
以下是您可以调查正在运行/已完成的 Spark 应用程序、监控进度并采取操作的不同方式。
访问日志
日志可以通过 Kubernetes API 和 kubectl
CLI 访问。当 Spark 应用程序运行时,可以使用以下命令从应用程序流式传输日志:
$ kubectl -n=<namespace> logs -f <driver-pod-name>
如果集群中安装了 Kubernetes 仪表板,也可以通过它访问相同的日志。
当存在日志收集系统时,您可以在 Spark Driver Executors
选项卡 UI 中暴露它。例如,
spark.ui.custom.executor.log.url='https://log-server/log?appId=&execId='
您可以向此 URL 模板添加额外的自定义变量,这些变量由现有执行器环境变量的值填充,例如:
spark.executorEnv.SPARK_EXECUTOR_ATTRIBUTE_YOUR_VAR='$(EXISTING_EXECUTOR_ENV_VAR)'
spark.ui.custom.executor.log.url='https://log-server/log?appId=&execId=&your_var='
访问 Driver UI
与任何应用程序关联的 UI 都可以通过 kubectl port-forward
在本地访问。
$ kubectl port-forward <driver-pod-name> 4040:4040
然后,Spark 驱动程序 UI 可以在 http://localhost:4040
访问。
自 Apache Spark 4.0.0 起,Driver UI 提供了一种通过新配置查看驱动程序日志的方式。
spark.driver.log.localDir=/tmp
然后,Spark 驱动程序 UI 可以在 http://localhost:4040/logs/
访问。可选地,日志的布局可以通过以下方式配置。
spark.driver.log.layout="%m%n%ex"
调试
可能会有几种类型的故障。如果 Kubernetes API 服务器拒绝来自 spark-submit 的请求,或者由于其他原因连接被拒绝,提交逻辑应指示遇到的错误。但是,如果在应用程序运行期间出现错误,通常,最佳调查方式可能是通过 Kubernetes CLI。
要获取有关驱动程序 Pod 调度决策的一些基本信息,您可以运行:
$ kubectl describe pod <spark-driver-pod>
如果 Pod 遇到运行时错误,可以使用以下命令进一步探测其状态:
$ kubectl logs <spark-driver-pod>
失败的执行器 Pod 的状态和日志也可以通过类似方式检查。最后,删除驱动程序 Pod 将清理整个 Spark 应用程序,包括所有执行器、相关服务等。驱动程序 Pod 可以被视为 Spark 应用程序的 Kubernetes 表示。
Kubernetes 功能
配置文件
您的 Kubernetes 配置文件通常位于主目录下的 .kube/config
或由 KUBECONFIG
环境变量指定的位置。Spark on Kubernetes 将尝试使用此文件对用于与 Kubernetes 集群交互的 Kubernetes 客户端进行初始自动配置。提供了各种 Spark 配置属性,允许进一步自定义客户端配置,例如使用替代的认证方法。
上下文
Kubernetes 配置文件可以包含多个上下文,允许在不同的集群和/或用户身份之间切换。默认情况下,Spark on Kubernetes 在进行 Kubernetes 客户端的初始自动配置时,将使用您当前的上下文(可以通过运行 kubectl config current-context
进行检查)。
为了使用替代上下文,用户可以通过 Spark 配置属性 spark.kubernetes.context
指定所需的上下文,例如 spark.kubernetes.context=minikube
。
命名空间
Kubernetes 有 命名空间 的概念。命名空间是划分集群资源在多个用户之间(通过资源配额)的方式。Spark on Kubernetes 可以使用命名空间来启动 Spark 应用程序。这可以通过 spark.kubernetes.namespace
配置来实现。
Kubernetes 允许使用 ResourceQuota 在各个命名空间上设置资源、对象数量等的限制。管理员可以将命名空间和 ResourceQuota 结合使用,以控制运行 Spark 应用程序的 Kubernetes 集群中的共享和资源分配。
RBAC
在启用 RBAC 的 Kubernetes 集群中,用户可以配置 Kubernetes RBAC 角色和服务帐户,供 Spark on Kubernetes 的各种组件访问 Kubernetes API 服务器。
Spark 驱动程序 Pod 使用 Kubernetes 服务帐户访问 Kubernetes API 服务器以创建和监视执行器 Pod。驱动程序 Pod 使用的服务帐户必须具有适当的权限,以便驱动程序能够完成其工作。具体来说,至少,服务帐户必须被授予允许驱动程序 Pod 创建 Pod 和服务的 Role
或 ClusterRole
。默认情况下,如果创建 Pod 时未指定服务帐户,则驱动程序 Pod 会自动分配 spark.kubernetes.namespace
指定命名空间中的 default
服务帐户。
根据部署的 Kubernetes 版本和设置,此 default
服务帐户可能具有或不具有允许驱动程序 Pod 在默认 Kubernetes RBAC 策略下创建 Pod 和服务的角色。有时用户可能需要指定一个具有正确角色的自定义服务帐户。Spark on Kubernetes 支持通过配置属性 spark.kubernetes.authenticate.driver.serviceAccountName=<service account name>
为驱动程序 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
for ClusterRoleBinding
)命令。例如,以下命令在 default
命名空间中创建一个 edit
ClusterRole
并将其授予上面创建的 spark
服务帐户:
$ kubectl create clusterrolebinding spark-role --clusterrole=edit --serviceaccount=default:spark --namespace=default
请注意,Role
只能用于授予对单个命名空间内资源(如 Pod)的访问权限,而 ClusterRole
可以用于授予对集群范围资源(如节点)以及所有命名空间中的命名空间资源(如 Pod)的访问权限。对于 Spark on Kubernetes,由于驱动程序始终在同一命名空间中创建执行器 Pod,因此 Role
就足够了,尽管用户也可以使用 ClusterRole
。有关 RBAC 授权以及如何为 Pod 配置 Kubernetes 服务帐户的更多信息,请参阅 使用 RBAC 授权 和 为 Pod 配置服务帐户。
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
属性,通过 --conf
作为提供方式,指定 Pod 终止的宽限期(所有 K8s Pod 的默认值为 30 秒)。
未来工作
Spark on Kubernetes 目前正在开发或计划开发一些功能。这些功能预计最终将集成到 Spark-Kubernetes 集成的未来版本中。
其中一些包括:
- 外部混洗服务
- 作业队列和资源管理
配置
有关 Spark 配置的信息,请参阅配置页面。以下配置特定于 Spark on Kubernetes。
Spark 属性
属性名称 | 默认值 | 含义 | 起始版本 |
---|---|---|---|
spark.kubernetes.context |
(无) |
用户 Kubernetes 配置文件中用于 Kubernetes 客户端库初始自动配置的上下文。未指定时,使用用户当前上下文。注意:许多自动配置的设置可以通过使用其他 Spark 配置属性(例如 spark.kubernetes.namespace )来覆盖。 |
3.0.0 |
spark.kubernetes.driver.master |
https://kubernetes.default.svc |
用于驱动程序请求执行器的内部 Kubernetes master (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 Secret 的逗号分隔列表。 | 2.4.0 |
spark.kubernetes.allocation.batch.size |
10 |
在每轮执行器 Pod 分配中一次性启动的 Pod 数量。 | 2.3.0 |
spark.kubernetes.allocation.batch.delay |
1s |
每次执行器 Pod 分配之间等待的时间。指定小于 1 秒的值可能会导致 Spark 驱动程序上的 CPU 使用率过高。 | 2.3.0 |
spark.kubernetes.jars.avoidDownloadSchemes |
(无) |
方案的逗号分隔列表,对于这些方案,jar 包将不会在分发给执行器之前下载到驱动程序本地磁盘,仅适用于 kubernetes 部署。用于 jar 包较大且执行器数量较多,并发下载导致网络饱和和超时的情况。通配符 '*' 表示不下载任何方案的 jar 包。 | 4.0.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 从驱动程序 Pod 请求执行器时,通过 TLS 连接到 Kubernetes API 服务器的 CA 证书文件的路径。此文件必须位于提交机器的磁盘上,并将上传到驱动程序 Pod。将其指定为路径而非 URI(即不提供方案)。在客户端模式下,改用 spark.kubernetes.authenticate.caCertFile 。 |
2.3.0 |
spark.kubernetes.authenticate.driver.clientKeyFile |
(无) | 用于在驱动程序 Pod 从驱动程序 Pod 请求执行器时,针对 Kubernetes API 服务器进行身份验证的客户端密钥文件的路径。此文件必须位于提交机器的磁盘上,并将作为 Kubernetes Secret 上传到驱动程序 Pod。将其指定为路径而非 URI(即不提供方案)。在客户端模式下,改用 spark.kubernetes.authenticate.clientKeyFile 。 |
2.3.0 |
spark.kubernetes.authenticate.driver.clientCertFile |
(无) | 用于在驱动程序 Pod 从驱动程序 Pod 请求执行器时,针对 Kubernetes API 服务器进行身份验证的客户端证书文件的路径。此文件必须位于提交机器的磁盘上,并将作为 Kubernetes Secret 上传到驱动程序 Pod。将其指定为路径而非 URI(即不提供方案)。在客户端模式下,改用 spark.kubernetes.authenticate.clientCertFile 。 |
2.3.0 |
spark.kubernetes.authenticate.driver.oauthToken |
(无) | 用于在驱动程序 Pod 从驱动程序 Pod 请求执行器时,针对 Kubernetes API 服务器进行身份验证的 OAuth 令牌。请注意,与其他身份验证选项不同,这必须是用于身份验证的令牌的确切字符串值。此令牌值将作为 Kubernetes Secret 上传到驱动程序 Pod。在客户端模式下,改用 spark.kubernetes.authenticate.oauthToken 。 |
2.3.0 |
spark.kubernetes.authenticate.driver.oauthTokenFile |
(无) | 包含在驱动程序 Pod 从驱动程序 Pod 请求执行器时,用于针对 Kubernetes API 服务器进行身份验证的令牌的 OAuth 令牌文件的路径。请注意,与其他身份验证选项不同,此文件必须包含用于身份验证的令牌的确切字符串值。此令牌值将作为 Secret 上传到驱动程序 Pod。在客户端模式下,改用 spark.kubernetes.authenticate.oauthTokenFile 。 |
2.3.0 |
spark.kubernetes.authenticate.driver.mounted.caCertFile |
(无) | 用于在驱动程序 Pod 从驱动程序 Pod 请求执行器时,通过 TLS 连接到 Kubernetes API 服务器的 CA 证书文件的路径。此路径必须可从驱动程序 Pod 访问。将其指定为路径而非 URI(即不提供方案)。在客户端模式下,改用 spark.kubernetes.authenticate.caCertFile 。 |
2.3.0 |
spark.kubernetes.authenticate.driver.mounted.clientKeyFile |
(无) | 用于在驱动程序 Pod 从驱动程序 Pod 请求执行器时,针对 Kubernetes API 服务器进行身份验证的客户端密钥文件的路径。此路径必须可从驱动程序 Pod 访问。将其指定为路径而非 URI(即不提供方案)。在客户端模式下,改用 spark.kubernetes.authenticate.clientKeyFile 。 |
2.3.0 |
spark.kubernetes.authenticate.driver.mounted.clientCertFile |
(无) | 用于在驱动程序 Pod 从驱动程序 Pod 请求执行器时,针对 Kubernetes API 服务器进行身份验证的客户端证书文件的路径。此路径必须可从驱动程序 Pod 访问。将其指定为路径而非 URI(即不提供方案)。在客户端模式下,改用 spark.kubernetes.authenticate.clientCertFile 。 |
2.3.0 |
spark.kubernetes.authenticate.driver.mounted.oauthTokenFile |
(无) | 包含在驱动程序 Pod 从驱动程序 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 |
(无) | 在客户端模式下,用于在请求执行器时通过 TLS 连接到 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.[LabelName] |
(无) | 向驱动程序 Pod 添加由 LabelName 指定的标签。例如,spark.kubernetes.driver.label.something=true 。请注意,Spark 也会向驱动程序 Pod 添加其自己的标签用于簿记目的。 |
2.3.0 |
spark.kubernetes.driver.annotation.[AnnotationName] |
(无) | 向驱动程序 Pod 添加由 AnnotationName 指定的 Kubernetes 注解。例如,spark.kubernetes.driver.annotation.something=true 。 |
2.3.0 |
spark.kubernetes.driver.service.label.[LabelName] |
(无) | 向驱动程序服务添加由 LabelName 指定的 Kubernetes 标签。例如,spark.kubernetes.driver.service.label.something=true 。请注意,Spark 也会向驱动程序服务添加其自己的标签用于簿记目的。 |
3.4.0 |
spark.kubernetes.driver.service.annotation.[AnnotationName] |
(无) | 向驱动程序服务添加由 AnnotationName 指定的 Kubernetes 注解。例如,spark.kubernetes.driver.service.annotation.something=true 。 |
3.0.0 |
spark.kubernetes.executor.label.[LabelName] |
(无) | 向执行器 Pod 添加由 LabelName 指定的标签。例如,spark.kubernetes.executor.label.something=true 。请注意,Spark 也会向执行器 Pod 添加其自己的标签用于簿记目的。 |
2.3.0 |
spark.kubernetes.executor.annotation.[AnnotationName] |
(无) | 向执行器 Pod 添加由 AnnotationName 指定的 Kubernetes 注解。例如,spark.kubernetes.executor.annotation.something=true 。 |
2.3.0 |
spark.kubernetes.driver.pod.name |
(无) | 驱动程序 Pod 的名称。在集群模式下,如果未设置此项,驱动程序 Pod 名称将设置为 "spark.app.name" 后缀当前时间戳以避免名称冲突。在客户端模式下,如果您的应用程序在 Pod 内部运行,强烈建议将其设置为驱动程序运行的 Pod 的名称。在客户端模式下设置此值允许驱动程序成为其执行器 Pod 的所有者,进而允许执行器 Pod 由集群进行垃圾回收。 | 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 作业时具有“即发即忘”的行为。 | 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 不同:如果设置,它仅用于指定执行器 Pod 的 CPU 请求并优先于 spark.executor.cores 。任务并行度,例如,执行器可以并发运行的任务数量不受此影响。 |
2.4.0 |
spark.kubernetes.executor.limit.cores |
(无) | 为 Spark 应用程序启动的每个执行器 Pod 指定一个硬性 CPU 限制。 | 2.3.0 |
spark.kubernetes.node.selector.[labelKey] |
(无) | 向驱动程序 Pod 和执行器 Pod 的节点选择器添加键为 labelKey 、值为配置值的标签。例如,将 spark.kubernetes.node.selector.identifier 设置为 myIdentifier 将导致驱动程序 Pod 和执行器拥有一个键为 identifier 、值为 myIdentifier 的节点选择器。可以通过设置多个具有此前缀的配置来添加多个节点选择器键。 |
2.3.0 |
spark.kubernetes.driver.node.selector.[labelKey] |
(无) | 向驱动程序 Pod 的驱动程序节点选择器添加键为 labelKey 、值为配置值的标签。例如,将 spark.kubernetes.driver.node.selector.identifier 设置为 myIdentifier 将导致驱动程序 Pod 拥有一个键为 identifier 、值为 myIdentifier 的驱动程序节点选择器。可以通过设置多个具有此前缀的配置来添加多个驱动程序节点选择器键。 |
3.3.0 |
spark.kubernetes.executor.node.selector.[labelKey] |
(无) | 向执行器 Pod 的执行器节点选择器添加键为 labelKey 、值为配置值的标签。例如,将 spark.kubernetes.executor.node.selector.identifier 设置为 myIdentifier 将导致执行器拥有一个键为 identifier 、值为 myIdentifier 的执行器节点选择器。可以通过设置多个具有此前缀的配置来添加多个执行器节点选择器键。 |
3.3.0 |
spark.kubernetes.driverEnv.[EnvironmentVariableName] |
(无) | 向驱动程序进程添加由 EnvironmentVariableName 指定的环境变量。用户可以指定多个此类变量来设置多个环境变量。 |
2.3.0 |
spark.kubernetes.driver.secrets.[SecretName] |
(无) | 将名为 SecretName 的 Kubernetes Secret 添加到驱动程序 Pod 中指定路径的值。例如,spark.kubernetes.driver.secrets.spark-secret=/etc/secrets 。 |
2.3.0 |
spark.kubernetes.executor.secrets.[SecretName] |
(无) | 将名为 SecretName 的 Kubernetes Secret 添加到执行器 Pod 中指定路径的值。例如,spark.kubernetes.executor.secrets.spark-secret=/etc/secrets 。 |
2.3.0 |
spark.kubernetes.driver.secretKeyRef.[EnvName] |
(无) | 作为环境变量添加到驱动程序容器中,名称为 EnvName(区分大小写),其值是引用 Kubernetes Secret 数据中键为 key 的值。例如,spark.kubernetes.driver.secretKeyRef.ENV_VAR=spark-secret:key 。 |
2.4.0 |
spark.kubernetes.executor.secretKeyRef.[EnvName] |
(无) | 作为环境变量添加到执行器容器中,名称为 EnvName(区分大小写),其值是引用 Kubernetes Secret 数据中键为 key 的值。例如,spark.kubernetes.executor.secrets.ENV_VAR=spark-secret:key 。 |
2.4.0 |
spark.kubernetes.driver.volumes.[VolumeType].[VolumeName].mount.path |
(无) | 将名为 VolumeName 、类型为 VolumeType 的 Kubernetes 卷 添加到驱动程序 Pod 中指定路径的值。例如,spark.kubernetes.driver.volumes.persistentVolumeClaim.checkpointpvc.mount.path=/checkpoint 。 |
2.4.0 |
spark.kubernetes.driver.volumes.[VolumeType].[VolumeName].mount.subPath |
(无) | 指定要从卷挂载到驱动程序 Pod 的 子路径。spark.kubernetes.driver.volumes.persistentVolumeClaim.checkpointpvc.mount.subPath=checkpoint 。 |
3.0.0 |
spark.kubernetes.driver.volumes.[VolumeType].[VolumeName].mount.readOnly |
(无) | 指定挂载的卷是否为只读。例如,spark.kubernetes.driver.volumes.persistentVolumeClaim.checkpointpvc.mount.readOnly=false 。 |
2.4.0 |
spark.kubernetes.driver.volumes.[VolumeType].[VolumeName].options.[OptionName] |
(无) | 配置传递给 Kubernetes 的 Kubernetes 卷 选项,其中 OptionName 作为键并具有指定的值,必须符合 Kubernetes 选项格式。例如,spark.kubernetes.driver.volumes.persistentVolumeClaim.checkpointpvc.options.claimName=spark-pvc-claim 。 |
2.4.0 |
spark.kubernetes.driver.volumes.[VolumeType].[VolumeName].label.[LabelName] |
(无) | 配置传递给 Kubernetes 的 Kubernetes 卷 标签,其中 LabelName 作为键并具有指定的值,必须符合 Kubernetes 标签格式。例如,spark.kubernetes.driver.volumes.persistentVolumeClaim.checkpointpvc.label.foo=bar 。 |
4.0.0 |
spark.kubernetes.driver.volumes.[VolumeType].[VolumeName].annotation.[AnnotationName] |
(无) | 配置传递给 Kubernetes 的 Kubernetes 卷 注解,其中 AnnotationName 作为键并具有指定的值,必须符合 Kubernetes 注解格式。例如,spark.kubernetes.driver.volumes.persistentVolumeClaim.checkpointpvc.annotation.foo=bar 。 |
4.0.0 |
spark.kubernetes.executor.volumes.[VolumeType].[VolumeName].mount.path |
(无) | 将名为 VolumeName 、类型为 VolumeType 的 Kubernetes 卷 添加到执行器 Pod 中指定路径的值。例如,spark.kubernetes.executor.volumes.persistentVolumeClaim.checkpointpvc.mount.path=/checkpoint 。 |
2.4.0 |
spark.kubernetes.executor.volumes.[VolumeType].[VolumeName].mount.subPath |
(无) | 指定要从卷挂载到执行器 Pod 的 子路径。spark.kubernetes.executor.volumes.persistentVolumeClaim.checkpointpvc.mount.subPath=checkpoint 。 |
3.0.0 |
spark.kubernetes.executor.volumes.[VolumeType].[VolumeName].mount.readOnly |
false | 指定挂载的卷是否为只读。例如,spark.kubernetes.executor.volumes.persistentVolumeClaim.checkpointpvc.mount.readOnly=false 。 |
2.4.0 |
spark.kubernetes.executor.volumes.[VolumeType].[VolumeName].options.[OptionName] |
(无) | 配置传递给 Kubernetes 的 Kubernetes 卷 选项,其中 OptionName 作为键,具有指定的值。例如:spark.kubernetes.executor.volumes.persistentVolumeClaim.checkpointpvc.options.claimName=spark-pvc-claim 。 |
2.4.0 |
spark.kubernetes.executor.volumes.[VolumeType].[VolumeName].label.[LabelName] |
(无) | 配置传递给 Kubernetes 的 Kubernetes 卷 标签,其中 LabelName 作为键,具有指定的值,必须符合 Kubernetes 标签格式。例如:spark.kubernetes.executor.volumes.persistentVolumeClaim.checkpointpvc.label.foo=bar 。 |
4.0.0 |
spark.kubernetes.executor.volumes.[VolumeType].[VolumeName].annotation.[AnnotationName] |
(无) | 配置传递给 Kubernetes 的 Kubernetes 卷 注解,其中 AnnotationName 作为键,具有指定的值,必须符合 Kubernetes 注解格式。例如:spark.kubernetes.executor.volumes.persistentVolumeClaim.checkpointpvc.annotation.foo=bar 。 |
4.0.0 |
spark.kubernetes.local.dirs.tmpfs |
false |
配置用于支持 Spark 驱动程序和执行器 Pod 内 SPARK_LOCAL_DIRS 的 emptyDir 卷,以使用 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 的名称,该 ConfigMap 将被挂载到驱动程序和执行器上,用于 Kerberos 交互。定义的 KDC 需要在容器内部可见。ConfigMap 还必须与驱动程序和执行器 Pod 位于相同的命名空间中。 | 3.0.0 |
spark.kubernetes.hadoop.configMapName |
(无) |
指定包含 HADOOP_CONF_DIR 文件的 ConfigMap 的名称,该 ConfigMap 将被挂载到驱动程序和执行器上,用于自定义 Hadoop 配置。 | 3.0.0 |
spark.kubernetes.kerberos.tokenSecret.name |
(无) |
指定存储现有委派令牌的 Secret 名称。这消除了作业用户为启动作业提供任何 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 | 指定执行器 Pod 在失败或正常终止时是否应被删除。 | 3.0.0 |
spark.kubernetes.executor.checkAllContainers |
true |
指定在确定 Pod 状态时,执行器 Pod 应检查所有容器(包括边车容器)还是仅检查执行器容器。 | 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 |
5秒 |
在强制终止之前,等待执行器优雅关闭的时间。 | 3.0.0 |
spark.kubernetes.file.upload.path |
(无) | 在集群模式下,用于在 Spark 提交端存储文件的路径。例如:spark.kubernetes.file.upload.path=s3a://<s3桶>/路径 文件应指定为 file://路径/到/文件 或绝对路径。 |
3.0.0 |
spark.kubernetes.executor.decommissionLabel |
(无) | 应用于正在退出或正在退役的 Pod 的标签。旨在与 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 |
(无) | 为驱动程序和执行器 Pod 指定调度器名称。如果设置了 spark.kubernetes.driver.scheduler.name 或 spark.kubernetes.executor.scheduler.name ,则会覆盖此设置。 |
3.3.0 |
spark.kubernetes.configMap.maxSize |
1048576 |
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 成为按需持久卷声明的所有者,而不是执行器 Pod。 | 3.2.0 |
spark.kubernetes.driver.reusePersistentVolumeClaim |
true |
如果为 true,驱动程序 Pod 会尝试重用已删除执行器 Pod 的驱动程序拥有的按需持久卷声明(如果存在)。这有助于通过跳过持久卷创建来减少执行器 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 |
用于 Pod 的分配器。可能的值是 direct (默认)和 statefulset ,或者是实现 AbstractPodsAllocator 的类的完整类名。未来版本可能会添加 Job 或 replicaset。这是一个开发者 API,可能随时更改或删除。 |
3.3.0 |
spark.kubernetes.allocation.executor.timeout |
600秒 |
新创建的执行器 Pod 请求(尚未达到 Pod 待处理状态)在被视为超时并将被删除之前等待的时间。 | 3.1.0 |
spark.kubernetes.allocation.driver.readinessTimeout |
1s |
在创建执行器 Pod 之前等待驱动程序 Pod 准备就绪的时间。此等待仅发生在应用程序启动时。如果发生超时,执行器 Pod 仍将创建。 | 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 |
0秒 |
执行器滚动操作之间的间隔。默认为 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 将仅在驱动程序 Pod 上,并且仅在指定了 Spark 配置的情况下,用 Spark 配置的值覆盖 serviceAccount 。执行器 Pod 将不受影响。 |
serviceAccountName | spark.kubernetes.authenticate.driver.serviceAccountName 的值 |
Spark 将仅在驱动程序 Pod 上,并且仅在指定了 Spark 配置的情况下,用 Spark 配置的值覆盖 serviceAccountName 。执行器 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 文档。
只要 Kubernetes 资源类型遵循 Kubernetes 设备插件格式 vendor-domain/resourcetype
,Spark 就会自动处理将 Spark 配置 spark.{driver/executor}.resource.{resourceType}
转换为 Kubernetes 配置。用户必须使用 spark.{driver/executor}.resource.{resourceType}.vendor
配置指定供应商。如果您使用 Pod 模板,则无需明确添加任何内容。作为参考和示例,您可以查看 Kubernetes 文档中关于调度 GPU 的部分。Spark 仅支持设置资源限制。
Kubernetes 不会告诉 Spark 分配给每个容器的资源的地址。因此,用户必须指定一个发现脚本,该脚本在执行器启动时运行,以发现该执行器可用的资源。您可以在 examples/src/main/scripts/getGpusResources.sh
中找到示例脚本。该脚本必须设置执行权限,并且用户应设置权限以防止恶意用户修改它。该脚本应向 STDOUT 写入 ResourceInformation 类格式的 JSON 字符串。该字符串包含资源名称和该执行器可用的资源地址数组。
资源级别调度概览
Spark on Kubernetes 支持多种资源级别调度功能。
优先级调度
Kubernetes 默认支持 Pod 优先级。
Spark on Kubernetes 允许通过Pod 模板定义作业的优先级。用户可以在驱动程序或执行器 Pod 模板的 spec
部分指定 priorityClassName
。下面是一个示例,展示了如何指定它
apiVersion: v1
Kind: Pod
metadata:
labels:
template-label-key: driver-template-label-value
spec:
# Specify the priority in here
priorityClassName: system-node-critical
containers:
- name: test-driver-container
image: will-be-overwritten
Spark on Kubernetes 的自定义 Kubernetes 调度器
Spark 允许用户指定自定义 Kubernetes 调度器。
-
指定调度器名称。
用户可以使用
spark.kubernetes.scheduler.name
或spark.kubernetes.{driver/executor}.scheduler.name
配置指定自定义调度器。 -
指定调度器相关配置。
要配置自定义调度器,用户可以使用Pod 模板、添加标签 (
spark.kubernetes.{driver,executor}.label.*
)、注解 (spark.kubernetes.{driver/executor}.annotation.*
) 或调度器特定配置(例如spark.kubernetes.scheduler.volcano.podGroupTemplateFile
)。 -
指定调度器功能步骤。
用户还可以考虑使用
spark.kubernetes.{driver/executor}.pod.featureSteps
来支持更复杂的需求,包括但不限于- 为驱动程序/执行器调度创建额外的 Kubernetes 自定义资源。
- 根据配置或现有 Pod 信息动态设置调度器提示。
使用 Volcano 作为 Spark on Kubernetes 的自定义调度器
先决条件
-
自 Spark v3.3.0 和 Volcano v1.7.0 起,支持使用 Volcano 作为自定义调度器的 Spark on Kubernetes。以下是安装 Volcano 1.7.0 的示例
kubectl apply -f https://raw.githubusercontent.com/volcano-sh/volcano/v1.7.0/installer/volcano-development.yaml
构建
要创建支持 Volcano 的 Spark 分发版,例如 Spark 下载页面上分发的那些,请参阅 “构建 Spark” 中的更多信息
./dev/make-distribution.sh --name custom-spark --pip --r --tgz -Psparkr -Phive -Phive-thriftserver -Pkubernetes -Pvolcano
用法
Spark on Kubernetes 允许使用 Volcano 作为自定义调度器。用户可以使用 Volcano 支持更高级的资源调度:队列调度、资源预留、优先级调度等。
要使用 Volcano 作为自定义调度器,用户需要指定以下配置选项
# Specify volcano scheduler and PodGroup template
--conf spark.kubernetes.scheduler.name=volcano
--conf spark.kubernetes.scheduler.volcano.podGroupTemplateFile=/path/to/podgroup-template.yaml
# Specify driver/executor 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
Volcano 功能步骤
Volcano 功能步骤帮助用户创建 Volcano PodGroup 并设置驱动程序/执行器 Pod 注解以链接到此 PodGroup。
请注意,目前 Volcano 功能步骤中仅支持驱动程序/作业级别的 PodGroup。
Volcano PodGroup 模板
Volcano 使用 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:
# Specify minMember to 1 to make a driver pod
minMember: 1
# Specify minResources to support resource reservation (the driver pod resource and executors pod resource should be considered)
# It is useful for ensource the available resources meet the minimum requirements of the Spark job and avoiding the
# situation where drivers are scheduled, and then they are unable to schedule sufficient executors to progress.
minResources:
cpu: "2"
memory: "3Gi"
# Specify the priority, help users to specify job priority in the queue during scheduling.
priorityClassName: system-node-critical
# Specify the queue, indicates the resource queue which the job should be submitted to
queue: default
使用 Apache YuniKorn 作为 Spark on Kubernetes 的自定义调度器
Apache YuniKorn 是一个 Kubernetes 资源调度器,提供高级批处理调度功能,例如作业排队、资源公平性、最小/最大队列容量和灵活的作业排序策略。有关可用的 Apache YuniKorn 功能,请参阅核心功能。
先决条件
安装 Apache YuniKorn
helm repo add yunikorn https://apache.github.io/yunikorn-release
helm repo update
helm install yunikorn yunikorn/yunikorn --namespace yunikorn --version 1.6.3 --create-namespace --set embedAdmissionController=false
以上步骤将在现有 Kubernetes 集群上安装 YuniKorn v1.6.3。
入门
使用以下额外选项提交 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 上支持阶段级别调度
- 当禁用动态分配时:它允许用户在阶段级别指定不同的任务资源需求,并将使用启动时请求的相同执行器。
- 当启用动态分配时:它允许用户在阶段级别指定任务和执行器资源需求,并将请求额外的执行器。这还要求启用
spark.dynamicAllocation.shuffleTracking.enabled
,因为 Kubernetes 目前不支持外部 shuffle 服务。从 Kubernetes 请求不同配置文件容器的顺序无法保证。请注意,由于 Kubernetes 上的动态分配需要 shuffle 跟踪功能,这意味着来自使用不同 ResourceProfile 的前一阶段的执行器可能不会因其上存在 shuffle 数据而空闲超时。这可能导致使用更多的集群资源,在最坏的情况下,如果 Kubernetes 集群上没有剩余资源,Spark 可能会挂起。您可以考虑查看配置spark.dynamicAllocation.shuffleTracking.timeout
以设置超时,但这可能导致如果确实需要 shuffle 数据,则必须重新计算数据。请注意,基本默认配置文件和自定义 ResourceProfiles 之间处理 Pod 模板资源的方式有所不同。Pod 模板文件中指定的任何资源将仅与基本默认配置文件一起使用。如果您创建自定义 ResourceProfiles,请确保包含所有必要的资源,因为模板文件中的资源不会传播到自定义 ResourceProfiles。