Spark 如何在Kubernetes运行官方权威资料spark on k8s

Spark 如何在Kubernetes运行官方权威资料

文章目录

  • Spark 如何在Kubernetes运行官方权威资料
  • 安全性
    • 用户身份
    • 卷挂载
  • 先决条件
  • 工作原理
      • Spark集群组件
  • 提交应用到kubernetes
    • Docker镜像
    • 集群模式
    • 客户端模式
      • 客户端模式网络
      • 客户端模式执行器Pod垃圾回收
      • 身份验证参数
    • IPv4和IPv6
    • 依赖管理
    • 密钥管理
    • Pod模板
    • 使用Kubernetes卷
      • PVC导向的执行器Pod分配
    • 本地存储
      • 使用RAM作为本地存储
    • 自省和调试
      • 访问日志
      • 访问驱动程序UI
      • 调试
    • Kubernetes功能
        • 配置文件
        • 上下文
        • 命名空间
        • RBAC
    • Spark应用程序管理
    • 未来工作
  • Spark on Kubernetes配置
    • Spark属性
    • Pod 模板属性
    • 容器规格
    • 资源分配和配置概述
    • 资源级调度概述
        • 优先级调度
        • 自定义Kubernetes调度器
          • 指定调度器名称
          • 指定调度器相关配置
          • 指定调度器特性步骤
        • 使用Volcano作为自定义调度器
          • 先决条件
          • 构建
          • 使用方法
          • Volcano特性步骤
          • Volcano PodGroup模板
        • 使用Apache YuniKorn作为自定义调度器
          • 先决条件
          • 使用方法
      • 阶段级调度概述
      • 阶段级调度概述
  • 参考链接

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

安全性

默认情况下,未启用安全特性如身份验证。当部署一个对外开放或不受信任网络的集群时,重要的是保护集群的访问权限,以防止未经授权的应用程序在集群上运行。在运行Spark之前,请参考Spark安全性和本文档中的特定安全性部分。

用户身份

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

另外,Pod模板功能可以用于为Spark提交的Pod添加Security Context,并设置runAsUser。这可以用于覆盖镜像本身中的USER指令。请注意,这需要用户的合作,因此可能不适合共享环境的解决方案。如果集群管理员希望限制Pod能够以何种用户身份运行,应使用Pod安全策略。

卷挂载

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

集群管理员应使用Pod安全策略,适当限制挂载hostPath卷的能力。

先决条件

  • 运行版本大于等于1.24的Kubernetes集群,并使用kubectl进行配置访问。如果您还没有一个可用的Kubernetes集群,可以使用minikube在本地机器上设置一个测试集群。
  • 我们建议使用启用了DNS插件的最新版minikube。
  • 请注意,默认的minikube配置不足以运行Spark应用程序。我们建议使用3个CPU和4G内存来启动一个简单的Spark应用程序,其中只有一个执行器。
  • 检查kubernetes-client库的版本与您的Spark环境及其与Kubernetes集群版本的兼容性。
  • 您必须具有适当的权限,以在集群中列出、创建、编辑和删除Pod。您可以通过运行kubectl auth can-i pods来验证您是否能够列出这些资源。
  • 驱动程序Pod使用的服务帐户凭据必须被允许创建Pod、服务和配置映射。
  • 您必须在集群中配置了Kubernetes DNS。

工作原理

Spark 如何在Kubernetes运行官方权威资料spark on k8s_第1张图片

Spark集群组件

可以直接使用spark-submit将Spark应用程序提交到Kubernetes集群。提交机制的工作方式如下:

  1. Spark创建一个在Kubernetes pod中运行的Spark驱动程序。
  2. 驱动程序创建执行器,这些执行器也在Kubernetes pod中运行,并连接到它们并执行应用程序代码。
  3. 当应用程序完成时,执行器pod终止并进行清理,但是驱动程序pod保留日志,并在Kubernetes API中保持“已完成”状态,直到最终进行垃圾回收或手动清理。

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

驱动程序和执行器pod的调度由Kubernetes处理。通过fabric8进行与Kubernetes API的通信。可以使用节点选择器将驱动程序和执行器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  -t my-tag build
$ ./bin/docker-image-tool.sh -r  -t my-tag push

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

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

示例用法如下:

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

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

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

集群模式

要在集群模式下启动Spark Pi应用程序,请运行以下命令:

$ ./bin/spark-submit \
    --master k8s://https://<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://:的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应用程序名称或通过spark-submit的–name参数指定的名称将默认用于命名创建的驱动程序和执行器等Kubernetes资源。因此,应用程序名称必须由小写字母数字字符、-和.组成,并且必须以字母数字字符开头和结尾。

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

$ 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的jar文件。该URI是已经在Docker镜像中的示例jar的位置。

客户端模式

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

客户端模式网络

Spark执行器必须能够通过主机名和端口连接到Spark驱动程序。Spark在客户端模式下正常工作所需的特定网络配置会因设置而异。如果将驱动程序放在Kubernetes pod内,可以使用无头服务(headless service)来允许执行器通过稳定的主机名从执行器访问驱动程序。在部署无头服务时,请确保服务的标签选择器仅与驱动程序pod匹配,不与其他pod匹配;建议为驱动程序pod分配一个足够唯一的标签,并在无头服务的标签选择器中使用该标签。可以通过spark.driver.host指定驱动程序的主机名,并通过spark.driver.port指定Spark驱动程序的端口。

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

如果您将Spark驱动程序放在一个pod中,强烈建议将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环境中使用。根据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

在双栈环境中,您可能还需要使用java.net.preferIPv6Addresses=true配置JVM,并使用SPARK_PREFER_IPV6=true配置Python来使用IPv6。

依赖管理

如果应用程序的依赖项都托管在远程位置,如HDFS或HTTP服务器,可以使用相应的远程URI引用它们。还可以将应用程序依赖项预先挂载到自定义构建的Docker镜像中。可以通过使用local:// URI引用它们并/或在Dockerfiles中设置SPARK_EXTRA_CLASSPATH环境变量将这些依赖项添加到类路径中。客户端模式下,还支持从提交客户端的本地文件系统使用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.jars、spark.files和spark.archives指定的依赖项,也支持client scheme。

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

密钥管理

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

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

要通过环境变量使用密钥,请在spark-submit命令中使用以下选项:

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

Pod模板

Kubernetes允许从模板文件定义Pod。Spark用户可以类似地使用模板文件来定义驱动程序或执行器pod的配置,这些配置不受Spark配置支持。为此,请指定spark属性spark.kubernetes.driver.podTemplateFile和spark.kubernetes.executor.podTemplateFile,以指向对spark-submit进程可访问的文件。

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

要允许驱动程序pod访问执行器pod模板文件,当创建驱动程序pod时,该文件将自动挂载到驱动程序pod中的一个卷上。Spark不会在取消编组这些模板文件后进行任何验证,并依赖于Kubernetes API服务器进行验证。

重要提示:Spark对某些pod配置持有意见,因此在模板文件中将始终被Spark覆盖的值。因此,使用此功能的用户应注意,指定模板pod文件只是让Spark在构建过程中使用模板pod而不是空白pod。有关将被spark覆盖的完整列表,请参阅spark覆盖的完整列表。

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

使用Kubernetes卷

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

  • hostPath:将主机节点文件系统上的文件或目录挂载到pod中。
  • emptyDir:在分配pod给节点时创建的初始为空的卷。
  • nfs:将现有NFS(Network File System)挂载到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.。

例如,可以通过以下方式挂载每个执行器的动态创建的持久卷索赔:

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的生命周期与其所有者执行器紧密耦合。但是,在Spark作业的生命周期内,on-demand PVC可以由驱动程序拥有并在另一个执行器之间重复使用。这样可以减少PVC创建和删除的开销。

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

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

spark.kubernetes.driver.waitToReusePersistentVolumeClaim=true

本地存储

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

--conf spark.kubernetes.driver.volumes.[VolumeType].spark-local-dir-[VolumeName].mount.path=<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将使用临时的scratch空间在洗牌和其他操作期间将数据溢写到磁盘。当使用Kubernetes作为资源管理器时,将为每个列出的目录创建带有emptyDir卷的pod。如果未明确指定目录,则会创建一个默认目录,并相应地进行配置。

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

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

$ 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环境变量指定的位置。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命名空间中的默认服务账户。

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

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

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

$ kubectl create serviceaccount spark

要为服务账户授予Role或ClusterRole,需要使用RoleBinding或ClusterRoleBinding。用户可以使用kubectl create rolebinding(对于ClusterRoleBinding则使用kubectl create clusterrolebinding)命令来创建RoleBinding或ClusterRoleBinding。例如,以下命令在默认命名空间中创建一个名为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服务账户,请参阅“Using RBAC Authorization”和“Configure Service Accounts for Pods”。

Spark应用程序管理

Kubernetes通过spark-submit CLI工具提供了在集群模式下简单的应用程序管理功能。用户可以通过提供作业提交时打印的submission ID来终止作业。submission ID的格式为namespace:driver-pod-name。如果用户省略了命名空间,则使用当前k8s上下文中设置的命名空间。例如,如果用户已经设置了特定的命名空间如kubectl config set-context minikube --namespace=spark,那么默认情况下将使用spark命名空间。另外,如果特定上下文中没有添加命名空间,则默认情况下将考虑所有命名空间。这意味着无论命名空间如何,操作都将影响与给定submission 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集成的未来版本中。其中一些功能包括:

  • 外部Shuffle服务
  • 作业队列和资源管理

Spark on Kubernetes配置

Spark on Kubernetes有一些特定的配置,可以通过配置文件进行设置。以下是一些常用的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服务器)地址,或者在仅驱动程序模式下使用’local[*]'。 3.0.0
spark.kubernetes.namespace default 用于运行驱动程序和执行器Pod的命名空间。 2.3.0
spark.kubernetes.container.image (无) 用于Spark应用程序的容器映像。通常为example.com/repo/spark:v1.0.0。这个配置是必需的,并且必须由用户提供,除非为每个不同的容器类型提供了显式的镜像。 2.3.0
spark.kubernetes.driver.container.image spark.kubernetes.container.image的值 用于驱动程序的自定义容器映像。 2.3.0
spark.kubernetes.executor.container.image spark.kubernetes.container.image的值 用于执行器的自定义容器映像。 2.3.0
spark.kubernetes.container.image.pullPolicy IfNotPresent 在Kubernetes中拉取镜像时使用的容器映像拉取策略。有效值为Always、Never和IfNotPresent。 2.3.0
spark.kubernetes.container.image.pullSecrets (无) 用于从私有镜像仓库拉取镜像的Kubernetes密钥的逗号分隔列表。 2.4.0
spark.kubernetes.allocation.batch.size 5 每次执行器Pod分配中一次启动的Pod数量。 2.3.0
spark.kubernetes.allocation.batch.delay 1s 每次执行器Pod分配之间等待的时间。指定小于1秒的值可能会导致Spark驱动程序的过度CPU使用。 2.3.0
spark.kubernetes.authenticate.submission.caCertFile (无) 连接到Kubernetes API服务器时,用于驱动程序启动时进行TLS身份验证的CA证书文件的路径。该文件必须位于提交机器的磁盘上。在客户端模式下,请使用spark.kubernetes.authenticate.caCertFile。 2.3.0
spark.kubernetes.authenticate.submission.clientKeyFile (无) 连接到Kubernetes API服务器时,用于驱动程序启动时对API服务器进行身份验证的客户端密钥文件的路径。该文件必须位于提交机器的磁盘上。在客户端模式下,请使用spark.kubernetes.authenticate.clientKeyFile。 2.3.0
spark.kubernetes.authenticate.submission.clientCertFile (无) 连接到Kubernetes API服务器时,用于驱动程序启动时对API服务器进行身份验证的客户端证书文件的路径。该文件必须位于提交机器的磁盘上。在客户端模式下,请使用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令牌的OAuth令牌文件的路径。该文件必须位于提交机器的磁盘上。在客户端模式下,请使用spark.kubernetes.authenticate.oauthTokenFile。 2.3.0
spark.kubernetes.authenticate.driver.caCertFile (无) 用于从驱动程序Pod向API服务器请求执行器时,在TLS上下文中连接到Kubernetes API服务器时使用的CA证书文件的路径。该文件必须位于提交机器的磁盘上,并将被上传到驱动程序Pod。在客户端模式下,请使用spark.kubernetes.authenticate.caCertFile。 2.3.0
spark.kubernetes.authenticate.driver.clientKeyFile (无) 用于从驱动程序Pod向API服务器请求执行器时,用于对API服务器进行身份验证的客户端密钥文件的路径。该文件必须位于提交机器的磁盘上,并将作为Kubernetes密钥上传到驱动程序Pod。在客户端模式下,请使用spark.kubernetes.authenticate.clientKeyFile。 2.3.0
spark.kubernetes.authenticate.driver.clientCertFile (无) 用于从驱动程序Pod向API服务器请求执行器时,用于对API服务器进行身份验证的客户端证书文件的路径。该文件必须位于提交机器的磁盘上,并将作为Kubernetes密钥上传到驱动程序Pod。在客户端模式下,请使用spark.kubernetes.authenticate.clientCertFile。 2.3.0
spark.kubernetes.authenticate.driver.oauthToken (无) 用于从驱动程序Pod向API服务器请求执行器时进行身份验证的OAuth令牌。与其他身份验证选项不同,这个令牌必须是用于身份验证的确切字符串值。此令牌值将作为Kubernetes密钥上传到驱动程序Pod。在客户端模式下,请使用spark.kubernetes.authenticate.oauthToken。 2.3.0
spark.kubernetes.authenticate.driver.oauthTokenFile (无) 包含用于从驱动程序Pod向API服务器请求执行器时进行身份验证的OAuth令牌的OAuth令牌文件的路径。该文件必须位于提交机器的磁盘上,并作为密钥上传到驱动程序Pod。在客户端模式下,请使用spark.kubernetes.authenticate.oauthTokenFile。 2.3.0
spark.kubernetes.authenticate.driver.mounted.caCertFile (无) 用于从驱动程序Pod向API服务器请求执行器时,在TLS上下文中连接到Kubernetes API服务器时使用的CA证书文件的路径。该路径必须从驱动程序Pod可访问。在客户端模式下,请使用spark.kubernetes.authenticate.caCertFile。 2.3.0
spark.kubernetes.authenticate.driver.mounted.clientKeyFile (无) 用于从驱动程序Pod向API服务器请求执行器时,用于对API服务器进行身份验证的客户端密钥文件的路径。该路径必须从驱动程序Pod可访问。在客户端模式下,请使用spark.kubernetes.authenticate.clientKeyFile。 2.3.0
spark.kubernetes.authenticate.driver.mounted.clientCertFile (无) 用于从驱动程序Pod向API服务器请求执行器时,用于对API服务器进行身份验证的客户端证书文件的路径。该路径必须从驱动程序Pod可访问。在客户端模式下,请使用spark.kubernetes.authenticate.clientCertFile。 2.3.0
spark.kubernetes.authenticate.driver.mounted.oauthTokenFile (无) 包含用于从驱动程序Pod向API服务器请求执行器时进行身份验证的OAuth令牌的OAuth令牌文件的路径。该路径必须从驱动程序Pod可访问。与其他身份验证选项不同,此文件必须包含用于身份验证的确切字符串值。在客户端模式下,请使用spark.kubernetes.authenticate.oauthTokenFile。 2.3.0
spark.kubernetes.authenticate.driver.serviceAccountName default 运行驱动程序Pod时使用的服务帐户。驱动程序Pod在向API服务器请求执行器Pod时使用此服务帐户。请注意,这不能与CA证书文件、客户端密钥文件、客户端证书文件和/或OAuth令牌一起指定。在客户端模式下,请使用spark.kubernetes.authenticate.serviceAccountName。 2.3.0
spark.kubernetes.authenticate.executor.serviceAccountName spark.kubernetes.authenticate.driver.serviceAccountName的值 运行执行器Pod时使用的服务帐户。如果没有设置此参数,则回退逻辑将使用驱动程序的服务帐户。 3.1.0
spark.kubernetes.authenticate.caCertFile (无) 在客户端模式下,用于连接到Kubernetes API服务器进行TLS身份验证时的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令牌的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 Label Names的规则。前缀将用于生成执行器Pod的名称,形如podNamePrefix-exec-id,其中id是一个正整数值,因此podNamePrefix的长度需要小于等于47(= 63 - 10 - 6)。 2.3.0
spark.kubernetes.submission.waitAppCompletion true 在集群模式下,在退出launcher进程之前是否等待应用程序完成。当设置为false时,启动Spark作业的launcher进程具有“fire-and-forget”的行为。 2.3.0
spark.kubernetes.report.interval 1s 在集群模式下,当前Spark作业状态报告的间隔。 2.3.0
spark.kubernetes.executor.apiPollingInterval 30s 对Kubernetes API服务器进行轮询以检查执行器状态的间隔。 2.4.0
spark.kubernetes.driver.request.cores (无) 指定驱动程序Pod的CPU请求。值符合Kubernetes约定。例如,0.1、500m、1.5、5等,其中CPU单位的定义在CPU units中记录。如果设置了此配置,则优先于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 units中记录。这与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] (无) 将LabelName指定的标签添加到驱动程序Pod和执行器Pod的节点选择器中,其值为配置的值。例如,将spark.kubernetes.node.selector.identifier设置为myIdentifier将导致驱动程序Pod和执行器Pod具有带有标签identifier和值myIdentifier的节点选择器。可以通过设置具有此前缀的多个配置来添加多个节点选择器键。 2.3.0
spark.kubernetes.driver.node.selector.[labelKey] (无) 将LabelName指定的标签添加到驱动程序Pod的节点选择器中,其值为配置的值。例如,将spark.kubernetes.driver.node.selector.identifier设置为myIdentifier将导致驱动程序Pod具有带有标签identifier和值myIdentifier的节点选择器。可以通过设置具有此前缀的多个配置来添加多个驱动程序节点选择器键。 3.3.0
spark.kubernetes.executor.node.selector.[labelKey] (无) 将LabelName指定的标签添加到执行器Pod的节点选择器中,其值为配置的值。例如,将spark.kubernetes.executor.node.selector.identifier设置为myIdentifier将导致执行器Pod具有带有标签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 (无) 将具有VolumeType类型和VolumeName名称的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] (无) 配置传递给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 (无) 将具有VolumeType类型和VolumeName名称的Kubernetes Volume添加到执行器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_DIRS的emptyDir卷是否使用tmpfs(RAM)作为后备存储。有关此问题的更多讨论,请参见前面的本地存储。 3.0.0
spark.kubernetes.memoryOverheadFactor 0.1 设置将内存分配给非JVM内存的Memory Overhead Factor,其中包括堆外内存分配、非JVM任务、各种系统进程以及当spark.kubernetes.local.dirs.tmpfs为true时基于tmpfs的本地目录。对于基于JVM的作业,默认值为0.10,对于非JVM的作业默认值为0.40。这样做是因为非JVM任务需要更多的非JVM堆空间,而这些任务通常会出现“内存超过限制”的错误。通过较高的默认值来预防此错误。这个值将被spark.driver.memoryOverheadFactor和spark.executor.memoryOverheadFactor显式设置的值覆盖。 2.4.0
spark.kubernetes.pyspark.pythonVersion “3” 设置用于运行驱动程序和执行器容器的Docker镜像的主要Python版本。只能为"3"。从Spark 3.1.0开始,该配置已被弃用,并且实际上不起作用。用户应该设置’spark.pyspark.python’和’spark.pyspark.driver.python’配置或’PYSPARK_PYTHON’和’PYSPARK_DRIVER_PYTHON’环境变量。 2.4.0
spark.kubernetes.kerberos.krb5.path (无) 指定krb5.conf文件的本地位置,用于在驱动程序和执行器上挂载进行Kerberos交互。重要的是注意,KDC需要从容器内部可见。 3.0.0
spark.kubernetes.kerberos.krb5.configMapName (无) 指定包含krb5.conf文件的ConfigMap的名称,用于在驱动程序和执行器上挂载进行Kerberos交互。KDC需要从容器内部可见。ConfigMap还必须与驱动程序和执行器Pod位于同一个命名空间中。 3.0.0
spark.kubernetes.hadoop.configMapName (无) 指定包含HADOOP_CONF_DIR文件的ConfigMap的名称,用于在驱动程序和执行器上挂载自定义的Hadoop配置。 3.0.0
spark.kubernetes.kerberos.tokenSecret.name (无) 指定存储现有委托令牌的密钥的名称。这样可以省去作业用户提供任何Kerberos凭据来启动作业的需要。 3.0.0
spark.kubernetes.kerberos.tokenSecret.itemKey (无) 指定存储现有委托令牌的数据的项目键。这样可以省去作业用户提供任何Kerberos凭据来启动作业的需要。 3.0.0
spark.kubernetes.driver.podTemplateFile (无) 指定包含驱动程序Pod模板的本地文件。例如spark.kubernetes.driver.podTemplateFile=/path/to/driver-pod-template.yaml 3.0.0
spark.kubernetes.driver.podTemplateContainerName (无) 指定要在给定Pod模板中用作驱动程序基础的容器名称。例如spark.kubernetes.driver.podTemplateContainerName=spark-driver 3.0.0
spark.kubernetes.executor.podTemplateFile (无) 指定包含执行器Pod模板的本地文件。例如spark.kubernetes.executor.podTemplateFile=/path/to/executor-pod-template.yaml 3.0.0
spark.kubernetes.executor.podTemplateContainerName (无) 指定要在给定Pod模板中用作执行器基础的容器名称。例如spark.kubernetes.executor.podTemplateContainerName=spark-executor 3.0.0
spark.kubernetes.executor.deleteOnTermination true 指定在出现故障或正常终止时是否删除执行器Pod。 3.0.0
spark.kubernetes.executor.checkAllContainers false 指定在确定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 (none) 使用spark-submit删除Spark应用程序时指定的容忍期限(以秒为单位) 3.0.0
spark.kubernetes.dynamicAllocation.deleteGracePeriod 5s 在强制终止之前等待执行器正常关闭的时间(以秒为单位) 3.0.0
spark.kubernetes.file.upload.path (none) 集群模式下存储文件的路径。例如:spark.kubernetes.file.upload.path=s3a:///path 文件应指定为file://path/to/file或绝对路径。 3.0.0
spark.kubernetes.executor.decommissionLabel (none) 退出或被废除的pod应用的标签。可与pod破坏预算、删除成本和类似情况一起使用。 3.3.0
spark.kubernetes.executor.decommissionLabelValue (none) 启用spark.kubernetes.executor.decommissionLabel时要应用的标签的值。 3.3.0
spark.kubernetes.executor.scheduler.name (none) 指定每个执行器pod的调度程序名称。 3.0.0
spark.kubernetes.driver.scheduler.name (none) 指定驱动程序pod的调度程序名称。 3.3.0
spark.kubernetes.scheduler.name (none) 指定驱动程序和执行器pod的调度程序名称。如果设置了spark.kubernetes.driver.scheduler.namespark.kubernetes.executor.scheduler.name,将覆盖此设置。 3.3.0
spark.kubernetes.configMap.maxSize 1572864 配置映射的最大大小限制。这可根据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 Family策略。有效值为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,则驱动程序pod成为按需持久卷索赔的所有者,而不是执行器pod。 3.2.0
spark.kubernetes.driver.reusePersistentVolumeClaim true 如果为true,则驱动程序pod尝试重用已删除的执行器pod的驱动程序拥有的按需持久卷索赔(如果存在)。这可以通过跳过持久卷创建来减少执行器pod的创建延迟。请注意,“Terminating” 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 (none) 实现KubernetesFeatureConfigStep的额外驱动程序pod功能步骤的类名。这是开发人员API。逗号分隔。在所有Spark内部功能步骤之后运行。从3.3.0开始,您的驱动程序功能步骤可以实现KubernetesDriverCustomFeatureConfigStep,其中驱动程序配置也可用。 3.2.0
spark.kubernetes.executor.pod.featureSteps (none) 实现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 执行器滚动策略。

Pod 模板属性

请查看以下表格,了解将被 Spark 覆盖的完整 Pod 规格列表。

Pod Metadata键 修改后的值 描述
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 规格中的其他所有容器都不会受到影响。
容器规格键

修改后的值 描述
imagePullSecrets spark.kubernetes.container.image.pullSecrets 附加的拉取密钥将从spark配置添加到执行器pod中。
nodeSelector spark.kubernetes.node.selector.* 附加的节点选择器将从spark配置添加到执行器pod中。
restartPolicy “never” Spark假设驱动程序和执行器永远不会重启。
serviceAccount spark.kubernetes.authenticate.driver.serviceAccountName 仅当指定了spark配置时,Spark将使用spark配置的值来覆盖driver pods的serviceAccount。执行器pod将不受影响。
serviceAccountName spark.kubernetes.authenticate.driver.serviceAccountName 仅当指定了spark配置时,Spark将使用spark配置的值来覆盖driver pods的serviceAccountName。执行器pod将不受影响。
volumes spark.kubernetes.{driver,executor}.volumes.[VolumeType].[VolumeName].mount.path Spark将根据spark配置添加卷,以及传递spark配置和pod模板文件所需的附加卷。

资源分配和配置概述

请确保已阅读配置页面上的"自定义资源调度和配置概述"部分。本节仅讨论资源调度在Kubernetes中的特定方面。

用户负责正确配置Kubernetes集群,以确保有足够的可用资源,并最好为每个容器隔离资源,避免多个容器共享同一资源。如果资源未被隔离,用户需要编写发现脚本,以确保资源不会在容器之间共享。具体的Kubernetes配置细节请参考Kubernetes文档。

Spark会自动将Spark配置spark.{driver/executor}.resource.{resourceType}转换为Kubernetes配置,前提是Kubernetes资源类型符合Kubernetes设备插件格式vendor-domain/resourcetype。用户需要使用spark.{driver/executor}.resource.{resourceType}.vendor配置来指定供应商。如果您正在使用Pod模板,无需显式添加任何内容。关于示例和参考,请查看Kubernetes文档中有关调度GPU的部分。Spark仅支持设置资源限制。

Kubernetes不会向Spark提供分配给每个容器的资源地址。因此,用户需要指定一个发现脚本,在执行器启动时由执行器运行,以发现该执行器可用的资源。示例脚本可以在examples/src/main/scripts/getGpusResources.sh中找到。该脚本必须具有可执行权限,并且用户应设置适当的权限,以防止恶意用户修改脚本。该脚本应将资源信息作为JSON字符串写入标准输出(STDOUT),格式应符合ResourceInformation类的要求,包括资源名称和该执行器可用的资源地址数组。

资源级调度概述

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

优先级调度

Kubernetes默认支持Pod优先级。

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

apiVersion: v1
kind: Pod
metadata:
  labels:
    template-label-key: driver-template-label-value
spec:
  priorityClassName: system-node-critical
  containers:
  - name: test-driver-container
    image: will-be-overwritten
自定义Kubernetes调度器

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

指定调度器名称

用户可以使用spark.kubernetes.scheduler.namespark.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 v3.3.0和Volcano v1.7.0开始,Spark on Kubernetes支持将Volcano作为自定义调度器。以下是安装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作为自定义调度器,用户需要指定以下配置选项:

--conf spark.kubernetes.scheduler.name=volcano
--conf spark.kubernetes.scheduler.volcano.podGroupTemplateFile=/path/to/podgroup-template.yaml
--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使用CRD YAML定义PodGroup规范。

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

apiVersion: scheduling.volcano.sh/v1beta1
kind: PodGroup
spec:
  minMember: 1
  minResources:
    cpu: "2"
    memory: "3Gi"
  priorityClassName: system-node-critical
  queue: default
使用Apache YuniKorn作为自定义调度器

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支持阶段级调度。但这要求启用spark.dynamicAllocation.shuffleTracking.enabled,因为Kubernetes当前不支持外部Shuffle服务。从Kubernetes请求具有不同资源配置的容器的顺序无法保证。需要注意的是,由于动态分配在Kubernetes上需要Shuffle跟踪功能,这意味着使用其他资源配置的先前阶段的执行器可能不会因为它们上有Shuffle数据而处于空闲状态。这可能会占用更多的集群资源,最坏的情况下,如果Kubernetes集群上没有剩余资源,Spark可能会挂起。可以考虑配置spark.dynamicAllocation.shuffleTracking.timeout来设置超时时间,但这可能导致需要重新计算数据(如果确实需要Shuffle数据)。需要注意的是,默认配置文件和自定义ResourceProfiles之间在处理Pod模板资源时存在差异。任何在Pod模板文件中指定的资源仅适用于默认配置文件。如果创建了自定义ResourceProfiles,请确保在其中包含所有必需的资源,因为模板文件中的资源不会传递到自定义ResourceProfiles中。

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

阶段级调度概述

在启用动态分配时,Kubernetes支持阶段级调度。但这要求启用spark.dynamicAllocation.shuffleTracking.enabled,因为Kubernetes当前不支持外部Shuffle服务。从Kubernetes请求具有不同资源配置的容器的顺序无法保证。需要注意的是,由于动态分配在Kubernetes上需要Shuffle跟踪功能,这意味着使用其他资源配置的先前阶段的执行器可能不会因为它们上有Shuffle数据而处于空闲状态。这可能会占用更多的集群资源,最坏的情况下,如果Kubernetes集群上没有剩余资源,Spark可能会挂起。可以考虑配置spark.dynamicAllocation.shuffleTracking.timeout来设置超时时间,但这可能导致需要重新计算数据(如果确实需要Shuffle数据)。需要注意的是,默认配置文件和自定义ResourceProfiles之间在处理Pod模板资源时存在差异。任何在Pod模板文件中指定的资源仅适用于默认配置文件。如果创建了自定义ResourceProfiles,请确保在其中包含所有必需的资源,因为模板文件中的资源不会传递到自定义ResourceProfiles中。

参考链接

你可能感兴趣的:(云计算,spark,spark,kubernetes,大数据)