This is an automated email from the ASF dual-hosted git repository. dongjoon pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/spark.git
The following commit(s) were added to refs/heads/master by this push: new 4cc8101cb5e0 [SPARK-52830][K8S] Support `spark.kubernetes.(driver|executor).pod.excludedFeatureSteps` 4cc8101cb5e0 is described below commit 4cc8101cb5e0e52af10a2fa4d74696addd95e478 Author: Dongjoon Hyun <dongj...@apache.org> AuthorDate: Wed Jul 16 20:56:51 2025 -0700 [SPARK-52830][K8S] Support `spark.kubernetes.(driver|executor).pod.excludedFeatureSteps` ### What changes were proposed in this pull request? This PR aims to support `spark.kubernetes.(driver|executor).pod.excludedFeatureSteps` configuration. ### Why are the changes needed? Since Apache Spark 3.2, we have been providing `spark.kubernetes.(driver|executor).pod.featureSteps`. - https://github.com/apache/spark/pull/30206 This PR aims to allow users to exclude feature steps selectively by configurations. Please note that this is designed to allow to exclude all steps including both built-in and user-provided steps. ### Does this PR introduce _any_ user-facing change? No because this is a new feature. ### How was this patch tested? Pass the CIs with newly added test cases. ### Was this patch authored or co-authored using generative AI tooling? No. Closes #51522 from dongjoon-hyun/SPARK-52830. Authored-by: Dongjoon Hyun <dongj...@apache.org> Signed-off-by: Dongjoon Hyun <dongj...@apache.org> --- .../main/scala/org/apache/spark/deploy/k8s/Config.scala | 16 ++++++++++++++++ .../deploy/k8s/submit/KubernetesDriverBuilder.scala | 5 ++++- .../cluster/k8s/KubernetesExecutorBuilder.scala | 5 ++++- .../org/apache/spark/deploy/k8s/PodBuilderSuite.scala | 17 +++++++++++++++++ .../k8s/submit/KubernetesDriverBuilderSuite.scala | 4 ++++ .../cluster/k8s/KubernetesExecutorBuilderSuite.scala | 4 ++++ 6 files changed, 49 insertions(+), 2 deletions(-) diff --git a/resource-managers/kubernetes/core/src/main/scala/org/apache/spark/deploy/k8s/Config.scala b/resource-managers/kubernetes/core/src/main/scala/org/apache/spark/deploy/k8s/Config.scala index 4467f73e7056..37edc81991ac 100644 --- a/resource-managers/kubernetes/core/src/main/scala/org/apache/spark/deploy/k8s/Config.scala +++ b/resource-managers/kubernetes/core/src/main/scala/org/apache/spark/deploy/k8s/Config.scala @@ -404,6 +404,14 @@ private[spark] object Config extends Logging { .toSequence .createWithDefault(Nil) + val KUBERNETES_DRIVER_POD_EXCLUDED_FEATURE_STEPS = + ConfigBuilder("spark.kubernetes.driver.pod.excludedFeatureSteps") + .doc("Class names to exclude from driver pod feature steps. Comma separated.") + .version("4.1.0") + .stringConf + .toSequence + .createWithDefault(Nil) + val KUBERNETES_EXECUTOR_POD_FEATURE_STEPS = ConfigBuilder("spark.kubernetes.executor.pod.featureSteps") .doc("Class name of an extra executor pod feature step implementing " + @@ -416,6 +424,14 @@ private[spark] object Config extends Logging { .toSequence .createWithDefault(Nil) + val KUBERNETES_EXECUTOR_POD_EXCLUDED_FEATURE_STEPS = + ConfigBuilder("spark.kubernetes.executor.pod.excludedFeatureSteps") + .doc("Class name to exclude from executor pod feature steps. Comma separated.") + .version("4.1.0") + .stringConf + .toSequence + .createWithDefault(Nil) + val KUBERNETES_EXECUTOR_DECOMMISSION_LABEL = ConfigBuilder("spark.kubernetes.executor.decommissionLabel") .doc("Label to apply to a pod which is being decommissioned." + diff --git a/resource-managers/kubernetes/core/src/main/scala/org/apache/spark/deploy/k8s/submit/KubernetesDriverBuilder.scala b/resource-managers/kubernetes/core/src/main/scala/org/apache/spark/deploy/k8s/submit/KubernetesDriverBuilder.scala index 12626a8676ef..da234762ea1d 100644 --- a/resource-managers/kubernetes/core/src/main/scala/org/apache/spark/deploy/k8s/submit/KubernetesDriverBuilder.scala +++ b/resource-managers/kubernetes/core/src/main/scala/org/apache/spark/deploy/k8s/submit/KubernetesDriverBuilder.scala @@ -72,7 +72,7 @@ class KubernetesDriverBuilder { } } - val features = Seq( + val allFeatures = Seq( new BasicDriverFeatureStep(conf), new DriverKubernetesCredentialsFeatureStep(conf), new DriverServiceFeatureStep(conf), @@ -85,6 +85,9 @@ class KubernetesDriverBuilder { new PodTemplateConfigMapStep(conf), new LocalDirsFeatureStep(conf)) ++ userFeatures + val features = allFeatures.filterNot(f => + conf.get(Config.KUBERNETES_DRIVER_POD_EXCLUDED_FEATURE_STEPS).contains(f.getClass.getName)) + val spec = KubernetesDriverSpec( initialPod, driverPreKubernetesResources = Seq.empty, diff --git a/resource-managers/kubernetes/core/src/main/scala/org/apache/spark/scheduler/cluster/k8s/KubernetesExecutorBuilder.scala b/resource-managers/kubernetes/core/src/main/scala/org/apache/spark/scheduler/cluster/k8s/KubernetesExecutorBuilder.scala index a85e42662b89..2253c07df116 100644 --- a/resource-managers/kubernetes/core/src/main/scala/org/apache/spark/scheduler/cluster/k8s/KubernetesExecutorBuilder.scala +++ b/resource-managers/kubernetes/core/src/main/scala/org/apache/spark/scheduler/cluster/k8s/KubernetesExecutorBuilder.scala @@ -65,7 +65,7 @@ private[spark] class KubernetesExecutorBuilder { } } - val features = Seq( + val allFeatures = Seq( new BasicExecutorFeatureStep(conf, secMgr, resourceProfile), new ExecutorKubernetesCredentialsFeatureStep(conf), new MountSecretsFeatureStep(conf), @@ -74,6 +74,9 @@ private[spark] class KubernetesExecutorBuilder { new HadoopConfExecutorFeatureStep(conf), new LocalDirsFeatureStep(conf)) ++ userFeatures + val features = allFeatures.filterNot(f => + conf.get(Config.KUBERNETES_EXECUTOR_POD_EXCLUDED_FEATURE_STEPS).contains(f.getClass.getName)) + val spec = KubernetesExecutorSpec( initialPod, executorKubernetesResources = Seq.empty) diff --git a/resource-managers/kubernetes/core/src/test/scala/org/apache/spark/deploy/k8s/PodBuilderSuite.scala b/resource-managers/kubernetes/core/src/test/scala/org/apache/spark/deploy/k8s/PodBuilderSuite.scala index 947db5dd41c1..a80381943237 100644 --- a/resource-managers/kubernetes/core/src/test/scala/org/apache/spark/deploy/k8s/PodBuilderSuite.scala +++ b/resource-managers/kubernetes/core/src/test/scala/org/apache/spark/deploy/k8s/PodBuilderSuite.scala @@ -40,6 +40,8 @@ abstract class PodBuilderSuite extends SparkFunSuite { protected def roleSpecificSchedulerNameConf: ConfigEntry[_] + protected def excludedFeatureStepsConf: ConfigEntry[_] + protected def userFeatureStepsConf: ConfigEntry[_] protected def userFeatureStepWithExpectedAnnotation: (String, String) @@ -91,6 +93,21 @@ abstract class PodBuilderSuite extends SparkFunSuite { assert(pod.container.getVolumeMounts.asScala.exists(_.getName == "so_long_two")) } + test("SPARK-52830: exclude a feature step") { + val client = mockKubernetesClient() + val sparkConf = baseConf.clone() + .set(excludedFeatureStepsConf.key, + "org.apache.spark.deploy.k8s.TestStepTwo") + .set(userFeatureStepsConf.key, + "org.apache.spark.deploy.k8s.TestStepTwo," + + "org.apache.spark.deploy.k8s.TestStep") + .set(templateFileConf.key, "template-file.yaml") + val pod = buildPod(sparkConf, client) + verifyPod(pod) + assert(pod.container.getVolumeMounts.asScala.exists(_.getName == "so_long")) + assert(!pod.container.getVolumeMounts.asScala.exists(_.getName == "so_long_two")) + } + test("SPARK-37145: configure a custom test step with base config") { val client = mockKubernetesClient() val sparkConf = baseConf.clone() diff --git a/resource-managers/kubernetes/core/src/test/scala/org/apache/spark/deploy/k8s/submit/KubernetesDriverBuilderSuite.scala b/resource-managers/kubernetes/core/src/test/scala/org/apache/spark/deploy/k8s/submit/KubernetesDriverBuilderSuite.scala index 861b8e0fff94..d3fd5ee5f00c 100644 --- a/resource-managers/kubernetes/core/src/test/scala/org/apache/spark/deploy/k8s/submit/KubernetesDriverBuilderSuite.scala +++ b/resource-managers/kubernetes/core/src/test/scala/org/apache/spark/deploy/k8s/submit/KubernetesDriverBuilderSuite.scala @@ -38,6 +38,10 @@ class KubernetesDriverBuilderSuite extends PodBuilderSuite { Config.KUBERNETES_DRIVER_SCHEDULER_NAME } + override protected def excludedFeatureStepsConf: ConfigEntry[_] = { + Config.KUBERNETES_DRIVER_POD_EXCLUDED_FEATURE_STEPS + } + override protected def userFeatureStepsConf: ConfigEntry[_] = { Config.KUBERNETES_DRIVER_POD_FEATURE_STEPS } diff --git a/resource-managers/kubernetes/core/src/test/scala/org/apache/spark/scheduler/cluster/k8s/KubernetesExecutorBuilderSuite.scala b/resource-managers/kubernetes/core/src/test/scala/org/apache/spark/scheduler/cluster/k8s/KubernetesExecutorBuilderSuite.scala index 17c2d4a938c1..5f0f04da9196 100644 --- a/resource-managers/kubernetes/core/src/test/scala/org/apache/spark/scheduler/cluster/k8s/KubernetesExecutorBuilderSuite.scala +++ b/resource-managers/kubernetes/core/src/test/scala/org/apache/spark/scheduler/cluster/k8s/KubernetesExecutorBuilderSuite.scala @@ -42,6 +42,10 @@ class KubernetesExecutorBuilderSuite extends PodBuilderSuite { Config.KUBERNETES_EXECUTOR_SCHEDULER_NAME } + override protected def excludedFeatureStepsConf: ConfigEntry[_] = { + Config.KUBERNETES_EXECUTOR_POD_EXCLUDED_FEATURE_STEPS + } + override protected def userFeatureStepsConf: ConfigEntry[_] = { Config.KUBERNETES_EXECUTOR_POD_FEATURE_STEPS } --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@spark.apache.org For additional commands, e-mail: commits-h...@spark.apache.org