Chapter 4. Run Spark workloads from OpenShift AI workbenches
This section describes how to deploy a Spark Connect server on OpenShift AI and run PySpark workloads from Jupyter workbenches without managing Spark infrastructure.
Spark Connect on OpenShift AI is a Technology Preview feature only. Technology Preview features are not supported with Red Hat production service level agreements (SLAs) and might not be functionally complete. Red Hat does not recommend using them in production. These features provide early access to upcoming product features, enabling customers to test functionality and provide feedback during the development process.
For more information about the support scope of Red Hat Technology Preview features, see Technology Preview Features Support Scope.
4.1. Spark Connect on OpenShift AI Copy linkLink copied to clipboard!
You can run distributed Apache Spark workloads directly from OpenShift AI Jupyter workbenches by using Spark Connect and the Kubeflow Spark Operator. Spark Connect provides a gRPC-based client/server architecture that decouples the PySpark client in your notebook from the Spark driver, so you can submit and monitor Spark jobs without managing Spark infrastructure or requiring cluster-level permissions.
4.1.1. How the Kubeflow Spark Operator manages Spark Connect Copy linkLink copied to clipboard!
The Kubeflow Spark Operator automates the lifecycle of Spark Connect servers on OpenShift AI. When you create a SparkConnect custom resource, the Operator provisions the following resources automatically:
-
A
ConfigMapwith the executor pod template. - A server pod that runs the Spark Connect driver process.
-
A ClusterIP
Servicethat exposes the server with a stable DNS name, including ports for Spark internal communication (7078, 7079, 4040) and the gRPC endpoint (15002).
The auto-created Service follows the naming convention _<connect_name>_-server, where _<connect_name>_ is the metadata.name value from your SparkConnect custom resource. The full DNS name is _<connect_name>_-server._<namespace>_.svc.cluster.local.
You do not need to create a Service manually. The Operator creates and manages it as part of the SparkConnect resource reconciliation.
4.2. Configure Spark Connect for a non-default namespace Copy linkLink copied to clipboard!
You can deploy a Spark Connect server in a namespace other than {dbd-config-default-namespace} to isolate workloads by team or project. Because the Spark Operator creates RBAC and NetworkPolicy resources only in {dbd-config-default-namespace} during initial deployment, you must manually create these resources in the target namespace before deploying the SparkConnect custom resource.
Spark Connect on OpenShift AI is a Technology Preview feature only. Technology Preview features are not supported with Red Hat production service level agreements (SLAs) and might not be functionally complete. Red Hat does not recommend using them in production. These features provide early access to upcoming product features, enabling customers to test functionality and provide feedback during the development process.
For more information about the support scope of Red Hat Technology Preview features, see Technology Preview Features Support Scope.
Prerequisites
-
A Spark Connect server is deployed successfully in
{dbd-config-default-namespace}, confirming that the Spark Operator is working correctly. - You have cluster administrator privileges for the OpenShift cluster.
- The OpenShift CLI (`oc`) is installed.
- You know the target namespace where you want to deploy the Spark Connect server.
Procedure
Create the
ServiceAccountin the target namespace.In the following command, replace
_<target_namespace>_with the name of your namespace:$ cat <<EOF | oc apply -f - apiVersion: v1 kind: ServiceAccount metadata: name: spark-operator-spark namespace: <target_namespace> EOFCreate the
Rolewith the required permissions in the target namespace.The Spark driver needs permissions to create and manage executor pods,
ConfigMaps,PersistentVolumeClaims, andServices:$ cat <<EOF | oc apply -f - apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: spark-role namespace: <target_namespace> rules: - apiGroups: - "" resources: - pods - configmaps - persistentvolumeclaims - services verbs: - get - list - watch - create - update - patch - delete - deletecollection EOFCreate the
RoleBindingto connect theServiceAccountto theRole:$ cat <<EOF | oc apply -f - apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: spark-role-binding namespace: <target_namespace> subjects: - kind: ServiceAccount name: spark-operator-spark roleRef: kind: Role name: spark-role apiGroup: rbac.authorization.k8s.io EOFCreate the
NetworkPolicyto allow Spark internal communication and workbench connectivity:$ cat <<EOF | oc apply -f - apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: spark-operator-allow-internal namespace: <target_namespace> spec: podSelector: matchLabels: sparkoperator.k8s.io/launched-by-spark-operator: "true" policyTypes: - Ingress ingress: - ports: - port: 7078 protocol: TCP - port: 7079 protocol: TCP - port: 4040 protocol: TCP from: - podSelector: {} - namespaceSelector: matchLabels: network.openshift.io/policy-group: ingress - ports: - port: 15002 protocol: TCP from: - podSelector: {} - namespaceSelector: matchLabels: opendatahub.io/dashboard: "true" podSelector: matchLabels: opendatahub.io/workbenches: "true" EOF- Ports 7078 and 7079 enable remote procedure call (RPC) and block manager communication between the Spark driver and executor pods.
- Port 4040 enables the Spark UI.
- Port 15002 enables gRPC connectivity from workbench pods in namespaces managed by the OpenShift AI dashboard.
Deploy the
SparkConnectcustom resource in the target namespace.Create a YAML file with the
metadata.namespacefield set to your target namespace and apply it:$ oc apply -f spark-connect-server.yamlFor the complete
SparkConnectcustom resource example, see SparkConnect custom resource and infrastructure reference.
Verification
Verify that the server pod is running in the target namespace:
$ oc get pods -n <target_namespace> -l sparkoperator.k8s.io/launched-by-spark-operator=trueThe output shows a pod with a
Runningstatus.Verify that the auto-created
Serviceexists:$ oc get svc -n <target_namespace> -l sparkoperator.k8s.io/connect-name=spark-connectThe output shows a ClusterIP
Serviceexposing port 15002.Verify that the RBAC resources are created correctly:
$ oc get serviceaccount spark-operator-spark -n <target_namespace> $ oc get role spark-role -n <target_namespace> $ oc get rolebinding spark-role-binding -n <target_namespace>Verify that the
NetworkPolicywas created in the target namespace:$ oc get networkpolicy spark-operator-allow-internal -n <target_namespace>
4.3. Deploy a Spark Connect server on OpenShift AI Copy linkLink copied to clipboard!
You can deploy a Spark Connect server on OpenShift AI by creating a SparkConnect custom resource in a namespace that an administrator has configured with the required RBAC resources. After you deploy the server, the Kubeflow Spark Operator automatically creates a ClusterIP Service that provides a stable DNS endpoint for workbench connectivity.
Prerequisites
- Red Hat OpenShift AI 3.5 or later is installed.
-
The
DataScienceClusterresource is configured with thesparkoperatorcomponent set toManaged. -
The
DataScienceClusterresource is configured with theworkbenchescomponent set toManaged. - An administrator has configured a namespace with the required ServiceAccount, Role, RoleBinding, and NetworkPolicy resources for Spark Connect.
- You have access to the configured namespace.
- The OpenShift CLI (`oc`) is installed.
Procedure
Create a YAML file for the
SparkConnectresource. The following example shows a basicSparkConnectconfiguration:apiVersion: sparkoperator.k8s.io/v1alpha1 kind: SparkConnect metadata: name: spark-connect namespace: <your_namespace> spec: sparkVersion: 4.0.1 server: template: spec: containers: - name: spark-kubernetes-driver image: quay.io/opendatahub/data-processing:Spark-v4.0.1 imagePullPolicy: Always resources: requests: cpu: 1 memory: 1Gi limits: cpu: 1 memory: 1Gi serviceAccountName: spark-operator-spark securityContext: {} executor: instances: 2 cores: 1 memory: 512m template: spec: containers: - name: spark-kubernetes-executor image: quay.io/opendatahub/data-processing:Spark-v4.0.1 imagePullPolicy: Always securityContext: {}NoteThe
securityContext: {}field at the pod level is intentionally empty. On OpenShift, the restricted-v2 Security Context Constraint (SCC) automatically enforces security restrictions such asrunAsNonRoot, capability dropping, and seccomp profiles. Do not add explicit security context fields to theSparkConnectcustom resource.Apply the
SparkConnectcustom resource:$ oc apply -f spark-connect-server.yamlVerify that the Spark Connect server pod is running:
$ oc get pods -n <your_namespace> -l sparkoperator.k8s.io/launched-by-spark-operator=trueThe output shows a pod named
spark-connect-serverwith aRunningstatus:NAME READY STATUS RESTARTS AGE spark-connect-server 1/1 Running 0 30sVerify that the Operator has created the ClusterIP
Serviceautomatically:$ oc get svc -n <your_namespace> -l sparkoperator.k8s.io/connect-name=spark-connectThe output shows the auto-created
Serviceexposing ports for Spark internal communication and gRPC connectivity:NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE spark-connect-server ClusterIP 172.30.x.x <none> 7078/TCP,7079/TCP,4040/TCP,15002/TCP 30sNoteThe Operator creates this
Serviceautomatically. You do not need to create aServicemanually. TheServiceDNS name follows the convention_<connect_name>_-server._<namespace>_.svc.cluster.local. For example, the DNS name isspark-connect-server.<your_namespace>.svc.cluster.local.Record the
ServiceDNS name for use in the workbench connection string:spark-connect-server.<namespace>.svc.cluster.localWorkbench users use this DNS name with port 15002 to construct the
sc://connection URL in their workbench notebooks.
4.4. Run PySpark workloads from an OpenShift AI workbench Copy linkLink copied to clipboard!
You can connect to a Spark Connect server from an OpenShift AI Jupyter workbench and run distributed PySpark workloads directly from your notebook. Spark Connect supports DataFrame operations and Spark SQL, so you can process large datasets without managing Spark infrastructure.
Prerequisites
- A Spark Connect server is deployed and running on your OpenShift AI cluster. For instructions, see Deploy a Spark Connect server on OpenShift AI.
- The ClusterIP Service for the Spark Connect server is available, and you know the Service DNS name.
- An OpenShift AI Jupyter workbench is running. A minimal Jupyter image with CPU support is sufficient for Spark Connect workloads, such as "Jupyter | Minimal | CPU | Python 3.12".
Procedure
In your Jupyter notebook, install PySpark and the required dependencies by running the following command in a notebook cell:
!pip install -q pyspark==4.0.1 pandas pyarrow grpcio grpcio-status zstandardImportantThe PySpark version must match the Spark version used in the Spark Connect server container image. A version mismatch causes connection failures. After the installation completes, restart the notebook kernel so that the new packages take effect.
Construct the Spark Connect URL by using the Service DNS name and port 15002.
The URL follows this format:
sc://<connect_name>-server.<namespace>.svc.cluster.local:15002For a SparkConnect resource named
spark-connectdeployed in{dbd-config-default-namespace}, the URL is:sc://spark-connect-server.redhat-ods-applications.svc.cluster.local:15002Create a
SparkSessionby using thesc://connection URL.Run the following code in a notebook cell:
from pyspark.sql import SparkSession spark = SparkSession.builder.remote( "sc://spark-connect-server.redhat-ods-applications.svc.cluster.local:15002" ).getOrCreate()NoteReplace the
ServiceDNS name and namespace if your Spark Connect server is deployed in a different namespace.Run a PySpark DataFrame workload to verify the connection.
The following example creates a DataFrame, applies a filter, and displays the results:
data = [("Alice", 34), ("Bob", 45), ("Claire", 66)] df = spark.createDataFrame(data, ["Name", "Age"]) df.filter(df.Age > 40).show()The expected output is as follows:
+------+---+ | Name|Age| +------+---+ | Bob| 45| |Claire| 66| +------+---+
4.5. Troubleshoot Spark Connect workbench connectivity Copy linkLink copied to clipboard!
If you cannot connect to the Spark Connect server from your OpenShift AI workbench, you can diagnose the problem by checking the server pod status, verifying the Service endpoint, and confirming that NetworkPolicy rules allow gRPC traffic on port 15002.
Prerequisites
- A Spark Connect server has been deployed. For instructions, see Deploy a Spark Connect server on OpenShift AI.
- The OpenShift CLI (`oc`) is installed.
- You have access to the namespace where the Spark Connect server is deployed.
The following commands use spark-connect-server as the pod and Service name. The Operator derives these names from the metadata.name of your SparkConnect custom resource by appending -server. If your SparkConnect resource uses a different name, replace spark-connect-server with _<your_connect_name>_-server in all commands.
Check the Spark Connect server pod status and logs.
In the following commands, replace
_<namespace>_with the namespace where the SparkConnect resource is deployed:$ oc get pods -n <namespace> -l sparkoperator.k8s.io/launched-by-spark-operator=trueIf the pod is not in
Runningstatus, inspect the pod events for startup failures:$ oc describe pod spark-connect-server -n <namespace>Check the server logs for error messages:
$ oc logs spark-connect-server -n <namespace>Verify that the ClusterIP
Serviceexists and has the correct selector labels.$ oc get svc -n <namespace> -l sparkoperator.k8s.io/connect-name=spark-connectIf no
Serviceis returned, verify that theSparkConnectcustom resource has been applied correctly. The Operator creates theServiceautomatically during reconciliation.Inspect the
Servicedetails to confirm that the selector labels and port match:$ oc describe svc spark-connect-server -n <namespace>The
Serviceshould select pods with labelssparkoperator.k8s.io/launched-by-spark-operator: true,sparkoperator.k8s.io/connect-name: _<connect_name>_,spark-role: connect-server, andspark-version: _<spark_version>_. TheServiceexposes ports 7078, 7079, 4040, and 15002.Verify that the
ServiceDNS name resolves from inside the workbench pod.Find the workbench pod name:
$ oc get pods --all-namespaces -l opendatahub.io/workbenches=trueTest DNS resolution from inside the workbench pod. In the following command, replace
_<workbench_pod>_and_<workbench_namespace>_with your workbench pod name and namespace:$ oc exec -n <workbench_namespace> <workbench_pod> -- nslookup spark-connect-server.<namespace>.svc.cluster.localIf DNS resolution fails, verify that the
Serviceexists in the expected namespace.Verify that the
NetworkPolicyallows traffic on port 15002 from your workbench.Check that the workbench pod has the required label:
$ oc get pod <workbench_pod> -n <workbench_namespace> --show-labels | grep opendatahub.io/workbenchesCheck that the workbench namespace has the required label:
$ oc get namespace <workbench_namespace> --show-labels | grep opendatahub.io/dashboardIf either label is missing, the
spark-operator-allow-internalNetworkPolicyblocks the gRPC traffic. The workbench pod must have theopendatahub.io/workbenches: "true"label, and the workbench namespace must have theopendatahub.io/dashboard: "true"label.Test gRPC connectivity from the workbench pod.
Open a remote shell on the workbench pod and attempt a PySpark connection:
$ oc rsh -n <workbench_namespace> <workbench_pod>Inside the shell, run a basic connection test:
python -c "from pyspark.sql import SparkSession; spark = SparkSession.builder.remote('sc://spark-connect-server.<namespace>.svc.cluster.local:15002').getOrCreate(); print(spark.version)"If this command succeeds but the notebook cell fails, restart the notebook kernel to reload the installed packages.
4.6. SparkConnect custom resource and infrastructure reference Copy linkLink copied to clipboard!
You can use the following reference tables to understand the fields in the SparkConnect custom resource, the RBAC resources required by the Spark Operator, the NetworkPolicy rules for workbench connectivity, and the PySpark client dependencies.
The SparkConnect custom resource is a Technology Preview feature only. Technology Preview features are not supported with Red Hat production service level agreements (SLAs) and might not be functionally complete. Red Hat does not recommend using them in production. These features provide early access to upcoming product features, enabling customers to test functionality and provide feedback during the development process.
For more information about the support scope of Red Hat Technology Preview features, see Technology Preview Features Support Scope.
4.6.1. SparkConnect custom resource fields Copy linkLink copied to clipboard!
The SparkConnect custom resource uses the sparkoperator.k8s.io/v1alpha1 API version. The following table describes the key fields.
| Field | Type | Description |
|---|---|---|
|
| String |
The name of the SparkConnect resource. The Operator uses this value to derive the server pod name and |
|
| String |
The namespace where the SparkConnect server is deployed. If you use a namespace other than |
|
| String | The version of Apache Spark that the Spark Connect server uses. This value must match the version in the container image. |
|
| String |
Optional. The default container image for the server and executor containers. Per-container images in |
|
| Map |
Optional. Spark configuration properties, equivalent to |
|
| Map |
Optional. Hadoop configuration properties. The Operator automatically adds the |
|
| PodTemplateSpec |
The pod template for the Spark Connect server. Use this to configure the container image, resource requests, limits, security context, and service account. Set the service account at |
|
| Service |
Optional. Custom |
|
| Integer | The number of executor instances to run. Minimum value is 0. |
|
| Integer | The number of CPU cores per executor. Minimum value is 1. |
|
| String |
The amount of memory per executor, such as |
|
| PodTemplateSpec | The pod template for executor pods. Use this to configure the executor container image and resources. |
|
| Object | Optional. Configures dynamic allocation of executors, available since Spark 3.0 with the Kubernetes scheduler backend. |
4.6.2. SparkConnect custom resource example Copy linkLink copied to clipboard!
The following example creates a SparkConnect server with two executor instances in the {dbd-config-default-namespace} namespace:
apiVersion: sparkoperator.k8s.io/v1alpha1
kind: SparkConnect
metadata:
name: spark-connect
namespace: redhat-ods-applications
spec:
sparkVersion: 4.0.1
server:
template:
spec:
containers:
- name: spark-kubernetes-driver
image: quay.io/opendatahub/data-processing:Spark-v4.0.1
imagePullPolicy: Always
resources:
requests:
cpu: 1
memory: 1Gi
limits:
cpu: 1
memory: 1Gi
serviceAccountName: spark-operator-spark
securityContext: {}
executor:
instances: 2
cores: 1
memory: 512m
template:
spec:
containers:
- name: spark-kubernetes-executor
image: quay.io/opendatahub/data-processing:Spark-v4.0.1
imagePullPolicy: Always
securityContext: {}
-
securityContext: {}at the pod level delegates security enforcement to the OpenShift restricted-v2 Security Context Constraint. Do not add explicit security context fields such asrunAsNonRootorcapabilities.drop, because OpenShift applies these constraints automatically. -
spec.server.template.spec.serviceAccountNamemust reference a service account with sufficient RBAC permissions to manage executor pods.
4.6.3. RBAC resources Copy linkLink copied to clipboard!
The Spark Operator creates the following RBAC resources in the {dbd-config-default-namespace} namespace during initial deployment. If you deploy a SparkConnect server in a different namespace, you must recreate these resources manually.
| Field | Value |
|---|---|
| Name |
|
| Purpose | Identity for the Spark Connect server pod and Spark driver, which creates and manages executor pods. |
| API group | Resources | Verbs |
|---|---|---|
|
|
|
|
| Field | Value |
|---|---|
| Name |
|
| Role reference |
|
| Subject |
ServiceAccount |
4.6.4. NetworkPolicy Copy linkLink copied to clipboard!
The Spark Operator creates a NetworkPolicy named spark-operator-allow-internal in the {dbd-config-default-namespace} namespace. This policy controls ingress traffic to pods launched by the Operator.
| Port | Protocol | Purpose |
|---|---|---|
| 7078 | TCP | Spark driver remote procedure call (RPC) communication between driver and executor pods. |
| 7079 | TCP | Spark block manager data transfer between pods. |
| 4040 | TCP | Spark UI for monitoring running applications. |
| 15002 | TCP | Spark Connect gRPC endpoint for workbench connectivity. |
The port 15002 ingress rule allows traffic from:
-
Any pod in the same namespace through
podSelector: {}. -
Workbench pods labeled
opendatahub.io/workbenches: "true"in namespaces labeledopendatahub.io/dashboard: "true". This combination enables workbenches running in rhods-notebooks or other dashboard-managed namespaces to reach the Spark Connect server.
4.6.5. Auto-created Service Copy linkLink copied to clipboard!
When you create a SparkConnect custom resource, the Operator automatically creates a ClusterIP Service.
| Field | Value |
|---|---|
| Name |
|
| Type | ClusterIP |
| Ports | 7078 (driver-rpc), 7079 (blockmanager), 4040 (web-ui), 15002 (gRPC) |
| Selector labels |
|
| DNS name |
|
4.6.6. PySpark client dependencies Copy linkLink copied to clipboard!
Install the following Python packages in your workbench to connect to the Spark Connect server. The PySpark version must match the Spark version used in the server container image.
| Package | Version | Purpose |
|---|---|---|
|
| 4.0.1 | PySpark client library with Spark Connect support. Must match the server image Spark version. |
|
| Latest compatible |
Required for DataFrame interoperability and |
|
| Latest compatible | Columnar data interchange between PySpark and pandas. |
|
| Latest compatible |
gRPC client library for the |
|
| Latest compatible | gRPC status code handling for error reporting. |
|
| Latest compatible | Zstandard compression support for Spark Connect protocol communication. |