在 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 卷的能力。

先决条件

工作原理

Spark cluster components

spark-submit 可以直接用于将 Spark 应用程序提交到 Kubernetes 集群。提交机制的工作原理如下

请注意,在已完成状态下,驱动程序 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 命令行参数传递给 spark-submit 或通过在应用程序的配置中设置 spark.master 来指定)必须是一个具有格式 k8s://<api_server_host>:<k8s-apiserver-port> 的 URL。即使是 HTTPS 端口 443,也必须始终指定端口。在主字符串前面加上 k8s:// 将导致 Spark 应用程序在 Kubernetes 集群上启动,并与 api_server_url 处的 API 服务器进行通信。如果 URL 中没有指定 HTTP 协议,则默认为 https。例如,将主节点设置为 k8s://example.com:443 等效于将其设置为 k8s://https://example.com:443,但要在不同端口上连接而不使用 TLS,主节点将设置为 k8s://http://example.com:8080

在 Kubernetes 模式下,由 spark.app.namespark-submit--name 参数指定的 Spark 应用程序名称默认情况下用于命名创建的 Kubernetes 资源,如驱动程序和执行器。因此,应用程序名称必须由小写字母数字字符、-. 组成,并且必须以字母数字字符开头和结尾。

如果您有一个 Kubernetes 集群设置,则发现 API 服务器 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 的参数。最后,请注意,在上面的示例中,我们指定了一个具有 local:// 方案的特定 URI 的 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 驱动程序的端口指定为 spark.driver.port

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

如果您在 Pod 中运行 Spark 驱动程序,强烈建议将 spark.kubernetes.driver.pod.name 设置为该 Pod 的名称。设置此属性后,Spark 调度程序将使用 所有者引用 部署执行器 Pod,这将确保一旦驱动程序 Pod 从集群中删除,应用程序的所有执行器 Pod 也将被删除。驱动程序将在由 spark.kubernetes.namespace 指定的命名空间中查找具有给定名称的 Pod,并将指向该 Pod 的所有者引用添加到每个执行器 Pod 的所有者引用列表中。注意不要将所有者引用设置为实际上不是该驱动程序 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.ipFamilyPolicyspark.kubernetes.driver.service.ipFamilies 可以是 SingleStackPreferDualStackRequireDualStack 中的一个,以及 IPv4IPv6IPv4,IPv6IPv6,IPv4 中的一个。默认情况下,Spark 使用 spark.kubernetes.driver.service.ipFamilyPolicy=SingleStackspark.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://<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.jarsspark.filesspark.archives 指定的依赖项。

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

密钥管理

Kubernetes 秘密 可用于为 Spark 应用程序提供访问安全服务的凭据。要将用户指定的秘密安装到驱动程序容器中,用户可以使用以下形式的配置属性:spark.kubernetes.driver.secrets.[SecretName]=<mount path>。类似地,可以使用以下形式的配置属性:spark.kubernetes.executor.secrets.[SecretName]=<mount path> 将用户指定的秘密安装到执行器容器中。请注意,假设要安装的秘密与驱动程序和执行器 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.podTemplateFilespark.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 开始。有关详细信息,请参阅 Pod 模板值的完整列表,这些值将被 spark 覆盖。

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

使用 Kubernetes 卷

用户可以将以下类型的 Kubernetes 安装到驱动程序和执行器 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 可以是以下值之一:hostPathemptyDirnfspersistentVolumeClaimVolumeName 是您要在 pod 规范的 volumes 字段下使用的卷的名称。

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

spark.kubernetes.driver.volumes.[VolumeType].[VolumeName].options.[OptionName]=<value>

例如,可以使用以下属性指定具有卷名 imagesnfs 的服务器和路径。

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

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

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

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

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

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 将使用 emptyDir 卷来创建,该卷为 spark.local.dir 中列出的每个目录或环境变量 SPARK_LOCAL_DIRS 挂载。如果没有明确指定目录,则会创建默认目录并进行适当配置。

emptyDir 卷使用 Kubernetes 的短暂存储功能,并且不会在 pod 的生命周期结束后持续存在。

使用 RAM 作为本地存储

emptyDir 卷默认使用支持节点的存储作为短暂存储,这种行为可能不适合某些计算环境。例如,如果您有使用通过网络挂载的远程存储的无盘节点,那么让大量执行器对该远程存储进行 IO 实际上可能会降低性能。

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

自省和调试

这些是您可以用来调查正在运行/已完成的 Spark 应用程序、监控进度和采取操作的不同方法。

访问日志

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

$ kubectl -n=<namespace> logs -f <driver-pod-name>

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

访问驱动程序 UI

可以使用 kubectl port-forward 在本地访问与任何应用程序关联的 UI。

$ kubectl port-forward <driver-pod-name> 4040:4040

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

调试

可能存在多种类型的故障。如果 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 环境变量指定的某个位置。Kubernetes 上的 Spark 将尝试使用此文件对用于与 Kubernetes 集群交互的 Kubernetes 客户端进行初始自动配置。提供各种 Spark 配置属性,允许进一步自定义客户端配置,例如使用替代身份验证方法。

上下文

Kubernetes 配置文件可以包含多个上下文,允许在不同的集群和/或用户身份之间切换。默认情况下,Kubernetes 上的 Spark 在对 Kubernetes 客户端进行初始自动配置时将使用您的当前上下文(可以通过运行 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 驱动程序 pod 使用 Kubernetes 服务帐户来访问 Kubernetes API 服务器,以创建和监视执行器 pod。驱动程序 pod 使用的服务帐户必须具有驱动程序能够执行其工作所需的适当权限。具体来说,至少,必须向服务帐户授予 RoleClusterRole,允许驱动程序 pod 创建 pod 和服务。默认情况下,驱动程序 pod 会自动分配 spark.kubernetes.namespace 指定的命名空间中的 default 服务帐户,如果在 pod 创建时没有指定服务帐户。

根据 Kubernetes 部署的版本和设置,此 default 服务帐户可能具有或可能没有允许驱动程序 pod 在默认 Kubernetes RBAC 策略下创建 pod 和服务的权限。有时,用户可能需要指定具有授予的正确角色的自定义服务帐户。Kubernetes 上的 Spark 支持通过配置属性 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

要向服务帐户授予 RoleClusterRole,需要 RoleBindingClusterRoleBinding。要创建 RoleBindingClusterRoleBinding,用户可以使用 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,由于驱动程序始终在同一个命名空间中创建执行器 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 属性指定 pod 终止的宽限期,使用 --conf 作为提供它的方式(所有 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 主机(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 中拉取镜像时使用的容器镜像拉取策略。有效值为 AlwaysNeverIfNotPresent 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 令牌文件路径。请注意,与其他身份验证选项不同,此文件必须包含用于身份验证的令牌的精确字符串值。此令牌值将作为 Kubernetes 秘密上传到驱动程序 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 (无) 在客户端模式下,用于通过 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] (无) 将由 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 不同:它仅在设置时使用,并优先于 spark.executor.cores 来指定执行器 Pod CPU 请求。任务并行度(例如,执行器可以同时运行的任务数量)不受此影响。 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] (无) 将名为 SecretNameKubernetes 密钥 添加到驱动程序 Pod 上的值中指定的路径。例如,spark.kubernetes.driver.secrets.spark-secret=/etc/secrets 2.3.0
spark.kubernetes.executor.secrets.[SecretName] (无) 将名为 SecretNameKubernetes 密钥 添加到执行器 Pod 上的值中指定的路径。例如,spark.kubernetes.executor.secrets.spark-secret=/etc/secrets 2.3.0
spark.kubernetes.driver.secretKeyRef.[EnvName] (无) 将作为环境变量添加到驱动程序容器,名称为 EnvName(区分大小写),值为引用的 Kubernetes 密钥 数据中的键 key 所引用。例如,spark.kubernetes.driver.secretKeyRef.ENV_VAR=spark-secret:key 2.4.0
spark.kubernetes.executor.secretKeyRef.[EnvName] (无) 将作为环境变量添加到执行器容器,名称为 EnvName(区分大小写),值为引用的 Kubernetes 密钥 数据中的键 key 所引用。例如,spark.kubernetes.executor.secrets.ENV_VAR=spark-secret:key 2.4.0
spark.kubernetes.driver.volumes.[VolumeType].[VolumeName].mount.path (无) 将名为 VolumeNameVolumeType 类型的 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.executor.volumes.[VolumeType].[VolumeName].mount.path (无) 将名为 VolumeNameVolumeType 类型的 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.local.dirs.tmpfs false 配置用于支持 Spark 驱动程序和执行器 Pod 中 SPARK_LOCAL_DIRSemptyDir 卷以使用 tmpfs 支持,即 RAM。有关此的更多讨论,请参阅本页前面部分的 本地存储 3.0.0
spark.kubernetes.memoryOverheadFactor 0.1 这将设置内存开销因子,该因子将为非 JVM 内存分配内存,其中包括堆外内存分配、非 JVM 任务、各种系统进程以及当 spark.kubernetes.local.dirs.tmpfstrue 时基于 tmpfs 的本地目录。对于基于 JVM 的作业,此值将默认为 0.10,对于非 JVM 作业,此值将默认为 0.40。这是因为非 JVM 任务需要更多非 JVM 堆空间,并且此类任务通常会因“内存开销超过”错误而失败。这通过更高的默认值来防止此错误。这将被 spark.driver.memoryOverheadFactorspark.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 (无) 指定 ConfigMap 的名称,该 ConfigMap 包含 krb5.conf 文件,并将被挂载到驱动程序和执行器上,用于 Kerberos 交互。定义的 KDC 需要从容器内部可见。ConfigMap 还必须与驱动程序和执行器 Pod 位于同一个命名空间。 3.0.0
spark.kubernetes.hadoop.configMapName (无) 指定 ConfigMap 的名称,该 ConfigMap 包含 HADOOP_CONF_DIR 文件,并将被挂载到驱动程序和执行器上,用于自定义 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 指定执行器 Pod 是否应该在失败或正常终止的情况下被删除。 3.0.0
spark.kubernetes.executor.checkAllContainers false 指定执行器 Pod 是否应该检查所有容器(包括 sidecar)或仅在确定 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 5s 强制杀死之前等待执行器正常关闭的时间。 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 (无) 指定每个执行器 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 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 族策略。有效值为 SingleStackPreferDualStackRequireDualStack 3.4.0
spark.kubernetes.driver.service.ipFamilies IPv4 K8s 驱动程序服务的 IP 族列表。有效值为 IPv4IPv6 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=truespark.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 600s 在新建的执行器 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 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 将仅为驱动程序 Pod 覆盖 serviceAccount,并仅在指定了 Spark 配置的情况下。执行器 Pod 将保持不受影响。
serviceAccountName spark.kubernetes.authenticate.driver.serviceAccountName 的值 Spark 将仅为驱动程序 Pod 覆盖 serviceAccountName,并仅在指定了 Spark 配置的情况下。执行器 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}.memoryspark.{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 中找到示例脚本。该脚本必须设置执行权限,用户应设置权限以不允许恶意用户修改它。该脚本应将 ResourceInformation 类格式的 JSON 字符串写入 STDOUT。这包含资源名称和仅对该执行器可用的资源地址数组。

资源级别调度概述

Spark 在 Kubernetes 上支持几种资源级调度功能。

优先级调度

Kubernetes 默认支持 Pod 优先级

Spark 在 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 调度器。

  1. 指定调度器名称。

    用户可以使用 spark.kubernetes.scheduler.namespark.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 信息动态设置调度器提示。

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

先决条件
构建

要创建与 Volcano 支持一起的 Spark 发行版(例如 Spark 下载页面 上分发的那些发行版),请参阅 “构建 Spark” 中的更多信息

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

Spark 在 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.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 调度器调度。

阶段级别调度概述

Kubernetes 上支持阶段级调度