-
Notifications
You must be signed in to change notification settings - Fork 29.3k
[SPARK-22994][k8s] Use a single image for all Spark containers. #20192
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
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -24,29 +24,11 @@ function error { | |
| exit 1 | ||
| } | ||
|
|
||
| # Detect whether this is a git clone or a Spark distribution and adjust paths | ||
| # accordingly. | ||
| if [ -z "${SPARK_HOME}" ]; then | ||
| SPARK_HOME="$(cd "`dirname "$0"`"/..; pwd)" | ||
| fi | ||
| . "${SPARK_HOME}/bin/load-spark-env.sh" | ||
|
|
||
| if [ -f "$SPARK_HOME/RELEASE" ]; then | ||
| IMG_PATH="kubernetes/dockerfiles" | ||
| SPARK_JARS="jars" | ||
| else | ||
| IMG_PATH="resource-managers/kubernetes/docker/src/main/dockerfiles" | ||
| SPARK_JARS="assembly/target/scala-$SPARK_SCALA_VERSION/jars" | ||
| fi | ||
|
|
||
| if [ ! -d "$IMG_PATH" ]; then | ||
| error "Cannot find docker images. This script must be run from a runnable distribution of Apache Spark." | ||
| fi | ||
|
|
||
| declare -A path=( [spark-driver]="$IMG_PATH/driver/Dockerfile" \ | ||
| [spark-executor]="$IMG_PATH/executor/Dockerfile" \ | ||
| [spark-init]="$IMG_PATH/init-container/Dockerfile" ) | ||
|
|
||
| function image_ref { | ||
| local image="$1" | ||
| local add_repo="${2:-1}" | ||
|
|
@@ -60,35 +42,53 @@ function image_ref { | |
| } | ||
|
|
||
| function build { | ||
| docker build \ | ||
| --build-arg "spark_jars=$SPARK_JARS" \ | ||
| --build-arg "img_path=$IMG_PATH" \ | ||
| -t spark-base \ | ||
| -f "$IMG_PATH/spark-base/Dockerfile" . | ||
| for image in "${!path[@]}"; do | ||
| docker build -t "$(image_ref $image)" -f ${path[$image]} . | ||
| done | ||
| # Detect whether this is a git clone or a Spark distribution and adjust paths | ||
| # accordingly. | ||
| local BUILD_ARGS | ||
| local IMG_PATH | ||
|
|
||
| if [ ! -f "$SPARK_HOME/RELEASE" ]; then | ||
| IMG_PATH=resource-managers/kubernetes/docker/src/main/dockerfiles | ||
| BUILD_ARGS=( | ||
| --build-arg | ||
| img_path=$IMG_PATH | ||
| --build-arg | ||
| spark_jars=assembly/target/scala-$SPARK_SCALA_VERSION/jars | ||
| ) | ||
| else | ||
| # Not passed as an argument to docker, but used to validate the Spark directory. | ||
| IMG_PATH="kubernetes/dockerfiles" | ||
| fi | ||
|
|
||
| local DOCKERFILE=${DOCKERFILE:-"$IMG_PATH/spark/Dockerfile"} | ||
|
|
||
| if [ ! -d "$IMG_PATH" ]; then | ||
| error "Cannot find docker images. This script must be run from a runnable distribution of Apache Spark." | ||
| fi | ||
|
|
||
| docker build "${BUILD_ARGS[@]}" \ | ||
| -t $(image_ref spark) \ | ||
| -f "$DOCKERFILE" . | ||
| } | ||
|
|
||
| function push { | ||
| for image in "${!path[@]}"; do | ||
| docker push "$(image_ref $image)" | ||
| done | ||
| docker push "$(image_ref spark)" | ||
| } | ||
|
|
||
| function usage { | ||
| cat <<EOF | ||
| Usage: $0 [options] [command] | ||
| Builds or pushes the built-in Spark Docker images. | ||
| Builds or pushes the built-in Spark Docker image. | ||
|
|
||
| Commands: | ||
| build Build images. | ||
| push Push images to a registry. Requires a repository address to be provided, both | ||
| when building and when pushing the images. | ||
| build Build image. | ||
| push Push a pre-built image to a registry. Requires a repository address to be provided, | ||
| both when building and when pushing the image. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's better to state explicitly for |
||
|
|
||
| Options: | ||
| -f file Dockerfile to build. By default builds the Dockerfile shipped with Spark. | ||
| -r repo Repository address. | ||
| -t tag Tag to apply to built images, or to identify images to be pushed. | ||
| -t tag Tag to apply to the built image, or to identify the image to be pushed. | ||
| -m Use minikube's Docker daemon. | ||
|
|
||
| Using minikube when building images will do so directly into minikube's Docker daemon. | ||
|
|
@@ -100,10 +100,10 @@ Check the following documentation for more information on using the minikube Doc | |
| https://kubernetes.io/docs/getting-started-guides/minikube/#reusing-the-docker-daemon | ||
|
|
||
| Examples: | ||
| - Build images in minikube with tag "testing" | ||
| - Build image in minikube with tag "testing" | ||
| $0 -m -t testing build | ||
|
|
||
| - Build and push images with tag "v2.3.0" to docker.io/myrepo | ||
| - Build and push image with tag "v2.3.0" to docker.io/myrepo | ||
| $0 -r docker.io/myrepo -t v2.3.0 build | ||
| $0 -r docker.io/myrepo -t v2.3.0 push | ||
| EOF | ||
|
|
@@ -116,10 +116,12 @@ fi | |
|
|
||
| REPO= | ||
| TAG= | ||
| while getopts mr:t: option | ||
| DOCKERFILE= | ||
| while getopts f:mr:t: option | ||
| do | ||
| case "${option}" | ||
| in | ||
| f) DOCKERFILE=${OPTARG};; | ||
| r) REPO=${OPTARG};; | ||
| t) TAG=${OPTARG};; | ||
| m) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -56,14 +56,13 @@ be run in a container runtime environment that Kubernetes supports. Docker is a | |
| frequently used with Kubernetes. With Spark 2.3, there are Dockerfiles provided in the runnable distribution that can be customized | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It should be called out that a single Dockerfile is shipped with Spark. |
||
| and built for your usage. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it worths having a dedicated sub-section here on how to use custom images, e.g., named
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Separate change. I don't even know what you'd write there. The whole "custom image" thing needs to be properly specified first - what exactly is the contract between the submission code and the images, for example.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree that we don't have a solid story around customizing images here. But I do think that we need something clearly telling people that we do support using custom images if they want to and the properties they should use to configure custom images, and better with a submission command example. It just doesn't need to be opinionated on things like the contact you mentioned.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Still, that sounds like something that should be added in a separate change. I'm not changing the customizability of images in this change. And not having a contract means people will have no idea of how to customize images, so you can't even write proper documentation for that.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK, I am fine with adding this in a future change. |
||
|
|
||
| You may build these docker images from sources. | ||
| There is a script, `sbin/build-push-docker-images.sh` that you can use to build and push | ||
| customized Spark distribution images consisting of all the above components. | ||
| You may build these docker images from sources. Spark ships with a `bin/docker-image-tool.sh` script | ||
| that can be used to build and publish the Spark Docker image to use with the Kubernetes backend. | ||
|
|
||
| Example usage is: | ||
|
|
||
| ./sbin/build-push-docker-images.sh -r <repo> -t my-tag build | ||
| ./sbin/build-push-docker-images.sh -r <repo> -t my-tag push | ||
| ./bin/docker-image-tool.sh -r <repo> -t my-tag build | ||
| ./bin/docker-image-tool.sh -r <repo> -t my-tag push | ||
|
|
||
| Docker files are under the `kubernetes/dockerfiles/` directory and can be customized further before | ||
| building using the supplied script, or manually. | ||
|
|
@@ -79,8 +78,7 @@ $ bin/spark-submit \ | |
| --name spark-pi \ | ||
| --class org.apache.spark.examples.SparkPi \ | ||
| --conf spark.executor.instances=5 \ | ||
| --conf spark.kubernetes.driver.container.image=<driver-image> \ | ||
| --conf spark.kubernetes.executor.container.image=<executor-image> \ | ||
| --conf spark.kubernetes.container.image=<spark-image> \ | ||
| local:///path/to/examples.jar | ||
| ``` | ||
|
|
||
|
|
@@ -126,13 +124,7 @@ Those dependencies can be added to the classpath by referencing them with `local | |
| ### Using Remote Dependencies | ||
| When there are application dependencies hosted in remote locations like HDFS or HTTP servers, the driver and executor pods | ||
| need a Kubernetes [init-container](https://kubernetes.io/docs/concepts/workloads/pods/init-containers/) for downloading | ||
| the dependencies so the driver and executor containers can use them locally. This requires users to specify the container | ||
| image for the init-container using the configuration property `spark.kubernetes.initContainer.image`. For example, users | ||
| simply add the following option to the `spark-submit` command to specify the init-container image: | ||
|
|
||
| ``` | ||
| --conf spark.kubernetes.initContainer.image=<init-container image> | ||
| ``` | ||
| the dependencies so the driver and executor containers can use them locally. | ||
|
|
||
| The init-container handles remote dependencies specified in `spark.jars` (or the `--jars` option of `spark-submit`) and | ||
| `spark.files` (or the `--files` option of `spark-submit`). It also handles remotely hosted main application resources, e.g., | ||
|
|
@@ -147,9 +139,7 @@ $ bin/spark-submit \ | |
| --jars https://path/to/dependency1.jar,https://path/to/dependency2.jar | ||
| --files hdfs://host:port/path/to/file1,hdfs://host:port/path/to/file2 | ||
| --conf spark.executor.instances=5 \ | ||
| --conf spark.kubernetes.driver.container.image=<driver-image> \ | ||
| --conf spark.kubernetes.executor.container.image=<executor-image> \ | ||
| --conf spark.kubernetes.initContainer.image=<init-container image> | ||
| --conf spark.kubernetes.container.image=<spark-image> \ | ||
| https://path/to/examples.jar | ||
| ``` | ||
|
|
||
|
|
@@ -322,21 +312,27 @@ specific to Spark on Kubernetes. | |
| </td> | ||
| </tr> | ||
| <tr> | ||
| <td><code>spark.kubernetes.driver.container.image</code></td> | ||
| <td><code>spark.kubernetes.container.image</code></td> | ||
| <td><code>(none)</code></td> | ||
| <td> | ||
| Container image to use for the driver. | ||
| This is usually of the form <code>example.com/repo/spark-driver:v1.0.0</code>. | ||
| This configuration is required and must be provided by the user. | ||
| Container image to use for the Spark application. | ||
| This is usually of the form <code>example.com/repo/spark:v1.0.0</code>. | ||
| This configuration is required and must be provided by the user, unless explicit | ||
| images are provided for each different container type. | ||
| </td> | ||
| </tr> | ||
| <tr> | ||
| <td><code>spark.kubernetes.driver.container.image</code></td> | ||
| <td><code>(value of spark.kubernetes.container.image)</code></td> | ||
| <td> | ||
| Custom container image to use for the driver. | ||
| </td> | ||
| </tr> | ||
| <tr> | ||
| <td><code>spark.kubernetes.executor.container.image</code></td> | ||
| <td><code>(none)</code></td> | ||
| <td><code>(value of spark.kubernetes.container.image)</code></td> | ||
| <td> | ||
| Container image to use for the executors. | ||
| This is usually of the form <code>example.com/repo/spark-executor:v1.0.0</code>. | ||
| This configuration is required and must be provided by the user. | ||
| Custom container image to use for executors. | ||
| </td> | ||
| </tr> | ||
| <tr> | ||
|
|
@@ -643,9 +639,9 @@ specific to Spark on Kubernetes. | |
| </tr> | ||
| <tr> | ||
| <td><code>spark.kubernetes.initContainer.image</code></td> | ||
| <td>(none)</td> | ||
| <td><code>(value of spark.kubernetes.container.image)</code></td> | ||
| <td> | ||
| Container image for the <a href="https://kubernetes.io/docs/concepts/workloads/pods/init-containers/">init-container</a> of the driver and executors for downloading dependencies. This is usually of the form <code>example.com/repo/spark-init:v1.0.0</code>. This configuration is optional and must be provided by the user if any non-container local dependency is used and must be downloaded remotely. | ||
| Custom container image for the init container of both driver and executors. | ||
| </td> | ||
| </tr> | ||
| <tr> | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -29,17 +29,23 @@ private[spark] object Config extends Logging { | |
| .stringConf | ||
| .createWithDefault("default") | ||
|
|
||
| val CONTAINER_IMAGE = | ||
| ConfigBuilder("spark.kubernetes.container.image") | ||
| .doc("Container image to use for Spark containers. Individual container types " + | ||
| "(e.g. driver or executor) can also be configured to use different images if desired, " + | ||
| "by setting the container-specific image name.") | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit:
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why would I mention just one specific way of overriding this? I also have half a mind to just remove this since this documentation is not visible anywhere... |
||
| .stringConf | ||
| .createOptional | ||
|
|
||
| val DRIVER_CONTAINER_IMAGE = | ||
| ConfigBuilder("spark.kubernetes.driver.container.image") | ||
| .doc("Container image to use for the driver.") | ||
| .stringConf | ||
| .createOptional | ||
| .fallbackConf(CONTAINER_IMAGE) | ||
|
|
||
| val EXECUTOR_CONTAINER_IMAGE = | ||
| ConfigBuilder("spark.kubernetes.executor.container.image") | ||
| .doc("Container image to use for the executors.") | ||
| .stringConf | ||
| .createOptional | ||
| .fallbackConf(CONTAINER_IMAGE) | ||
|
|
||
| val CONTAINER_IMAGE_PULL_POLICY = | ||
| ConfigBuilder("spark.kubernetes.container.image.pullPolicy") | ||
|
|
@@ -148,8 +154,7 @@ private[spark] object Config extends Logging { | |
| val INIT_CONTAINER_IMAGE = | ||
| ConfigBuilder("spark.kubernetes.initContainer.image") | ||
| .doc("Image for the driver and executor's init-container for downloading dependencies.") | ||
| .stringConf | ||
| .createOptional | ||
| .fallbackConf(CONTAINER_IMAGE) | ||
|
|
||
| val INIT_CONTAINER_MOUNT_TIMEOUT = | ||
| ConfigBuilder("spark.kubernetes.mountDependencies.timeout") | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -34,8 +34,7 @@ class DriverConfigOrchestratorSuite extends SparkFunSuite { | |
| private val SECRET_MOUNT_PATH = "/etc/secrets/driver" | ||
|
|
||
| test("Base submission steps with a main app resource.") { | ||
| val sparkConf = new SparkConf(false) | ||
| .set(DRIVER_CONTAINER_IMAGE, DRIVER_IMAGE) | ||
| val sparkConf = new SparkConf(false).set(CONTAINER_IMAGE, DRIVER_IMAGE) | ||
| val mainAppResource = JavaMainAppResource("local:///var/apps/jars/main.jar") | ||
| val orchestrator = new DriverConfigOrchestrator( | ||
| APP_ID, | ||
|
|
@@ -55,8 +54,7 @@ class DriverConfigOrchestratorSuite extends SparkFunSuite { | |
| } | ||
|
|
||
| test("Base submission steps without a main app resource.") { | ||
| val sparkConf = new SparkConf(false) | ||
| .set(DRIVER_CONTAINER_IMAGE, DRIVER_IMAGE) | ||
| val sparkConf = new SparkConf(false).set(CONTAINER_IMAGE, DRIVER_IMAGE) | ||
| val orchestrator = new DriverConfigOrchestrator( | ||
| APP_ID, | ||
| LAUNCH_TIME, | ||
|
|
@@ -75,8 +73,8 @@ class DriverConfigOrchestratorSuite extends SparkFunSuite { | |
|
|
||
| test("Submission steps with an init-container.") { | ||
| val sparkConf = new SparkConf(false) | ||
| .set(DRIVER_CONTAINER_IMAGE, DRIVER_IMAGE) | ||
| .set(INIT_CONTAINER_IMAGE, IC_IMAGE) | ||
| .set(CONTAINER_IMAGE, DRIVER_IMAGE) | ||
| .set(INIT_CONTAINER_IMAGE.key, IC_IMAGE) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you still need to set this?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, the test is checking different values for the default and init container images. |
||
| .set("spark.jars", "hdfs://localhost:9000/var/apps/jars/jar1.jar") | ||
| val mainAppResource = JavaMainAppResource("local:///var/apps/jars/main.jar") | ||
| val orchestrator = new DriverConfigOrchestrator( | ||
|
|
@@ -98,7 +96,7 @@ class DriverConfigOrchestratorSuite extends SparkFunSuite { | |
|
|
||
| test("Submission steps with driver secrets to mount") { | ||
| val sparkConf = new SparkConf(false) | ||
| .set(DRIVER_CONTAINER_IMAGE, DRIVER_IMAGE) | ||
| .set(CONTAINER_IMAGE, DRIVER_IMAGE) | ||
| .set(s"$KUBERNETES_DRIVER_SECRETS_PREFIX$SECRET_FOO", SECRET_MOUNT_PATH) | ||
| .set(s"$KUBERNETES_DRIVER_SECRETS_PREFIX$SECRET_BAR", SECRET_MOUNT_PATH) | ||
| val mainAppResource = JavaMainAppResource("local:///var/apps/jars/main.jar") | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"paths" => "values of the following variables?.