This is an automated email from the ASF dual-hosted git repository.

sunchao pushed a commit to branch branch-4.x
in repository https://gitbox.apache.org/repos/asf/spark.git


The following commit(s) were added to refs/heads/branch-4.x by this push:
     new a73c92179d0d [SPARK-58202][K8S] Skip driver containerPort declaration 
when the port is 0
a73c92179d0d is described below

commit a73c92179d0db3cf436a976d43f5f5933402c412
Author: zhengchenyu <[email protected]>
AuthorDate: Tue Aug 18 22:07:44 2026 -0700

    [SPARK-58202][K8S] Skip driver containerPort declaration when the port is 0
    
    ### What changes were proposed in this pull request?
    
    `BasicDriverFeatureStep` skips `containerPort` entries whose port is 0.
    
    ### Why are the changes needed?
    
    When we use host network, we want to resolve port conflicts by binding port 
0. But setting `spark.driver.port` / `spark.driver.blockManager.port` / 
`spark.ui.port` / `spark.connect.grpc.binding.port` to 0 makes driver Pod 
creation fail. The error log is as follows:
    
    ```
    Exception in thread "main" 
io.fabric8.kubernetes.client.KubernetesClientException: Failure executing: POST 
at: https://XX.XX.XX.XX:443/api/v1/namespaces/default/pods. Message: Pod 
"xxx-driver" is invalid: [spec.containers[0].ports[0].containerPort: Required 
value, spec.containers[0].ports[1].containerPort: Required value ...
    ```
    BasicExecutorFeatureStep already skips the entry when the port is 0. The 
driver side should follow the same pattern.
    
    > Note: DriverServiceFeatureStep still builds all four ServicePort entries 
without a port != 0 filter, we will fix this in 
https://github.com/apache/spark/pull/57350. For now, we can use below 
configuration to avoid this problem.
    >```
    
>spark.kubernetes.driver.pod.excludedFeatureSteps=org.apache.spark.deploy.k8s.features.DriverServiceFeatureStep
    >spark.kubernetes.executor.useDriverPodIP=true
    >```
    
    ### Does this PR introduce _any_ user-facing change?
    
    No.
    
    ### How was this patch tested?
    
    * Unit tests in `BasicDriverFeatureStepSuite`.
    * Test in kubernetes cluster.
    
    Closes #57349 from zhengchenyu/SPARK-58202.
    
    Authored-by: zhengchenyu <[email protected]>
    Signed-off-by: Chao Sun <[email protected]>
    (cherry picked from commit 1591e2f5bfc61f94c1fe846e499b63eb7d60e7fc)
    Signed-off-by: Chao Sun <[email protected]>
---
 .../k8s/features/BasicDriverFeatureStep.scala      | 34 ++++++++-----------
 .../k8s/features/BasicDriverFeatureStepSuite.scala | 38 ++++++++++++++++++++++
 2 files changed, 52 insertions(+), 20 deletions(-)

diff --git 
a/resource-managers/kubernetes/core/src/main/scala/org/apache/spark/deploy/k8s/features/BasicDriverFeatureStep.scala
 
b/resource-managers/kubernetes/core/src/main/scala/org/apache/spark/deploy/k8s/features/BasicDriverFeatureStep.scala
index 579e5baeffda..3201ab48e86e 100644
--- 
a/resource-managers/kubernetes/core/src/main/scala/org/apache/spark/deploy/k8s/features/BasicDriverFeatureStep.scala
+++ 
b/resource-managers/kubernetes/core/src/main/scala/org/apache/spark/deploy/k8s/features/BasicDriverFeatureStep.scala
@@ -100,30 +100,24 @@ private[spark] class BasicDriverFeatureStep(conf: 
KubernetesDriverConf)
     val driverUIPort = SparkUI.getUIPort(conf.sparkConf)
     val driverSparkConnectServerPort =
       conf.sparkConf.getInt(CONNECT_GRPC_BINDING_PORT, 
DEFAULT_SPARK_CONNECT_SERVER_PORT)
+    // 0 is invalid as kubernetes containerPort request, we shall leave it 
unmounted.
+    val driverContainerPorts = Seq(
+      DRIVER_PORT_NAME -> driverPort,
+      BLOCK_MANAGER_PORT_NAME -> driverBlockManagerPort,
+      UI_PORT_NAME -> driverUIPort,
+      SPARK_CONNECT_SERVER_PORT_NAME -> driverSparkConnectServerPort
+    ).collect { case (name, port) if port != 0 =>
+      new ContainerPortBuilder()
+        .withName(name)
+        .withContainerPort(port)
+        .withProtocol("TCP")
+        .build()
+    }
     val driverContainer = new ContainerBuilder(pod.container)
       
.withName(Option(pod.container.getName).getOrElse(DEFAULT_DRIVER_CONTAINER_NAME))
       .withImage(driverContainerImage)
       .withImagePullPolicy(conf.imagePullPolicy)
-      .addNewPort()
-        .withName(DRIVER_PORT_NAME)
-        .withContainerPort(driverPort)
-        .withProtocol("TCP")
-        .endPort()
-      .addNewPort()
-        .withName(BLOCK_MANAGER_PORT_NAME)
-        .withContainerPort(driverBlockManagerPort)
-        .withProtocol("TCP")
-        .endPort()
-      .addNewPort()
-        .withName(UI_PORT_NAME)
-        .withContainerPort(driverUIPort)
-        .withProtocol("TCP")
-        .endPort()
-      .addNewPort()
-        .withName(SPARK_CONNECT_SERVER_PORT_NAME)
-        .withContainerPort(driverSparkConnectServerPort)
-        .withProtocol("TCP")
-        .endPort()
+      .addAllToPorts(driverContainerPorts.asJava)
       .addNewEnv()
         .withName(ENV_SPARK_USER)
         .withValue(Utils.getCurrentUserName())
diff --git 
a/resource-managers/kubernetes/core/src/test/scala/org/apache/spark/deploy/k8s/features/BasicDriverFeatureStepSuite.scala
 
b/resource-managers/kubernetes/core/src/test/scala/org/apache/spark/deploy/k8s/features/BasicDriverFeatureStepSuite.scala
index 70e2239205ae..fce22a28c6d0 100644
--- 
a/resource-managers/kubernetes/core/src/test/scala/org/apache/spark/deploy/k8s/features/BasicDriverFeatureStepSuite.scala
+++ 
b/resource-managers/kubernetes/core/src/test/scala/org/apache/spark/deploy/k8s/features/BasicDriverFeatureStepSuite.scala
@@ -475,6 +475,44 @@ class BasicDriverFeatureStepSuite extends SparkFunSuite {
     assert(amountAndFormat(limits("memory")) === "5500Mi")
   }
 
+  test("SPARK-58202: containerPort entries are skipped when the corresponding 
Spark port is 0") {
+    val sparkConf = new SparkConf()
+      .set(CONTAINER_IMAGE, "spark-driver:latest")
+      .set(KUBERNETES_DRIVER_POD_NAME, "spark-driver-pod")
+      .set(DRIVER_PORT, 0)
+      .set(DRIVER_BLOCK_MANAGER_PORT, 0)
+      .set(UI_PORT, 0)
+      .set(CONNECT_GRPC_BINDING_PORT, "0")
+    val kubernetesConf: KubernetesDriverConf = 
KubernetesTestConf.createDriverConf(
+      sparkConf = sparkConf,
+      environment = DRIVER_ENVS,
+      annotations = DRIVER_ANNOTATIONS)
+
+    val featureStep = new BasicDriverFeatureStep(kubernetesConf)
+    val configuredPod = featureStep.configurePod(SparkPod.initialPod())
+    assert(configuredPod.container.getPorts.isEmpty)
+  }
+
+  test("SPARK-58202: containerPort entries include only ports with non-zero 
values") {
+    val sparkConf = new SparkConf()
+      .set(CONTAINER_IMAGE, "spark-driver:latest")
+      .set(KUBERNETES_DRIVER_POD_NAME, "spark-driver-pod")
+      .set(DRIVER_PORT, 9000)
+      .set(DRIVER_BLOCK_MANAGER_PORT, 0)
+      .set(UI_PORT, 4040)
+      .set(CONNECT_GRPC_BINDING_PORT, "0")
+    val kubernetesConf: KubernetesDriverConf = 
KubernetesTestConf.createDriverConf(
+      sparkConf = sparkConf,
+      environment = DRIVER_ENVS,
+      annotations = DRIVER_ANNOTATIONS)
+
+    val featureStep = new BasicDriverFeatureStep(kubernetesConf)
+    val configuredPod = featureStep.configurePod(SparkPod.initialPod())
+    val portsByName = configuredPod.container.getPorts.asScala
+      .map(cp => cp.getName -> cp.getContainerPort).toMap
+    assert(portsByName === Map(DRIVER_PORT_NAME -> 9000, UI_PORT_NAME -> 4040))
+  }
+
 
   def containerPort(name: String, portNumber: Int): ContainerPort =
     new ContainerPortBuilder()


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to