Skip to content

[SPARK-23146][K8S] Support client mode. #21748

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 29 commits into from

Conversation

mccheah
Copy link
Contributor

@mccheah mccheah commented Jul 11, 2018

What changes were proposed in this pull request?

Support client mode for the Kubernetes scheduler.

Client mode works more or less identically to cluster mode. However, in client mode, the Spark Context needs to be manually bootstrapped with certain properties which would have otherwise been set up by spark-submit in cluster mode. Specifically:

  • If the user doesn't provide a driver pod name, we don't add an owner reference. This is for usage when the driver is not running in a pod in the cluster. In such a case, the driver can only provide a best effort to clean up the executors when the driver exits, but cleaning up the resources is not guaranteed. The executor JVMs should exit if the driver JVM exits, but the pods will still remain in the cluster in a COMPLETED or FAILED state.
  • The user must provide a host (spark.driver.host) and port (spark.driver.port) that the executors can connect to. When using spark-submit in cluster mode, spark-submit generates the headless service automatically; in client mode, the user is responsible for setting up their own connectivity.

We also change the authentication configuration prefixes for client mode.

How was this patch tested?

Adding an integration test to exercise client mode support.

Client mode works more or less identically to cluster mode. However, in client mode, the Spark Context needs to be manually bootstrapped with certain properties which would have otherwise been set up by spark-submit in cluster mode. Specifically:

- The user must provide a pod name for the driver. This implies that all drivers in client mode must be running inside a pod. This pod is primarily used to create the owner reference graph so that executors are not orphaned if the driver pod is deleted.
- The user must provide a host (spark.driver.host) and port (spark.driver.port) that the executors can connect to. When using spark-submit in cluster mode, spark-submit generates the headless service automatically; in client mode, the user is responsible for setting up their own connectivity.
@mccheah
Copy link
Contributor Author

mccheah commented Jul 11, 2018

TODO - finish verifying the integration test, and docs.

@mccheah
Copy link
Contributor Author

mccheah commented Jul 11, 2018

test this please

@SparkQA
Copy link

SparkQA commented Jul 11, 2018

Test build #92869 has finished for PR 21748 at commit 19618aa.

  • This patch passes all tests.
  • This patch merges cleanly.
  • This patch adds no public classes.

@mccheah mccheah changed the title [SPARK-23146] Support client mode. [SPARK-23146][K8S] Support client mode. Jul 11, 2018
@mccheah
Copy link
Contributor Author

mccheah commented Jul 11, 2018

retest this please

@SparkQA
Copy link

SparkQA commented Jul 11, 2018

@SparkQA
Copy link

SparkQA commented Jul 11, 2018

Test build #92873 has finished for PR 21748 at commit 19618aa.

  • This patch passes all tests.
  • This patch merges cleanly.
  • This patch adds no public classes.

@SparkQA
Copy link

SparkQA commented Jul 11, 2018

Kubernetes integration test status failure
URL: https://amplab.cs.berkeley.edu/jenkins/job/testing-k8s-prb-make-spark-distribution-unified/861/

@SparkQA
Copy link

SparkQA commented Jul 11, 2018

Test build #92875 has finished for PR 21748 at commit 94ed1cc.

  • This patch fails to build.
  • This patch merges cleanly.
  • This patch adds no public classes.

@SparkQA
Copy link

SparkQA commented Jul 11, 2018

Test build #92878 has finished for PR 21748 at commit 560993e.

  • This patch fails to build.
  • This patch merges cleanly.
  • This patch adds no public classes.

@SparkQA
Copy link

SparkQA commented Jul 11, 2018

Test build #92879 has finished for PR 21748 at commit e961fd3.

  • This patch fails to build.
  • This patch merges cleanly.
  • This patch adds no public classes.

@SparkQA
Copy link

SparkQA commented Jul 11, 2018

Test build #92880 has finished for PR 21748 at commit a00561f.

  • This patch fails to build.
  • This patch merges cleanly.
  • This patch adds no public classes.

@SparkQA
Copy link

SparkQA commented Jul 11, 2018

Test build #92881 has finished for PR 21748 at commit a2609b0.

  • This patch fails to build.
  • This patch merges cleanly.
  • This patch adds no public classes.

@SparkQA
Copy link

SparkQA commented Jul 11, 2018

Test build #92882 has finished for PR 21748 at commit 97f1284.

  • This patch fails to build.
  • This patch merges cleanly.
  • This patch adds no public classes.

@mccheah
Copy link
Contributor Author

mccheah commented Jul 11, 2018

retest this please

@SparkQA
Copy link

SparkQA commented Jul 11, 2018

Test build #92884 has finished for PR 21748 at commit 97f1284.

  • This patch fails to build.
  • This patch merges cleanly.
  • This patch adds no public classes.

@SparkQA
Copy link

SparkQA commented Jul 11, 2018

Test build #92887 has finished for PR 21748 at commit 2205220.

  • This patch fails to build.
  • This patch merges cleanly.
  • This patch adds the following public classes (experimental):
  • public class JavaSummarizerExample
  • trait ComplexTypeMergingExpression extends Expression
  • sealed trait MultipleWatermarkPolicy
  • case class WatermarkTracker(policy: MultipleWatermarkPolicy) extends Logging

@shaneknapp
Copy link
Contributor

i'm going to kill the ubuntu build and reboot the worker. i'll retrigger when it's back.

and your spark driver's port to `spark.driver.port`.
driver pod to be routable from the executors by a stable hostname. When deploying your headless service, ensure that
the service's label selector will only match the driver pod and no other pods; it is recommended to assign your driver
pod a sufficiently unique label and to use that label in the node selector of the headless service. Specify the driver's
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/node selector/label selector/.

server fails for any reason, these pods will remain in the cluster. The executor processes should exit when they cannot
reach the driver, so the executor pods should not consume resources in the cluster after your application exits.
The driver will look for a pod with the given name in the namespace specified by `spark.kubernetes.namespace`, and
all executor pods will have their owner reference field set to point to that pod. Be careful to avoid setting the
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/all executor pods will have their owner reference field set/a OwnerReference point to that pod will be added to each of the executor pods..

The driver will look for a pod with the given name in the namespace specified by `spark.kubernetes.namespace`, and
all executor pods will have their owner reference field set to point to that pod. Be careful to avoid setting the
owner reference to a pod that is not actually that driver pod, or else the executors may be terminated prematurely when
the wrong pod is terminated.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/terminated/deleted/.

actually running in a pod, keep in mind that the executor pods may not be deleted from the cluster when the application
exits. The Spark scheduler attempts to delete these pods, but if the network request to the API server fails for any
reason, these pods will remain in the cluster. The executor processes should exit when they cannot reach the driver, so
the executor pods should not consume resources in the cluster after your application exits.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/should not consume resources/should not consume compute resources (cpus and memory)/.

reach the driver, so the executor pods should not consume resources in the cluster after your application exits.
The driver will look for a pod with the given name in the namespace specified by `spark.kubernetes.namespace`, and
all executor pods will have their owner reference field set to point to that pod. Be careful to avoid setting the
owner reference to a pod that is not actually that driver pod, or else the executors may be terminated prematurely when
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/owner reference/OwnerReference/ for consistency.

If your application is not running inside a pod, or if `spark.driver.pod.name` is not set when your application is
actually running in a pod, keep in mind that the executor pods may not be deleted from the cluster when the application
exits. The Spark scheduler attempts to delete these pods, but if the network request to the API server fails for any
reason, these pods will remain in the cluster. The executor processes should exit when they cannot reach the driver, so
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/these pods will remain in the cluster/these pods may not get deleted properly/. There's a pod-specific GC that deletes terminated pods based on a cluster-wide capacity (by default 12500 pods). It sorts those pods by creation timestamp before deleting them. But this is unpredictable.

@SparkQA
Copy link

SparkQA commented Jul 20, 2018

@SparkQA
Copy link

SparkQA commented Jul 20, 2018

Kubernetes integration test status success
URL: https://amplab.cs.berkeley.edu/jenkins/job/testing-k8s-prb-make-spark-distribution-unified/1180/

@mccheah
Copy link
Contributor Author

mccheah commented Jul 20, 2018

@liyinan926 did some of my own edits on top of your suggestions for docs wording on the latest patch.

@SparkQA
Copy link

SparkQA commented Jul 20, 2018

Test build #93358 has finished for PR 21748 at commit d90f753.

  • This patch passes all tests.
  • This patch merges cleanly.
  • This patch adds no public classes.

@mccheah
Copy link
Contributor Author

mccheah commented Jul 20, 2018

test this please

@SparkQA
Copy link

SparkQA commented Jul 20, 2018

Test build #93359 has finished for PR 21748 at commit 001a525.

  • This patch passes all tests.
  • This patch merges cleanly.
  • This patch adds no public classes.

@mccheah
Copy link
Contributor Author

mccheah commented Jul 20, 2018

Anyone know what's happening with this:

[error] /home/jenkins/workspace/testing-k8s-prb-make-spark-distribution-unified/external/avro/src/test/scala/org/apache/spark/sql/avro/SerializableSchemaSuite.scala:39: Symbol 'term org.scalacheck' is missing from the classpath.
[error] This symbol is required by 'method org.scalatest.prop.Configuration.getParams'.
[error] Make sure that term scalacheck is in your classpath and check for conflicting dependencies with `-Ylog-classpath`.
[error] A full rebuild may help if 'Configuration.class' was compiled against an incompatible version of org.
[error]     serializer.deserialize[Any](serialized) match {
[error]                                ^
[error] one error found
[error] Compile failed at Jul 20, 2018 12:33:14 PM [1.370s]

@shaneknapp

@SparkQA
Copy link

SparkQA commented Jul 20, 2018

Test build #93361 has finished for PR 21748 at commit 72c96e0.

  • This patch passes all tests.
  • This patch merges cleanly.
  • This patch adds no public classes.

@mccheah
Copy link
Contributor Author

mccheah commented Jul 20, 2018

Never mind, think it's recovering now.

@liyinan926
Copy link
Contributor

LGTM for the docs updates.

@SparkQA
Copy link

SparkQA commented Jul 20, 2018

Test build #93360 has finished for PR 21748 at commit 72c96e0.

  • This patch passes all tests.
  • This patch merges cleanly.
  • This patch adds no public classes.

@SparkQA
Copy link

SparkQA commented Jul 20, 2018

Test build #93357 has finished for PR 21748 at commit 086747e.

  • This patch passes all tests.
  • This patch does not merge cleanly.
  • This patch adds no public classes.

@mccheah
Copy link
Contributor Author

mccheah commented Jul 23, 2018

Merging in a few hours if no additional comments are raised.

Copy link
Member

@felixcheung felixcheung left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! minor goodness for documentation/example IMO would be great to have later

driver pod to be routable from the executors by a stable hostname. When deploying your headless service, ensure that
the service's label selector will only match the driver pod and no other pods; it is recommended to assign your driver
pod a sufficiently unique label and to use that label in the label selector of the headless service. Specify the driver's
hostname via `spark.driver.host` and your spark driver's port to `spark.driver.port`.
Copy link
Member

@felixcheung felixcheung Jul 24, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mccheah as for your comment #21748 (comment) so this manual setup is ok, right?

there are some level of complexity here - perhaps a quick follow up of some sample template/kubectl commands would be helpful

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah manual setup is fine for now. Think additional docs around how to do all this can be a separate PR.

actually running in a pod, keep in mind that the executor pods may not be properly deleted from the cluster when the
application exits. The Spark scheduler attempts to delete these pods, but if the network request to the API server fails
for any reason, these pods will remain in the cluster. The executor processes should exit when they cannot reach the
driver, so the executor pods should not consume compute resources (cpu and memory) in the cluster after your application
Copy link
Member

@felixcheung felixcheung Jul 24, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

executor processes should exit when they cannot reach the driver
what's the time out value? is it configurable?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unclear, it triggers in the onDisconnected event so I think there's a persistent socket connection that's dropped that causes the exit. So, it should more or less be instantaneous.

Some(new File(Config.KUBERNETES_SERVICE_ACCOUNT_CA_CRT_PATH)))
} else {
(KUBERNETES_AUTH_CLIENT_MODE_PREFIX,
masterURL.substring("k8s://".length()),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought there's some function for parsing the k8s master url?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can make such a helper function, currently this logic is done here and in KubernetesClientApplication

@mccheah
Copy link
Contributor Author

mccheah commented Jul 25, 2018

Ok after the next build passes I'm going to merge immediately. Thanks for the review.

@SparkQA
Copy link

SparkQA commented Jul 25, 2018

@SparkQA
Copy link

SparkQA commented Jul 25, 2018

Test build #93551 has finished for PR 21748 at commit ded1ff6.

  • This patch passes all tests.
  • This patch merges cleanly.
  • This patch adds no public classes.

@SparkQA
Copy link

SparkQA commented Jul 25, 2018

Kubernetes integration test status success
URL: https://amplab.cs.berkeley.edu/jenkins/job/testing-k8s-prb-make-spark-distribution-unified/1317/

@asfgit asfgit closed this in 571a6f0 Jul 25, 2018
@ifilonenko
Copy link
Contributor

ifilonenko commented Jul 25, 2018

@mccheah the integration tests did not include the ClientModeTestsSuite. Can you add with ClientModeTestsSuite to the KuberneteSuite else, the PRB doesn't actually test the client mode support accurately.

.withLabels(labels.asJava)
.endMetadata()
.withNewSpec()
.withServiceAccountName("default")
Copy link
Contributor

@skonto skonto Jul 27, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mccheah if people use spark-rbac.yaml this will fail. It fails for me. Shouldnt be hardcoded.
Error: "User "system:serviceaccount:spark:default" cannot get pods in the namespace "spark"."

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup we can fix this

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there a JIRA?

Copy link
Contributor

@skonto skonto Jul 29, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mccheah mccheah deleted the k8s-client-mode branch July 27, 2018 18:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants