Add support for dynamic allocation via shuffle tracking (#976)
This commit is contained in:
parent
555c27a487
commit
3ca74728a3
114
docs/api-docs.md
114
docs/api-docs.md
|
@ -586,6 +586,21 @@ SparkUIConfiguration
|
||||||
<p>SparkUIOptions allows configuring the Service and the Ingress to expose the sparkUI</p>
|
<p>SparkUIOptions allows configuring the Service and the Ingress to expose the sparkUI</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<code>dynamicAllocation</code></br>
|
||||||
|
<em>
|
||||||
|
<a href="#sparkoperator.k8s.io/v1beta2.DynamicAllocation">
|
||||||
|
DynamicAllocation
|
||||||
|
</a>
|
||||||
|
</em>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<em>(Optional)</em>
|
||||||
|
<p>DynamicAllocation configures dynamic allocation that becomes available for the Kubernetes
|
||||||
|
scheduleer backend since Spark 3.0.</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -969,6 +984,86 @@ executors to connect to the driver.</p>
|
||||||
<p>
|
<p>
|
||||||
<p>DriverState tells the current state of a spark driver.</p>
|
<p>DriverState tells the current state of a spark driver.</p>
|
||||||
</p>
|
</p>
|
||||||
|
<h3 id="sparkoperator.k8s.io/v1beta2.DynamicAllocation">DynamicAllocation
|
||||||
|
</h3>
|
||||||
|
<p>
|
||||||
|
(<em>Appears on:</em>
|
||||||
|
<a href="#sparkoperator.k8s.io/v1beta2.SparkApplicationSpec">SparkApplicationSpec</a>)
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<p>DynamicAllocation contains configuration options for dynamic allocation.</p>
|
||||||
|
</p>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Field</th>
|
||||||
|
<th>Description</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<code>enabled</code></br>
|
||||||
|
<em>
|
||||||
|
bool
|
||||||
|
</em>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<p>Enabled controls whether dynamic allocation is enabled or not.</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<code>initialExecutors</code></br>
|
||||||
|
<em>
|
||||||
|
int32
|
||||||
|
</em>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<em>(Optional)</em>
|
||||||
|
<p>InitialExecutors is the initial number of executors to request. If .spec.executor.instances
|
||||||
|
is also set, the initial number of executors is set to the bigger of that and this option.</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<code>minExecutors</code></br>
|
||||||
|
<em>
|
||||||
|
int32
|
||||||
|
</em>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<em>(Optional)</em>
|
||||||
|
<p>MinExecutors is the lower bound for the number of executors if dynamic allocation is enabled.</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<code>maxExecutors</code></br>
|
||||||
|
<em>
|
||||||
|
int32
|
||||||
|
</em>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<em>(Optional)</em>
|
||||||
|
<p>MaxExecutors is the upper bound for the number of executors if dynamic allocation is enabled.</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<code>shuffleTrackingTimeout</code></br>
|
||||||
|
<em>
|
||||||
|
int64
|
||||||
|
</em>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<em>(Optional)</em>
|
||||||
|
<p>ShuffleTrackingTimeout controls the timeout in milliseconds for executors that are holding
|
||||||
|
shuffle data if shuffle tracking is enabled (true by default if dynamic allocation is enabled).</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
<h3 id="sparkoperator.k8s.io/v1beta2.ExecutorSpec">ExecutorSpec
|
<h3 id="sparkoperator.k8s.io/v1beta2.ExecutorSpec">ExecutorSpec
|
||||||
</h3>
|
</h3>
|
||||||
<p>
|
<p>
|
||||||
|
@ -2072,6 +2167,21 @@ SparkUIConfiguration
|
||||||
<p>SparkUIOptions allows configuring the Service and the Ingress to expose the sparkUI</p>
|
<p>SparkUIOptions allows configuring the Service and the Ingress to expose the sparkUI</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<code>dynamicAllocation</code></br>
|
||||||
|
<em>
|
||||||
|
<a href="#sparkoperator.k8s.io/v1beta2.DynamicAllocation">
|
||||||
|
DynamicAllocation
|
||||||
|
</a>
|
||||||
|
</em>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<em>(Optional)</em>
|
||||||
|
<p>DynamicAllocation configures dynamic allocation that becomes available for the Kubernetes
|
||||||
|
scheduleer backend since Spark 3.0.</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<h3 id="sparkoperator.k8s.io/v1beta2.SparkApplicationStatus">SparkApplicationStatus
|
<h3 id="sparkoperator.k8s.io/v1beta2.SparkApplicationStatus">SparkApplicationStatus
|
||||||
|
@ -2582,7 +2692,7 @@ string
|
||||||
<a href="#sparkoperator.k8s.io/v1beta2.SparkApplicationSpec">SparkApplicationSpec</a>)
|
<a href="#sparkoperator.k8s.io/v1beta2.SparkApplicationSpec">SparkApplicationSpec</a>)
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<p>Specific SparkUI config parameters</p>
|
<p>SparkUIConfiguration is for driver UI specific configuration parameters.</p>
|
||||||
</p>
|
</p>
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
|
@ -2636,5 +2746,5 @@ map[string]string
|
||||||
<hr/>
|
<hr/>
|
||||||
<p><em>
|
<p><em>
|
||||||
Generated with <code>gen-crd-api-reference-docs</code>
|
Generated with <code>gen-crd-api-reference-docs</code>
|
||||||
on git commit <code>f313873</code>.
|
on git commit <code>555c27a</code>.
|
||||||
</em></p>
|
</em></p>
|
||||||
|
|
|
@ -34,6 +34,7 @@ The Kubernetes Operator for Apache Spark ships with a command-line tool called `
|
||||||
* [Using Container LifeCycle Hooks](#using-container-lifecycle-hooks)
|
* [Using Container LifeCycle Hooks](#using-container-lifecycle-hooks)
|
||||||
* [Python Support](#python-support)
|
* [Python Support](#python-support)
|
||||||
* [Monitoring](#monitoring)
|
* [Monitoring](#monitoring)
|
||||||
|
* [Dynamic Allocation](#dynamic-allocation)
|
||||||
* [Working with SparkApplications](#working-with-sparkapplications)
|
* [Working with SparkApplications](#working-with-sparkapplications)
|
||||||
* [Creating a New SparkApplication](#creating-a-new-sparkapplication)
|
* [Creating a New SparkApplication](#creating-a-new-sparkapplication)
|
||||||
* [Deleting a SparkApplication](#deleting-a-sparkapplication)
|
* [Deleting a SparkApplication](#deleting-a-sparkapplication)
|
||||||
|
@ -638,6 +639,21 @@ spec:
|
||||||
|
|
||||||
The operator automatically adds the annotations such as `prometheus.io/scrape=true` on the driver and/or executor pods (depending on the values of `.spec.monitoring.exposeDriverMetrics` and `.spec.monitoring.exposeExecutorMetrics`) so the metrics exposed on the pods can be scraped by the Prometheus server in the same cluster.
|
The operator automatically adds the annotations such as `prometheus.io/scrape=true` on the driver and/or executor pods (depending on the values of `.spec.monitoring.exposeDriverMetrics` and `.spec.monitoring.exposeExecutorMetrics`) so the metrics exposed on the pods can be scraped by the Prometheus server in the same cluster.
|
||||||
|
|
||||||
|
### Dynamic Allocation
|
||||||
|
|
||||||
|
The operator supports a limited form of [Spark Dynamic Resource Allocation](http://spark.apache.org/docs/latest/job-scheduling.html#dynamic-resource-allocation) through the shuffle tracking enhancement introduced in Spark 3.0.0 *without needing an external shuffle service* (not available in the Kubernetes mode). See this [issue](https://issues.apache.org/jira/browse/SPARK-27963) for detais on the enhancement. To enable this limited form of dynamic allocation, follow the example below:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
spec:
|
||||||
|
dynamicAllocation:
|
||||||
|
enabled: true
|
||||||
|
initialExecutors: 2
|
||||||
|
minExecutors: 2
|
||||||
|
maxExecutors: 10
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that if dynamic allocation is enabled, the number of executors to request initially is set to the bigger of `.spec.dynamicAllocation.initialExecutors` and `.spec.executor.instances` if both are set.
|
||||||
|
|
||||||
## Working with SparkApplications
|
## Working with SparkApplications
|
||||||
|
|
||||||
### Creating a New SparkApplication
|
### Creating a New SparkApplication
|
||||||
|
|
|
@ -1800,6 +1800,23 @@ spec:
|
||||||
type: object
|
type: object
|
||||||
type: array
|
type: array
|
||||||
type: object
|
type: object
|
||||||
|
dynamicAllocation:
|
||||||
|
properties:
|
||||||
|
enabled:
|
||||||
|
type: boolean
|
||||||
|
initialExecutors:
|
||||||
|
format: int32
|
||||||
|
type: integer
|
||||||
|
maxExecutors:
|
||||||
|
format: int32
|
||||||
|
type: integer
|
||||||
|
minExecutors:
|
||||||
|
format: int32
|
||||||
|
type: integer
|
||||||
|
shuffleTrackingTimeout:
|
||||||
|
format: int64
|
||||||
|
type: integer
|
||||||
|
type: object
|
||||||
executor:
|
executor:
|
||||||
properties:
|
properties:
|
||||||
affinity:
|
affinity:
|
||||||
|
|
|
@ -1786,6 +1786,23 @@ spec:
|
||||||
type: object
|
type: object
|
||||||
type: array
|
type: array
|
||||||
type: object
|
type: object
|
||||||
|
dynamicAllocation:
|
||||||
|
properties:
|
||||||
|
enabled:
|
||||||
|
type: boolean
|
||||||
|
initialExecutors:
|
||||||
|
format: int32
|
||||||
|
type: integer
|
||||||
|
maxExecutors:
|
||||||
|
format: int32
|
||||||
|
type: integer
|
||||||
|
minExecutors:
|
||||||
|
format: int32
|
||||||
|
type: integer
|
||||||
|
shuffleTrackingTimeout:
|
||||||
|
format: int64
|
||||||
|
type: integer
|
||||||
|
type: object
|
||||||
executor:
|
executor:
|
||||||
properties:
|
properties:
|
||||||
affinity:
|
affinity:
|
||||||
|
|
|
@ -276,6 +276,10 @@ type SparkApplicationSpec struct {
|
||||||
// SparkUIOptions allows configuring the Service and the Ingress to expose the sparkUI
|
// SparkUIOptions allows configuring the Service and the Ingress to expose the sparkUI
|
||||||
// +optional
|
// +optional
|
||||||
SparkUIOptions *SparkUIConfiguration `json:"sparkUIOptions,omitempty"`
|
SparkUIOptions *SparkUIConfiguration `json:"sparkUIOptions,omitempty"`
|
||||||
|
// DynamicAllocation configures dynamic allocation that becomes available for the Kubernetes
|
||||||
|
// scheduleer backend since Spark 3.0.
|
||||||
|
// +optional
|
||||||
|
DynamicAllocation *DynamicAllocation `json:"dynamicAllocation,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// BatchSchedulerConfiguration used to configure how to batch scheduling Spark Application
|
// BatchSchedulerConfiguration used to configure how to batch scheduling Spark Application
|
||||||
|
@ -288,7 +292,7 @@ type BatchSchedulerConfiguration struct {
|
||||||
PriorityClassName *string `json:"priorityClassName,omitempty"`
|
PriorityClassName *string `json:"priorityClassName,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Specific SparkUI config parameters
|
// SparkUIConfiguration is for driver UI specific configuration parameters.
|
||||||
type SparkUIConfiguration struct {
|
type SparkUIConfiguration struct {
|
||||||
// ServicePort allows configuring the port at service level that might be different from the targetPort.
|
// ServicePort allows configuring the port at service level that might be different from the targetPort.
|
||||||
// TargetPort should be the same as the one defined in spark.ui.port
|
// TargetPort should be the same as the one defined in spark.ui.port
|
||||||
|
@ -631,6 +635,26 @@ type GPUSpec struct {
|
||||||
Quantity int64 `json:"quantity"`
|
Quantity int64 `json:"quantity"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DynamicAllocation contains configuration options for dynamic allocation.
|
||||||
|
type DynamicAllocation struct {
|
||||||
|
// Enabled controls whether dynamic allocation is enabled or not.
|
||||||
|
Enabled bool `json:"enabled,omitempty"`
|
||||||
|
// InitialExecutors is the initial number of executors to request. If .spec.executor.instances
|
||||||
|
// is also set, the initial number of executors is set to the bigger of that and this option.
|
||||||
|
// +optional
|
||||||
|
InitialExecutors *int32 `json:"initialExecutors,omitempty"`
|
||||||
|
// MinExecutors is the lower bound for the number of executors if dynamic allocation is enabled.
|
||||||
|
// +optional
|
||||||
|
MinExecutors *int32 `json:"minExecutors,omitempty"`
|
||||||
|
// MaxExecutors is the upper bound for the number of executors if dynamic allocation is enabled.
|
||||||
|
// +optional
|
||||||
|
MaxExecutors *int32 `json:"maxExecutors,omitempty"`
|
||||||
|
// ShuffleTrackingTimeout controls the timeout in milliseconds for executors that are holding
|
||||||
|
// shuffle data if shuffle tracking is enabled (true by default if dynamic allocation is enabled).
|
||||||
|
// +optional
|
||||||
|
ShuffleTrackingTimeout *int64 `json:"shuffleTrackingTimeout,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
// PrometheusMonitoringEnabled returns if Prometheus monitoring is enabled or not.
|
// PrometheusMonitoringEnabled returns if Prometheus monitoring is enabled or not.
|
||||||
func (s *SparkApplication) PrometheusMonitoringEnabled() bool {
|
func (s *SparkApplication) PrometheusMonitoringEnabled() bool {
|
||||||
return s.Spec.Monitoring != nil && s.Spec.Monitoring.Prometheus != nil
|
return s.Spec.Monitoring != nil && s.Spec.Monitoring.Prometheus != nil
|
||||||
|
|
|
@ -166,6 +166,42 @@ func (in *DriverSpec) DeepCopy() *DriverSpec {
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *DynamicAllocation) DeepCopyInto(out *DynamicAllocation) {
|
||||||
|
*out = *in
|
||||||
|
if in.InitialExecutors != nil {
|
||||||
|
in, out := &in.InitialExecutors, &out.InitialExecutors
|
||||||
|
*out = new(int32)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
|
if in.MinExecutors != nil {
|
||||||
|
in, out := &in.MinExecutors, &out.MinExecutors
|
||||||
|
*out = new(int32)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
|
if in.MaxExecutors != nil {
|
||||||
|
in, out := &in.MaxExecutors, &out.MaxExecutors
|
||||||
|
*out = new(int32)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
|
if in.ShuffleTrackingTimeout != nil {
|
||||||
|
in, out := &in.ShuffleTrackingTimeout, &out.ShuffleTrackingTimeout
|
||||||
|
*out = new(int64)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DynamicAllocation.
|
||||||
|
func (in *DynamicAllocation) DeepCopy() *DynamicAllocation {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(DynamicAllocation)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *ExecutorSpec) DeepCopyInto(out *ExecutorSpec) {
|
func (in *ExecutorSpec) DeepCopyInto(out *ExecutorSpec) {
|
||||||
*out = *in
|
*out = *in
|
||||||
|
@ -667,6 +703,11 @@ func (in *SparkApplicationSpec) DeepCopyInto(out *SparkApplicationSpec) {
|
||||||
*out = new(SparkUIConfiguration)
|
*out = new(SparkUIConfiguration)
|
||||||
(*in).DeepCopyInto(*out)
|
(*in).DeepCopyInto(*out)
|
||||||
}
|
}
|
||||||
|
if in.DynamicAllocation != nil {
|
||||||
|
in, out := &in.DynamicAllocation, &out.DynamicAllocation
|
||||||
|
*out = new(DynamicAllocation)
|
||||||
|
(*in).DeepCopyInto(*out)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -148,6 +148,24 @@ const (
|
||||||
SparkDriverKubernetesMaster = "spark.kubernetes.driver.master"
|
SparkDriverKubernetesMaster = "spark.kubernetes.driver.master"
|
||||||
// SparkDriverServiceAnnotationKeyPrefix is the key prefix of annotations to be added to the driver service.
|
// SparkDriverServiceAnnotationKeyPrefix is the key prefix of annotations to be added to the driver service.
|
||||||
SparkDriverServiceAnnotationKeyPrefix = "spark.kubernetes.driver.service.annotation."
|
SparkDriverServiceAnnotationKeyPrefix = "spark.kubernetes.driver.service.annotation."
|
||||||
|
// SparkDynamicAllocationEnabled is the Spark configuration key for specifying if dynamic
|
||||||
|
// allocation is enabled or not.
|
||||||
|
SparkDynamicAllocationEnabled = "spark.dynamicAllocation.enabled"
|
||||||
|
// SparkDynamicAllocationShuffleTrackingEnabled is the Spark configuration key for
|
||||||
|
// specifying if shuffle data tracking is enabled.
|
||||||
|
SparkDynamicAllocationShuffleTrackingEnabled = "spark.dynamicAllocation.shuffleTracking.enabled"
|
||||||
|
// SparkDynamicAllocationShuffleTrackingTimeout is the Spark configuration key for specifying
|
||||||
|
// the shuffle tracking timeout in milliseconds if shuffle tracking is enabled.
|
||||||
|
SparkDynamicAllocationShuffleTrackingTimeout = "spark.dynamicAllocation.shuffleTracking.timeout"
|
||||||
|
// SparkDynamicAllocationInitialExecutors is the Spark configuration key for specifying
|
||||||
|
// the initial number of executors to request if dynamic allocation is enabled.
|
||||||
|
SparkDynamicAllocationInitialExecutors = "spark.dynamicAllocation.initialExecutors"
|
||||||
|
// SparkDynamicAllocationMinExecutors is the Spark configuration key for specifying the
|
||||||
|
// lower bound of the number of executors to request if dynamic allocation is enabled.
|
||||||
|
SparkDynamicAllocationMinExecutors = "spark.dynamicAllocation.minExecutors"
|
||||||
|
// SparkDynamicAllocationMaxExecutors is the Spark configuration key for specifying the
|
||||||
|
// upper bound of the number of executors to request if dynamic allocation is enabled.
|
||||||
|
SparkDynamicAllocationMaxExecutors = "spark.dynamicAllocation.maxExecutors"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
|
@ -140,11 +140,6 @@ func buildSubmissionCommandArgs(app *v1beta2.SparkApplication, driverPodName str
|
||||||
args = append(args, "--conf", fmt.Sprintf("spark.hadoop.%s=%s", key, value))
|
args = append(args, "--conf", fmt.Sprintf("spark.hadoop.%s=%s", key, value))
|
||||||
}
|
}
|
||||||
|
|
||||||
for key, value := range app.Spec.NodeSelector {
|
|
||||||
conf := fmt.Sprintf("%s%s=%s", config.SparkNodeSelectorKeyPrefix, key, value)
|
|
||||||
args = append(args, "--conf", conf)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the driver and executor configuration options.
|
// Add the driver and executor configuration options.
|
||||||
// Note that when the controller submits the application, it expects that all dependencies are local
|
// Note that when the controller submits the application, it expects that all dependencies are local
|
||||||
// so init-container is not needed and therefore no init-container image needs to be specified.
|
// so init-container is not needed and therefore no init-container image needs to be specified.
|
||||||
|
@ -163,6 +158,16 @@ func buildSubmissionCommandArgs(app *v1beta2.SparkApplication, driverPodName str
|
||||||
args = append(args, "--conf", option)
|
args = append(args, "--conf", option)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
options = addDynamicAllocationConfOptions(app)
|
||||||
|
for _, option := range options {
|
||||||
|
args = append(args, "--conf", option)
|
||||||
|
}
|
||||||
|
|
||||||
|
for key, value := range app.Spec.NodeSelector {
|
||||||
|
conf := fmt.Sprintf("%s%s=%s", config.SparkNodeSelectorKeyPrefix, key, value)
|
||||||
|
args = append(args, "--conf", conf)
|
||||||
|
}
|
||||||
|
|
||||||
if app.Spec.Volumes != nil {
|
if app.Spec.Volumes != nil {
|
||||||
options, err = addLocalDirConfOptions(app)
|
options, err = addLocalDirConfOptions(app)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -393,6 +398,36 @@ func addExecutorConfOptions(app *v1beta2.SparkApplication, submissionID string)
|
||||||
return executorConfOptions, nil
|
return executorConfOptions, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func addDynamicAllocationConfOptions(app *v1beta2.SparkApplication) []string {
|
||||||
|
if app.Spec.DynamicAllocation == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
dynamicAllocation := app.Spec.DynamicAllocation
|
||||||
|
if !dynamicAllocation.Enabled {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var options []string
|
||||||
|
options = append(options, fmt.Sprintf("%s=true", config.SparkDynamicAllocationEnabled))
|
||||||
|
// Turn on shuffle tracking if dynamic allocation is enabled.
|
||||||
|
options = append(options, fmt.Sprintf("%s=true", config.SparkDynamicAllocationShuffleTrackingEnabled))
|
||||||
|
if dynamicAllocation.InitialExecutors != nil {
|
||||||
|
options = append(options, fmt.Sprintf("%s=%d", config.SparkDynamicAllocationInitialExecutors, *dynamicAllocation.InitialExecutors))
|
||||||
|
}
|
||||||
|
if dynamicAllocation.MinExecutors != nil {
|
||||||
|
options = append(options, fmt.Sprintf("%s=%d", config.SparkDynamicAllocationMinExecutors, *dynamicAllocation.MinExecutors))
|
||||||
|
}
|
||||||
|
if dynamicAllocation.MaxExecutors != nil {
|
||||||
|
options = append(options, fmt.Sprintf("%s=%d", config.SparkDynamicAllocationMaxExecutors, *dynamicAllocation.MaxExecutors))
|
||||||
|
}
|
||||||
|
if dynamicAllocation.ShuffleTrackingTimeout != nil {
|
||||||
|
options = append(options, fmt.Sprintf("%s=%d", config.SparkDynamicAllocationShuffleTrackingTimeout, *dynamicAllocation.ShuffleTrackingTimeout))
|
||||||
|
}
|
||||||
|
|
||||||
|
return options
|
||||||
|
}
|
||||||
|
|
||||||
// addLocalDirConfOptions excludes local dir volumes, update SparkApplication and returns local dir config options
|
// addLocalDirConfOptions excludes local dir volumes, update SparkApplication and returns local dir config options
|
||||||
func addLocalDirConfOptions(app *v1beta2.SparkApplication) ([]string, error) {
|
func addLocalDirConfOptions(app *v1beta2.SparkApplication) ([]string, error) {
|
||||||
var localDirConfOptions []string
|
var localDirConfOptions []string
|
||||||
|
|
|
@ -18,18 +18,20 @@ package sparkapplication
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/google/uuid"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/spark-on-k8s-operator/pkg/apis/sparkoperator.k8s.io/v1beta2"
|
"github.com/GoogleCloudPlatform/spark-on-k8s-operator/pkg/apis/sparkoperator.k8s.io/v1beta2"
|
||||||
|
"github.com/GoogleCloudPlatform/spark-on-k8s-operator/pkg/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -504,3 +506,40 @@ func TestPopulateLabelsOverride_Driver_Executor(t *testing.T) {
|
||||||
t.Errorf("Executor labels: wanted %+q got %+q", expectedExecutorLabels, executorOptions)
|
t.Errorf("Executor labels: wanted %+q got %+q", expectedExecutorLabels, executorOptions)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDynamicAllocationOptions(t *testing.T) {
|
||||||
|
app := &v1beta2.SparkApplication{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "spark-test",
|
||||||
|
UID: "spark-test-1",
|
||||||
|
},
|
||||||
|
Spec: v1beta2.SparkApplicationSpec{},
|
||||||
|
}
|
||||||
|
options := addDynamicAllocationConfOptions(app)
|
||||||
|
assert.Equal(t, 0, len(options))
|
||||||
|
|
||||||
|
app = &v1beta2.SparkApplication{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "spark-test",
|
||||||
|
UID: "spark-test-1",
|
||||||
|
},
|
||||||
|
Spec: v1beta2.SparkApplicationSpec{
|
||||||
|
DynamicAllocation: &v1beta2.DynamicAllocation{
|
||||||
|
Enabled: true,
|
||||||
|
InitialExecutors: int32ptr(2),
|
||||||
|
MinExecutors: int32ptr(0),
|
||||||
|
MaxExecutors: int32ptr(10),
|
||||||
|
ShuffleTrackingTimeout: int64ptr(6000000),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
options = addDynamicAllocationConfOptions(app)
|
||||||
|
assert.Equal(t, 6, len(options))
|
||||||
|
assert.Equal(t, fmt.Sprintf("%s=true", config.SparkDynamicAllocationEnabled), options[0])
|
||||||
|
assert.Equal(t, fmt.Sprintf("%s=true", config.SparkDynamicAllocationShuffleTrackingEnabled), options[1])
|
||||||
|
assert.Equal(t, fmt.Sprintf("%s=2", config.SparkDynamicAllocationInitialExecutors), options[2])
|
||||||
|
assert.Equal(t, fmt.Sprintf("%s=0", config.SparkDynamicAllocationMinExecutors), options[3])
|
||||||
|
assert.Equal(t, fmt.Sprintf("%s=10", config.SparkDynamicAllocationMaxExecutors), options[4])
|
||||||
|
assert.Equal(t, fmt.Sprintf("%s=6000000", config.SparkDynamicAllocationShuffleTrackingTimeout), options[5])
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue