在 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 模板特性,将包含 runAsUser
的 安全上下文添加到 Spark 提交的 pod。这可以用来覆盖镜像本身的 USER
指令。请记住,这需要用户的合作,因此可能不适用于共享环境。集群管理员应使用 Pod 安全策略,如果他们希望限制 pod 可以运行的用户。
卷挂载
如本文档稍后在使用 Kubernetes 卷下所述,K8S 上的 Spark 提供了配置选项,允许将某些卷类型挂载到 driver 和 executor pod 中。特别是,它允许 hostPath
卷,如 Kubernetes 文档中所述,它具有已知的安全漏洞。
集群管理员应使用 Pod 安全策略来限制挂载 hostPath
卷的能力,以适应其环境。
前提条件
- 一个运行中的 Kubernetes 集群,版本 >= 1.24,并使用 kubectl配置了对其的访问权限。如果您还没有一个可用的 Kubernetes 集群,您可以使用 minikube 在您的本地机器上设置一个测试集群。
- 我们建议使用最新版本的 minikube 并启用 DNS 插件。
- 请注意,默认的 minikube 配置不足以运行 Spark 应用程序。我们建议使用 3 个 CPU 和 4g 内存,以便能够启动一个带有单个 executor 的简单 Spark 应用程序。
- 检查您 Spark 环境的 kubernetes-client 库版本,以及它与您的 Kubernetes 集群版本的兼容性。
- 您必须具有适当的权限才能在您的集群中列出、创建、编辑和删除 pod。您可以通过运行
kubectl auth can-i <list|create|edit|delete> pods
来验证您是否可以列出这些资源。- driver pod 使用的服务帐户凭据必须被允许创建 pod、service 和 configmap。
- 您必须在您的集群中配置 Kubernetes DNS。
工作原理
spark-submit
可以直接用于将 Spark 应用程序提交到 Kubernetes 集群。提交机制如下:
- Spark 创建一个在 Kubernetes pod 中运行的 Spark driver。
- driver 创建也在 Kubernetes pod 中运行的 executor,并连接到它们,然后执行应用程序代码。
- 当应用程序完成时,executor pod 终止并被清理,但 driver pod 会持久化日志,并在 Kubernetes API 中保持“已完成”状态,直到它最终被垃圾回收或手动清理。
请注意,在完成状态下,driver pod 不使用任何计算或内存资源。
driver 和 executor pod 的调度由 Kubernetes 处理。与 Kubernetes API 的通信通过 fabric8 完成。可以通过使用节点选择器的配置属性在可用节点的子集上调度 driver 和 executor pod。在未来的版本中,可以使用更高级的调度提示,例如 节点/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 <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 必须是一个 URL,其格式为 k8s://<api_server_host>:<k8s-apiserver-port>
,可以通过以下两种方式指定:通过向 spark-submit
传递 --master
命令行参数,或者在应用程序的配置中设置 spark.master
。 端口必须始终指定,即使是 HTTPS 端口 443。 使用 k8s://
作为 master 字符串的前缀将导致 Spark 应用程序在 Kubernetes 集群上启动,并且 API 服务器将在 api_server_url
处进行联系。 如果 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 资源,例如 driver 和 executor。 因此,应用程序名称必须由小写字母数字字符、-
和 .
组成,并且必须以字母数字字符开头和结尾。
如果您已经设置了 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 集群与 spark-submit
结合使用。 此外,还可以使用身份验证代理 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 应用程序。 当您的应用程序在客户端模式下运行时,driver 可以在 pod 内部或物理主机上运行。 在客户端模式下运行应用程序时,建议考虑以下因素:
客户端模式网络
Spark executors 必须能够通过可从 Spark executors 路由的主机名和端口连接到 Spark driver。 Spark 在客户端模式下工作所需的特定网络配置将因设置而异。 如果您在 Kubernetes pod 中运行您的 driver,则可以使用 headless service 允许您的 driver pod 通过稳定的主机名从 executors 路由。 部署您的 headless service 时,请确保该服务的标签选择器仅匹配 driver pod,而不匹配其他 pod; 建议为您的 driver pod 分配一个足够唯一的标签,并在 headless service 的标签选择器中使用该标签。 通过 spark.driver.host
指定 driver 的主机名,并通过 spark.driver.port
指定 spark driver 的端口。
客户端模式 Executor Pod 垃圾回收
如果您在 pod 中运行您的 Spark driver,强烈建议将 spark.kubernetes.driver.pod.name
设置为该 pod 的名称。 设置此属性后,Spark 调度程序将使用 OwnerReference 部署 executor pods,这将确保一旦从集群中删除 driver pod,所有应用程序的 executor pods 也将被删除。 Driver 将在 spark.kubernetes.namespace
指定的命名空间中查找具有给定名称的 pod,并且指向该 pod 的 OwnerReference 将被添加到每个 executor pod 的 OwnerReferences 列表中。 请注意避免将 OwnerReference 设置为实际上不是该 driver pod 的 pod,否则,当错误的 pod 被删除时,executors 可能会过早终止。
如果您的应用程序未在 pod 中运行,或者如果当您的应用程序实际在 pod 中运行时未设置 spark.kubernetes.driver.pod.name
,请记住,当应用程序退出时,executor pods 可能无法从集群中正确删除。 Spark 调度程序尝试删除这些 pod,但如果由于任何原因导致对 API 服务器的网络请求失败,这些 pod 将保留在集群中。 当 executor 无法访问 driver 时,executor 进程应该退出,因此在您的应用程序退出后,executor pods 不应消耗集群中的计算资源(cpu 和内存)。
您可以使用 spark.kubernetes.executor.podNamePrefix
来完全控制 executor pod 的名称。 设置此属性后,强烈建议使其在同一命名空间中的所有作业中都是唯一的。
身份验证参数
在客户端模式下,对 Kubernetes 身份验证参数使用确切的前缀 spark.kubernetes.authenticate
。
IPv4 和 IPv6
从 3.4.0 开始,Spark 通过 IPv4/IPv6 双栈网络 功能额外支持仅 IPv6 的环境,该功能允许为 Pod 和 Service 分配 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 引用它们和/或在您的 Dockerfiles 中设置 SPARK_EXTRA_CLASSPATH
环境变量,将这些依赖项添加到 classpath 中。 在 spark-submit
中引用自定义构建的 Docker 镜像中的依赖项时,也需要 local://
方案。 我们支持来自提交客户端的本地文件系统的依赖项,使用 file://
方案或不使用方案(使用完整路径),其中目标应该是 Hadoop 兼容的文件系统。 使用 S3 的典型示例是通过传递以下选项:
...
--packages org.apache.hadoop:hadoop-aws:3.2.2
--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,然后在启动 driver 时,它将被下载到 driver pod 并添加到其 classpath 中。 Spark 将在上载路径下生成一个具有随机名称的子目录,以避免与并行运行的 spark 应用程序发生冲突。 用户可以根据自己的需要管理创建的子目录。
客户端方案支持应用程序 jar 以及由属性 spark.jars
,spark.files
和 spark.archives
指定的依赖项。
重要提示:所有客户端依赖项都将以上载到给定的路径,并且具有扁平的目录结构,因此文件名必须是唯一的,否则文件将被覆盖。 还要确保在派生的 k8s 镜像中,默认的 ivy 目录具有所需的访问权限,或者如上所述修改设置。 如果您在集群模式下使用 --packages
,则后者也很重要。
Secret 管理
Kubernetes Secrets 可用于为 Spark 应用程序提供凭据,以访问受保护的服务。 要将用户指定的 secret 挂载到 driver 容器中,用户可以使用 spark.kubernetes.driver.secrets.[SecretName]=<mount path>
形式的配置属性。 类似地,可以使用 spark.kubernetes.executor.secrets.[SecretName]=<mount path>
形式的配置属性将用户指定的 secret 挂载到 executor 容器中。 请注意,假定要挂载的 secret 与 driver 和 executor pod 位于同一命名空间中。 例如,要将名为 spark-secret
的 secret 挂载到 driver 和 executor 容器中的 /etc/secrets
路径上,请将以下选项添加到 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 配置不支持的 driver 或 executor 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
为了允许 driver pod 访问 executor pod 模板文件,该文件将在创建时自动挂载到 driver 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
来指示哪个容器应作为 Driver 或 Executor 的基础。如果未指定,或者容器名称无效,Spark 将假定列表中的第一个容器将是 Driver 或 Executor 容器。
使用 Kubernetes 卷
用户可以将以下类型的 Kubernetes 卷挂载到 Driver 和 Executor Pod 中
- hostPath:将主机节点的 FileSystem 中的文件或目录挂载到 Pod 中。
- emptyDir:一个初始为空的卷,当 Pod 被分配到节点时创建。
- nfs:将现有的 NFS(网络文件系统)挂载到 Pod 中。
- persistentVolumeClaim:将
PersistentVolume
挂载到 Pod 中。
注意: 有关卷挂载相关的安全问题,请参阅本文档的 安全 部分。
要将上述任何类型的卷挂载到 Driver 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
用于将卷挂载到 Executor Pod 中的配置属性使用前缀 spark.kubernetes.executor.
而不是 spark.kubernetes.driver.
。
例如,您可以使用 OnDemand
作为声明名称,以及 storageClass
和 sizeLimit
选项,为每个 Executor 挂载一个动态创建的 Persistent Volume Claim,如下所示。这在 动态分配 的情况下非常有用。
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 的 executor pod 分配
由于磁盘是重要的资源类型之一,Spark Driver 通过一组配置提供了细粒度的控制。 例如,默认情况下,按需 PVC 由 Executor 拥有,并且 PVC 的生命周期与其所有者 Executor 紧密结合。 但是,按需 PVC 可以由 Driver 拥有,并在 Spark 作业的生命周期内由另一个 Executor 重用,使用以下选项。 这减少了 PVC 创建和删除的开销。
spark.kubernetes.driver.ownPersistentVolumeClaim=true
spark.kubernetes.driver.reusePersistentVolumeClaim=true
此外,从 Spark 3.4 开始,Spark Driver 能够进行面向 PVC 的 Executor 分配,这意味着 Spark 会统计作业可以拥有的已创建 PVC 的总数,如果 Driver 拥有最大数量的 PVC,则会暂停新的 Executor 创建。 这有助于将现有 PVC 从一个 Executor 转移到另一个 Executor。
spark.kubernetes.driver.waitToReusePersistentVolumeClaim=true
本地存储
Spark 支持在 Shuffle 和其他操作期间使用卷来溢出数据。 要将卷用作本地存储,卷的名称应以 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
具体来说,如果作业需要在 Executor 中进行大型 Shuffle 和排序操作,则可以使用 Persistent Volume Claim。
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
插件启用 Shuffle 数据恢复功能,我们需要具备以下条件。 您可能还希望额外启用 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 使用临时暂存空间将数据溢出到磁盘,以进行 Shuffle 和其他操作。 当使用 Kubernetes 作为资源管理器时,将使用 emptyDir 卷创建 Pod,并为 spark.local.dir
或环境变量 SPARK_LOCAL_DIRS
中列出的每个目录挂载该卷。 如果未明确指定任何目录,则会创建一个默认目录并进行相应的配置。
emptyDir
卷使用 Kubernetes 的临时存储功能,并且不会在 Pod 的生命周期之外保留。
使用 RAM 作为本地存储
emptyDir
卷默认使用节点的后备存储作为临时存储,此行为可能不适用于某些计算环境。 例如,如果您有无盘节点,并通过网络挂载远程存储,则让大量 Executor 对此远程存储执行 IO 可能会降低性能。
在这种情况下,可能需要将配置中的 spark.kubernetes.local.dirs.tmpfs=true
设置为 tmpfs
,这将导致 emptyDir
卷配置为 tmpfs
,即 RAM 支持的卷。 这样配置后,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.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='
访问 Driver UI
可以使用 kubectl port-forward
在本地访问与任何应用程序关联的 UI。
$ kubectl port-forward <driver-pod-name> 4040:4040
然后,可以在 http://localhost:4040
上访问 Spark Driver UI。
调试
可能存在几种类型的故障。 如果 Kubernetes API 服务器拒绝 spark-submit 发出的请求,或者由于其他原因导致连接被拒绝,则提交逻辑应指示遇到的错误。 但是,如果应用程序运行期间出现错误,通常,最好的调查方法是通过 Kubernetes CLI。
要获取有关围绕 Driver Pod 做出的调度决策的一些基本信息,您可以运行
$ kubectl describe pod <spark-driver-pod>
如果 Pod 遇到运行时错误,可以使用以下命令进一步探测状态
$ kubectl logs <spark-driver-pod>
可以以类似的方式检查失败的 Executor Pod 的状态和日志。 最后,删除 Driver Pod 将清理整个 Spark 应用程序,包括所有 Executor、关联的服务等。 Driver Pod 可以被认为是 Spark 应用程序的 Kubernetes 表示形式。
Kubernetes 特性
配置文件
您的 Kubernetes 配置文件通常位于您主目录中的 .kube/config
下,或位于 KUBECONFIG
环境变量指定的位置。 Kubernetes 上的 Spark 将尝试使用此文件来自动配置用于与 Kubernetes 集群交互的 Kubernetes 客户端。 提供了各种 Spark 配置属性,允许进一步自定义客户端配置,例如,使用替代身份验证方法。
上下文
Kubernetes 配置文件可以包含多个上下文,允许在不同的集群和/或用户身份之间切换。 默认情况下,在自动配置 Kubernetes 客户端时,Kubernetes 上的 Spark 将使用您当前的上下文(可以通过运行 kubectl config current-context
进行检查)。
为了使用替代上下文,用户可以通过 Spark 配置属性 spark.kubernetes.context
指定所需的上下文,例如 spark.kubernetes.context=minikube
。
命名空间
Kubernetes 具有 命名空间 的概念。 命名空间是将集群资源在多个用户之间分配(通过资源配额)的方式。 Kubernetes 上的 Spark 可以使用命名空间来启动 Spark 应用程序。 这可以通过 spark.kubernetes.namespace
配置来实现。
Kubernetes 允许使用 ResourceQuota 来设置对单个命名空间中的资源、对象数量等的限制。 管理员可以将命名空间和 ResourceQuota 结合使用,以控制在运行 Spark 应用程序的 Kubernetes 集群中的共享和资源分配。
RBAC
在启用了 RBAC 的 Kubernetes 集群中,用户可以配置 Kubernetes RBAC 角色和服务帐户,这些角色和服务帐户由 Kubernetes 组件上的各种 Spark 使用,以访问 Kubernetes API 服务器。
Spark Driver Pod 使用 Kubernetes 服务帐户来访问 Kubernetes API 服务器,以创建和监视 Executor Pod。 Driver Pod 使用的服务帐户必须具有适当的权限,以便 Driver 能够完成其工作。 具体来说,至少,必须授予该服务帐户一个 Role
或 ClusterRole
,该角色允许 Driver Pod 创建 Pod 和服务。 默认情况下,如果创建 Pod 时未指定服务帐户,则 Driver Pod 会自动分配由 spark.kubernetes.namespace
指定的命名空间中的 default
服务帐户。
根据 Kubernetes 的版本和设置,此 default
服务帐户可能具有或可能不具有允许 Driver Pod 在默认 Kubernetes RBAC 策略下创建 Pod 和服务的角色。 有时,用户可能需要指定一个已授予正确角色的自定义服务帐户。 Kubernetes 上的 Spark 支持通过配置属性 spark.kubernetes.authenticate.driver.serviceAccountName=<service account name>
指定 Driver Pod 使用的自定义服务帐户。 例如,要使 Driver 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
只能用于授予对单个命名空间内资源(如 pod)的访问权限,而 ClusterRole
可以用于授予对集群范围资源(如节点)以及所有命名空间中的命名空间资源(如 pod)的访问权限。对于 Kubernetes 上的 Spark,由于驱动程序始终在同一命名空间中创建 executor 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
这两个操作都支持 glob 模式。例如,用户可以运行
$ 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 集成。
其中一些包括
- 外部 Shuffle 服务
- 作业队列和资源管理
配置
有关 Spark 配置的信息,请参阅配置页面。以下配置特定于 Kubernetes 上的 Spark。
Spark 属性
属性名称 | 默认值 | 含义 | 起始版本 |
---|---|---|---|
spark.kubernetes.context |
(无) |
用于 Kubernetes 客户端库的初始自动配置的用户 Kubernetes 配置文件中的上下文。如果未指定,则使用用户当前上下文。注意:许多自动配置的设置可以通过使用其他 Spark 配置属性来覆盖,例如 spark.kubernetes.namespace 。 |
3.0.0 |
spark.kubernetes.driver.master |
https://kubernetes.default.svc |
用于驱动程序请求 executor 的内部 Kubernetes master(API 服务器)地址,或者用于 driver-pod-only 模式的 'local[*]'。 | 3.0.0 |
spark.kubernetes.namespace |
default |
将用于运行驱动程序和 executor 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 的值) |
用于 executor 的自定义容器镜像。 | 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 |
5 |
在每轮 executor pod 分配中一次启动的 pod 数量。 | 2.3.0 |
spark.kubernetes.allocation.batch.delay |
1s |
在每轮 executor 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 请求 executor 时通过 TLS 从驱动程序 pod 连接到 Kubernetes API 服务器的 CA 证书文件的路径。此文件必须位于提交机器的磁盘上,并且将上传到驱动程序 pod。将其指定为路径而不是 URI(即不要提供方案)。在客户端模式下,请改用 spark.kubernetes.authenticate.caCertFile 。 |
2.3.0 |
spark.kubernetes.authenticate.driver.clientKeyFile |
(无) | 用于从驱动程序 pod 请求 executor 时针对 Kubernetes API 服务器进行身份验证的客户端密钥文件的路径。此文件必须位于提交机器的磁盘上,并且将作为 Kubernetes secret 上传到驱动程序 pod。将其指定为路径而不是 URI(即不要提供方案)。在客户端模式下,请改用 spark.kubernetes.authenticate.clientKeyFile 。 |
2.3.0 |
spark.kubernetes.authenticate.driver.clientCertFile |
(无) | 用于从驱动程序 pod 请求 executor 时针对 Kubernetes API 服务器进行身份验证的客户端证书文件的路径。此文件必须位于提交机器的磁盘上,并且将作为 Kubernetes secret 上传到驱动程序 pod。将其指定为路径而不是 URI(即不要提供方案)。在客户端模式下,请改用 spark.kubernetes.authenticate.clientCertFile 。 |
2.3.0 |
spark.kubernetes.authenticate.driver.oauthToken |
(无) | 用于从驱动程序 pod 请求 executor 时针对 Kubernetes API 服务器进行身份验证的 OAuth 令牌。请注意,与其他身份验证选项不同,这必须是用于身份验证的令牌的精确字符串值。此令牌值将作为 Kubernetes secret 上传到驱动程序 pod。在客户端模式下,请改用 spark.kubernetes.authenticate.oauthToken 。 |
2.3.0 |
spark.kubernetes.authenticate.driver.oauthTokenFile |
(无) | 包含用于从驱动程序 pod 请求 executor 时针对 Kubernetes API 服务器进行身份验证的令牌的 OAuth 令牌文件的路径。请注意,与其他身份验证选项不同,此文件必须包含用于身份验证的令牌的精确字符串值。此令牌值将作为 secret 上传到驱动程序 pod。在客户端模式下,请改用 spark.kubernetes.authenticate.oauthTokenFile 。 |
2.3.0 |
spark.kubernetes.authenticate.driver.mounted.caCertFile |
(无) | 用于从驱动程序 pod 请求 executor 时通过 TLS 从驱动程序 pod 连接到 Kubernetes API 服务器的 CA 证书文件的路径。此路径必须可以从驱动程序 pod 访问。将其指定为路径而不是 URI(即不要提供方案)。在客户端模式下,请改用 spark.kubernetes.authenticate.caCertFile 。 |
2.3.0 |
spark.kubernetes.authenticate.driver.mounted.clientKeyFile |
(无) | 用于从驱动程序 pod 请求 executor 时针对 Kubernetes API 服务器进行身份验证的客户端密钥文件的路径。此路径必须可以从驱动程序 pod 访问。将其指定为路径而不是 URI(即不要提供方案)。在客户端模式下,请改用 spark.kubernetes.authenticate.clientKeyFile 。 |
2.3.0 |
spark.kubernetes.authenticate.driver.mounted.clientCertFile |
(无) | 用于从驱动程序 Pod 针对 Kubernetes API 服务器进行身份验证以请求执行程序的客户端证书文件的路径。此路径必须可从驱动程序 Pod 访问。将其指定为路径,而不是 URI(即,不要提供 scheme)。在客户端模式下,请改用 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 时使用的服务帐户。如果未设置此参数,则回退逻辑将使用驱动程序的ServiceAccount。 | 3.1.0 |
spark.kubernetes.authenticate.caCertFile |
(无) | 在客户端模式下,用于通过 TLS 连接到 Kubernetes API 服务器以请求执行程序的 CA 证书文件的路径。将其指定为路径,而不是 URI(即,不要提供 scheme)。 | 2.4.0 |
spark.kubernetes.authenticate.clientKeyFile |
(无) | 在客户端模式下,用于针对 Kubernetes API 服务器进行身份验证以请求执行程序的客户端密钥文件的路径。将其指定为路径,而不是 URI(即,不要提供 scheme)。 | 2.4.0 |
spark.kubernetes.authenticate.clientCertFile |
(无) | 在客户端模式下,用于针对 Kubernetes API 服务器进行身份验证以请求执行程序的客户端证书文件的路径。将其指定为路径,而不是 URI(即,不要提供 scheme)。 | 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] |
(无) | 将由 LabelName 指定的标签添加到驱动程序 Pod。例如,spark.kubernetes.driver.label.something=true 。请注意,Spark 还会将自己的标签添加到驱动程序 Pod 中,以用于记账目的。 |
2.3.0 |
spark.kubernetes.driver.annotation.[AnnotationName] |
(无) | 将由 AnnotationName 指定的 Kubernetes 注释添加到驱动程序 Pod。例如,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] |
(无) | 将由 LabelName 指定的标签添加到执行程序 Pod。例如,spark.kubernetes.executor.label.something=true 。请注意,Spark 还会将自己的标签添加到执行程序 Pod 中,以用于记账目的。 |
2.3.0 |
spark.kubernetes.executor.annotation.[AnnotationName] |
(无) | 将由 AnnotationName 指定的 Kubernetes 注释添加到执行程序 Pod。例如,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 Volume 添加到驱动程序 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] |
(无) | 配置通过 OptionName 作为键传递给 Kubernetes 的 Kubernetes Volume 选项,并指定值,必须符合 Kubernetes 选项格式。例如:spark.kubernetes.driver.volumes.persistentVolumeClaim.checkpointpvc.options.claimName=spark-pvc-claim 。 |
2.4.0 |
spark.kubernetes.executor.volumes.[VolumeType].[VolumeName].mount.path |
(无) | 将 VolumeType 类型的名为 VolumeName 的 Kubernetes Volume 添加到 executor pod 中,路径由该值指定。例如:spark.kubernetes.executor.volumes.persistentVolumeClaim.checkpointpvc.mount.path=/checkpoint 。 |
2.4.0 |
spark.kubernetes.executor.volumes.[VolumeType].[VolumeName].mount.subPath |
(无) | 指定要从卷挂载到 executor 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] |
(无) | 配置通过 OptionName 作为键传递给 Kubernetes 的 Kubernetes Volume 选项,并指定值。例如:spark.kubernetes.executor.volumes.persistentVolumeClaim.checkpointpvc.options.claimName=spark-pvc-claim 。 |
2.4.0 |
spark.kubernetes.local.dirs.tmpfs |
false |
配置用于支持 Spark driver 和 executor pod 中 SPARK_LOCAL_DIRS 的 emptyDir 卷以使用 tmpfs 后端,即 RAM。有关更多讨论,请参阅本页前面的本地存储。 |
3.0.0 |
spark.kubernetes.memoryOverheadFactor |
0.1 |
这将设置内存开销因子,该因子会将内存分配给非 JVM 内存,其中包括堆外内存分配、非 JVM 任务、各种系统进程以及 tmpfs 的本地目录 (当 spark.kubernetes.local.dirs.tmpfs 为 true 时)。对于基于 JVM 的作业,此值将默认为 0.10,对于非 JVM 作业,此值将默认为 0.40。这样做是因为非 JVM 任务需要更多的非 JVM 堆空间,并且此类任务通常会因“超出内存开销”错误而失败。这将通过更高的默认值来抢占此错误。这将由 spark.driver.memoryOverheadFactor 和 spark.executor.memoryOverheadFactor 显式设置的值覆盖。 |
2.4.0 |
spark.kubernetes.pyspark.pythonVersion |
"3" |
这设置了用于运行 driver 和 executor 容器的 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 |
(无) |
指定要挂载在 driver 和 executor 上的 krb5.conf 文件的本地位置,用于 Kerberos 交互。重要的是要注意,定义的 KDC 需要从容器内部可见。 | 3.0.0 |
spark.kubernetes.kerberos.krb5.configMapName |
(无) |
指定 ConfigMap 的名称,其中包含要挂载在 driver 和 executor 上的 krb5.conf 文件,用于 Kerberos 交互。定义的 KDC 需要从容器内部可见。ConfigMap 还必须与 driver 和 executor pod 位于同一命名空间中。 | 3.0.0 |
spark.kubernetes.hadoop.configMapName |
(无) |
指定 ConfigMap 的名称,其中包含要挂载在 driver 和 executor 上的 HADOOP_CONF_DIR 文件,用于自定义 Hadoop 配置。 | 3.0.0 |
spark.kubernetes.kerberos.tokenSecret.name |
(无) |
指定存储现有委托令牌的 secret 的名称。这消除了作业用户提供任何 Kerberos 凭据来启动作业的需要。 | 3.0.0 |
spark.kubernetes.kerberos.tokenSecret.itemKey |
(无) |
指定存储现有委托令牌的数据的 item key。这消除了作业用户提供任何 Kerberos 凭据来启动作业的需要。 | 3.0.0 |
spark.kubernetes.driver.podTemplateFile |
(无) | 指定包含 driver pod 模板的本地文件。例如:spark.kubernetes.driver.podTemplateFile=/path/to/driver-pod-template.yaml |
3.0.0 |
spark.kubernetes.driver.podTemplateContainerName |
(无) | 指定要在给定的 pod 模板中用作 driver 基础的容器名称。例如:spark.kubernetes.driver.podTemplateContainerName=spark-driver |
3.0.0 |
spark.kubernetes.executor.podTemplateFile |
(无) | 指定包含 executor pod 模板的本地文件。例如:spark.kubernetes.executor.podTemplateFile=/path/to/executor-pod-template.yaml |
3.0.0 |
spark.kubernetes.executor.podTemplateContainerName |
(无) | 指定要在给定的 pod 模板中用作 executor 基础的容器名称。例如:spark.kubernetes.executor.podTemplateContainerName=spark-executor |
3.0.0 |
spark.kubernetes.executor.deleteOnTermination |
true | 指定是否应在失败或正常终止的情况下删除 executor pod。 | 3.0.0 |
spark.kubernetes.executor.checkAllContainers |
false |
指定在确定 pod 状态时,executor pod 应该检查所有容器(包括 sidecar)还是仅检查 executor 容器。 | 3.1.0 |
spark.kubernetes.submission.connectionTimeout |
10000 |
Kubernetes 客户端用于启动 driver 的连接超时时间,以毫秒为单位。 | 3.0.0 |
spark.kubernetes.submission.requestTimeout |
10000 |
Kubernetes 客户端用于启动 driver 的请求超时时间,以毫秒为单位。 | 3.0.0 |
spark.kubernetes.trust.certificates |
false |
如果设置为 true,则客户端只能使用令牌提交到 Kubernetes 集群。 | 3.2.0 |
spark.kubernetes.driver.connectionTimeout |
10000 |
Driver 中的 Kubernetes 客户端在请求 executor 时使用的连接超时时间,以毫秒为单位。 | 3.0.0 |
spark.kubernetes.driver.requestTimeout |
10000 |
Driver 中的 Kubernetes 客户端在请求 executor 时使用的请求超时时间,以毫秒为单位。 | 3.0.0 |
spark.kubernetes.appKillPodDeletionGracePeriod |
(无) | 指定在使用 spark-submit 删除 Spark 应用程序时的优雅终止期限(以秒为单位)。 | 3.0.0 |
spark.kubernetes.dynamicAllocation.deleteGracePeriod |
5s |
在强制终止之前,等待 executor 正常关闭的时间。 | 3.0.0 |
spark.kubernetes.file.upload.path |
(无) | 用于在集群模式下 spark submit 端存储文件的路径。例如:spark.kubernetes.file.upload.path=s3a://<s3-bucket>/path 文件应指定为 file://path/to/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 |
(无) | 为每个 executor pod 指定调度器名称。 | 3.0.0 |
spark.kubernetes.driver.scheduler.name |
(无) | 为 driver pod 指定调度器名称。 | 3.3.0 |
spark.kubernetes.scheduler.name |
(无) | 为 driver 和 executor pod 指定调度器名称。如果设置了 `spark.kubernetes.driver.scheduler.name` 或 `spark.kubernetes.executor.scheduler.name`,将覆盖此设置。 | 3.3.0 |
spark.kubernetes.configMap.maxSize |
1048576 |
Config map 的最大大小限制。 可以根据 k8s 服务器端的 limit 进行配置。 | 3.1.0 |
spark.kubernetes.executor.missingPodDetectDelta |
30s |
当已注册的执行器的 POD 在 Kubernetes API 服务器轮询的 POD 列表中丢失时,此 delta 时间被认为是注册时间和轮询时间之间可接受的时间差。 在此时间之后,POD 将被认为是从集群中丢失,并且执行器将被删除。 | 3.1.1 |
spark.kubernetes.decommission.script |
/opt/decom.sh |
用于正常停用的脚本的位置。 | 3.2.0 |
spark.kubernetes.driver.service.deleteOnTermination |
true |
如果为 true,则 driver service 将在 Spark 应用程序终止时被删除。如果为 false,则将在 driver pod 删除时清理它。 | 3.2.0 |
spark.kubernetes.driver.service.ipFamilyPolicy |
SingleStack |
Driver Service 的 K8s IP 系列策略。有效值为 SingleStack 、PreferDualStack 和 RequireDualStack 。 |
3.4.0 |
spark.kubernetes.driver.service.ipFamilies |
IPv4 |
K8s Driver Service 的 IP 系列列表。有效值为 IPv4 和 IPv6 。 |
3.4.0 |
spark.kubernetes.driver.ownPersistentVolumeClaim |
true |
如果为 true,则 driver pod 将成为按需持久卷声明的所有者,而不是 executor pod | 3.2.0 |
spark.kubernetes.driver.reusePersistentVolumeClaim |
true |
如果为 true,则 driver pod 尝试重用已删除的 executor pod 的 driver 拥有的按需持久卷声明(如果存在)。 这可以通过跳过持久卷创建来减少 executor pod 创建延迟。 请注意,处于“Terminating”pod 状态的 pod 从定义上来说不是已删除的 pod,并且其资源(包括持久卷声明)尚不可重用。 当不存在可重用的持久卷声明时,Spark 将创建新的持久卷声明。 换句话说,持久卷声明的总数有时可能大于正在运行的 executor 的数量。 此配置需要 spark.kubernetes.driver.ownPersistentVolumeClaim=true。 |
3.2.0 |
spark.kubernetes.driver.waitToReusePersistentVolumeClaim |
false |
如果为 true,则 driver pod 会计算已创建的按需持久卷声明的数量,如果该数量大于或等于 Spark 作业能够拥有的卷总数,则会等待。 此配置需要 spark.kubernetes.driver.ownPersistentVolumeClaim=true 和 spark.kubernetes.driver.reusePersistentVolumeClaim=true。 |
3.4.0 |
spark.kubernetes.executor.disableConfigMap |
false |
如果为 true,则禁用为 executor 创建 ConfigMap。 | 3.2.0 |
spark.kubernetes.driver.pod.featureSteps |
(无) | 实现 `KubernetesFeatureConfigStep` 的额外 driver pod 功能步骤的类名。这是一个开发者 API。用逗号分隔。在所有 Spark 内部功能步骤之后运行。自 3.3.0 起,您的 driver 功能步骤可以实现 `KubernetesDriverCustomFeatureConfigStep`,其中还可以使用 driver 配置。 | 3.2.0 |
spark.kubernetes.executor.pod.featureSteps |
(无) | 实现 `KubernetesFeatureConfigStep` 的额外 executor pod 功能步骤的类名。这是一个开发者 API。用逗号分隔。在所有 Spark 内部功能步骤之后运行。自 3.3.0 起,您的 executor 功能步骤可以实现 `KubernetesExecutorCustomFeatureConfigStep`,其中还可以使用 executor 配置。 | 3.2.0 |
spark.kubernetes.allocation.maxPendingPods |
Int.MaxValue |
在此应用程序的 executor 分配期间允许的最大挂起 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 |
600s |
在新的创建的执行程序 POD 请求,尚未达到 POD 挂起状态之前等待的时间,该请求被认为超时并将被删除。 | 3.1.0 |
spark.kubernetes.allocation.driver.readinessTimeout |
1s |
在创建 Executor Pod 之前,等待 Driver Pod 准备就绪的时间。此等待仅在应用程序启动时发生。如果超时,Executor Pod 仍将被创建。 | 3.1.3 |
spark.kubernetes.executor.enablePollingWithResourceVersion |
false |
如果为 true,则在调用 Pod Listing API 时,`resourceVersion` 将设置为 `0`,以便允许 API Server 端的缓存。 应谨慎使用此设置。 | 3.3.0 |
spark.kubernetes.executor.eventProcessingInterval |
1s |
连续检查从 Kubernetes API 发送的 Executor 事件的间隔。 | 2.4.0 |
spark.kubernetes.executor.rollInterval |
0s |
Executor Roll 操作之间的间隔。默认情况下,设置为 `0s` 时禁用。 | 3.3.0 |
spark.kubernetes.executor.minTasksPerExecutorBeforeRolling |
0 |
Roll 操作前,每个 Executor 的最小任务数。 如果 Executor 的任务总数小于此配置,则 Spark 不会 Roll 该 Executor。 默认值为零。 | 3.3.0 |
spark.kubernetes.executor.rollPolicy |
OUTLIER |
Executor Roll 策略:有效值为 ID、ADD_TIME、TOTAL_GC_TIME、TOTAL_DURATION、FAILED_TASKS 和 OUTLIER (默认)。 当发生 Executor Roll 时,Spark 使用此策略选择一个 Executor 并将其退役。 内置策略基于 Executor 摘要,新启动的 Executor 受 spark.kubernetes.executor.minTasksPerExecutorBeforeRolling 保护。 ID 策略选择具有最小 Executor ID 的 Executor。 ADD_TIME 策略选择具有最小添加时间的 Executor。 TOTAL_GC_TIME 策略选择具有最大总任务 GC 时间的 Executor。 TOTAL_DURATION 策略选择具有最大总任务时间的 Executor。 AVERAGE_DURATION 策略选择具有最大平均任务时间的 Executor。 FAILED_TASKS 策略选择具有最多失败任务数的 Executor。 OUTLIER 策略选择具有超出统计数据的 Executor,该统计数据在平均任务时间、总任务时间、总任务 GC 时间和存在的失败任务数方面至少比平均值高出两个标准差。 如果没有异常值,它的工作方式类似于 TOTAL_DURATION 策略。 | 3.3.0 |
Pod 模板属性
请参阅下表,了解将被 Spark 覆盖的 Pod 规范的完整列表。
Pod 元数据
Pod 元数据键 | 修改后的值 | 描述 |
---|---|---|
name | spark.kubernetes.driver.pod.name 的值 |
Driver Pod 名称将被配置的或默认的 spark.kubernetes.driver.pod.name 值覆盖。 Executor Pod 名称将不受影响。 |
namespace | spark.kubernetes.namespace 的值 |
Spark 对 Driver 和 Executor 的命名空间做出强假设。Driver 和 Executor 的命名空间都将被配置的或默认的 Spark 配置值替换。 |
labels | 添加来自 spark.kubernetes.{driver,executor}.label.* 的标签 |
Spark 将添加 Spark 配置指定的其他标签。 |
annotations | 添加来自 spark.kubernetes.{driver,executor}.annotation.* 的注解 |
Spark 将添加 Spark 配置指定的其他注解。 |
Pod Spec
Pod 规范键 | 修改后的值 | 描述 |
---|---|---|
imagePullSecrets | 添加来自 spark.kubernetes.container.image.pullSecrets 的镜像拉取密钥 |
将从 Spark 配置将额外的拉取密钥添加到 Executor Pod。 |
nodeSelector | 添加来自 spark.kubernetes.node.selector.* 的节点选择器 |
将从 Spark 配置将额外的节点选择器添加到 Executor Pod。 |
restartPolicy | "never" |
Spark 假设 Driver 和 Executor 永远不会重启。 |
serviceAccount | spark.kubernetes.authenticate.driver.serviceAccountName 的值 |
Spark 将仅对 Driver Pod,并且仅当指定了 Spark 配置时,使用 Spark 配置的值覆盖 serviceAccount 。 Executor Pod 将不受影响。 |
serviceAccountName | spark.kubernetes.authenticate.driver.serviceAccountName 的值 |
Spark 将仅对 Driver Pod,并且仅当指定了 Spark 配置时,使用 Spark 配置的值覆盖 serviceAccountName 。 Executor Pod 将不受影响。 |
volumes | 添加来自 spark.kubernetes.{driver,executor}.volumes.[VolumeType].[VolumeName].mount.path 的卷 |
Spark 将添加 Spark 配置指定的卷,以及传递 Spark 配置和 Pod 模板文件所需的额外卷。 |
Container spec
以下影响 Driver 和 Executor 容器。 Pod 规范中的所有其他容器将不受影响。
容器规范键 | 修改后的值 | 描述 |
---|---|---|
env | 添加来自 spark.kubernetes.driverEnv.[EnvironmentVariableName] 的环境变量 |
Spark 将添加来自 spark.kubernetes.driverEnv.[EnvironmentVariableName] 的 Driver 环境变量,以及来自 spark.executorEnv.[EnvironmentVariableName] 的 Executor 环境变量。 |
image | spark.kubernetes.{driver,executor}.container.image 的值 |
镜像将由 Spark 配置定义。 |
imagePullPolicy | spark.kubernetes.container.image.pullPolicy 的值 |
Spark 将覆盖 Driver 和 Executor 的拉取策略。 |
name | 请参阅描述 | 如果 Pod 模板未定义容器名称,则容器名称将由 Spark 分配(Driver 容器为 "spark-kubernetes-driver",每个 Executor 容器为 "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 分配给每个容器的资源的地址。 因此,用户必须指定一个发现脚本,该脚本由 Executor 在启动时运行,以发现该 Executor 可用的资源。 您可以在 examples/src/main/scripts/getGpusResources.sh
中找到示例脚本。 该脚本必须设置执行权限,并且用户应设置权限以不允许恶意用户修改它。 该脚本应以 ResourceInformation 类的格式将 JSON 字符串写入 STDOUT。 这具有资源名称和仅该 Executor 可用的资源地址数组。
资源级别调度概述
Kubernetes 上的 Spark 支持多种资源级别的调度功能。
优先级调度
Kubernetes 默认支持 Pod 优先级。
Kubernetes 上的 Spark 允许通过 Pod 模板 定义作业的优先级。 用户可以在 Driver 或 Executor 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
用于 Kubernetes 上 Spark 的自定义 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
来支持更复杂的需求,包括但不限于- 为 Driver/Executor 调度创建额外的 Kubernetes 自定义资源。
- 根据配置或现有 Pod 信息动态设置调度器提示。
使用 Volcano 作为 Kubernetes 上 Spark 的自定义调度器
前提条件
-
自 Spark v3.3.0 和 Volcano v1.7.0 以来,支持使用 Volcano 作为自定义调度器的 Kubernetes 上的 Spark。 以下是一个安装 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
用法
Kubernetes 上的 Spark 允许使用 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 并设置 Driver/Executor Pod 注解以与此 PodGroup 链接。
请注意,目前 Volcano 特性步骤仅支持 Driver/Job 级别的 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 作为 Kubernetes 上 Spark 的自定义调度器
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.3.0 --create-namespace --set 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 调度器调度。
Stage 级别调度概述
Kubernetes 上支持阶段级别的调度
- 当动态分配被禁用时:它允许用户在阶段级别指定不同的任务资源需求,并将使用启动时请求的相同 Executor。
- 当启用动态分配时:它允许用户在阶段级别指定任务和 Executor 资源需求,并将请求额外的 Executor。 这也需要启用
spark.dynamicAllocation.shuffleTracking.enabled
,因为 Kubernetes 目前不支持外部 Shuffle 服务。 从 Kubernetes 请求不同配置文件的容器的顺序无法保证。 请注意,由于 Kubernetes 上的动态分配需要 Shuffle 跟踪功能,这意味着来自先前阶段的使用不同 ResourceProfile 的 Executor 可能不会因具有 Shuffle 数据而空闲超时。 这可能会导致使用更多的集群资源,并且在最坏的情况下,如果 Kubernetes 集群上没有剩余资源,那么 Spark 可能会挂起。 您可以考虑查看配置spark.dynamicAllocation.shuffleTracking.timeout
来设置超时,但这可能会导致如果真的需要 Shuffle 数据,则必须重新计算数据。 请注意,基本默认配置文件和自定义 ResourceProfile 之间处理 Pod 模板资源的方式存在差异。 Pod 模板文件中指定的任何资源都将仅用于基本默认配置文件。 如果您创建自定义 ResourceProfile,请务必包含所有必要的资源,因为模板文件中的资源不会传播到自定义 ResourceProfile。