shazebkhan1 commented on PR #58283:
URL: https://github.com/apache/spark/pull/58283#issuecomment-5476360272

   Hi @dongjoon-hyun,
   
   We wanted to share our experience with SPARK-53944 and also report a related 
issue that we discovered during testing.
   
   **SPARK-53944 — Backported and validated on Spark 3.5.2**
   
   We cherry-picked the changes from PRs #52650, #52923, and #52954 
(`Config.scala`, `BasicExecutorFeatureStep.scala`, and `SparkContext.scala`) 
onto a clean Spark 3.5.2 (`v3.5.2`) base. We also included the SPARK-57351 
default-to-true change from PR #56412.
   
   We rebuilt both `spark-core` and `spark-kubernetes` JARs, deployed the 
patched artifacts, and confirmed the following:
   
   * Executor pods now connect directly to the driver pod IP instead of using 
the driver Service hostname.
   * The NXDOMAIN queries for the driver Service name are no longer present in 
the CoreDNS logs.
   
   The fix works as expected. Thank you for the work on this.
   
   **New issue — API server NXDOMAIN queries from the driver pod**
   
   After resolving the executor-to-driver DNS issue, we observed another set of 
NXDOMAIN queries in CoreDNS. These queries originate from the driver pod itself 
when it communicates with the Kubernetes API server.
   
   For example:
   
   ```text
   NXDOMAIN  kubernetes.default.svc.default.svc.cluster.local.
   NXDOMAIN  kubernetes.default.svc.svc.cluster.local.
   NOERROR   kubernetes.default.svc.cluster.local.
   ```
   
   This pattern occurs repeatedly during API server communication.
   
   The behavior appears to be related to the `ndots:5` resolver configuration. 
Since `kubernetes.default.svc` contains only two dots, the resolver first 
appends the search domains from `/etc/resolv.conf` before trying the name as an 
absolute domain. This results in unnecessary NXDOMAIN queries before the 
correct name is resolved.
   
   **Root cause**
   
   `SparkKubernetesClientFactory.createKubernetesClient()` first calls 
Fabric8's `autoConfigure()`. When running inside Kubernetes, Fabric8 correctly 
detects the in-cluster environment using `KUBERNETES_SERVICE_HOST` and 
`KUBERNETES_SERVICE_PORT` and configures the API server using the in-cluster 
IP, for example:
   
   ```text
   https://10.96.0.1:443
   ```
   
   However, Spark then unconditionally overrides this configuration using:
   
   ```scala
   .withMasterUrl(master)
   ```
   
   where `master` defaults to:
   
   ```scala
   val KUBERNETES_MASTER_INTERNAL_URL = "https://kubernetes.default.svc";
   ```
   
   This effectively overrides Fabric8's in-cluster configuration and forces the 
client to use the Kubernetes Service hostname instead of the API server IP.
   
   We also observed that Fabric8's `IpAddressMatcher` internally calls 
`InetAddress.getByName()` on this hostname, resulting in additional DNS lookups.
   
   We have confirmed that this behavior is present in Spark 3.5.x, 
`branch-4.1`, and the current master (5.0-SNAPSHOT).
   
   This issue is separate from SPARK-53944: SPARK-53944 addresses 
executor-to-driver connectivity, whereas this issue affects 
driver-to-Kubernetes API server connectivity.
   
   **Proposed fix**
   
   In `SparkKubernetesClientFactory.scala`, we propose skipping 
`.withMasterUrl(master)` when both of the following conditions are true:
   
   1. `KUBERNETES_SERVICE_HOST` is present, indicating that the driver is 
running inside Kubernetes.
   2. `master` is the default `KUBERNETES_MASTER_INTERNAL_URL`, meaning that 
the user has not configured a custom master URL.
   
   In this case, Fabric8's `autoConfigure()` has already configured the correct 
in-cluster API server IP, so there is no need to override it.
   
   The proposed change is:
   
   ```scala
   val baseConfig = new ConfigBuilder(autoConfigure(kubeContext.orNull))
     .withApiVersion("v1")
   
   // When running in-cluster with the default master URL, Fabric8 
autoConfigure() has already
   // configured the API server using KUBERNETES_SERVICE_HOST / 
KUBERNETES_SERVICE_PORT.
   // Overriding it with the hostname causes ndots:5 search-domain expansion 
and unnecessary
   // DNS lookups on API server calls. Skip the override so the in-cluster IP 
is used directly.
   val configWithMaster =
     if (sys.env.contains("KUBERNETES_SERVICE_HOST") &&
         master == KUBERNETES_MASTER_INTERNAL_URL) {
       logInfo(
         "Running in-cluster with default master URL; using API server IP from 
" +
         "KUBERNETES_SERVICE_HOST to avoid unnecessary DNS lookups."
       )
       baseConfig
     } else {
       baseConfig.withMasterUrl(master)
     }
   
   val config = configWithMaster
     .withRequestTimeout(clientType.requestTimeout(sparkConf))
     // ... rest unchanged
   ```
   
   **Compatibility**
   
   We believe this change should be safe for existing use cases:
   
   * **External-cluster deployments:** `KUBERNETES_SERVICE_HOST` is not 
present, so `withMasterUrl(master)` is still called.
   * **Custom `spark.kubernetes.driver.master`:** The master value differs from 
`KUBERNETES_MASTER_INTERNAL_URL`, so `withMasterUrl(master)` is still called.
   * **Non-Kubernetes deployments:** There is no change in behavior.
   
   Would the team be open to a PR for this change? We would be happy to 
contribute it against `master`.
   
   Thanks in advance for your feedback.
   
   Best regards,
   Shazeb Khan


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


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

Reply via email to