Skip to content

Driver pod templates

Since 0.13.0, a Kubernetes Pod template for the driver is supported through the Python client, CLI and both Airflow operators. This feature does not require a Spark operator or a custom resource.

Use a template for settings such as pod/container security contexts, affinity, image pull secrets, sidecars, init containers and additional volumes. The client merges the template into the same driver pod it normally submits.

Submit a template

Save this as driver.yaml. The application image still comes from the submission arguments, so the selected container does not need an image in the template.

apiVersion: v1
kind: Pod
metadata:
  labels:
    team: analytics
spec:
  securityContext:
    runAsNonRoot: true
    runAsUser: 185
    fsGroup: 185
  containers:
    - name: driver
      securityContext:
        allowPrivilegeEscalation: false
        capabilities:
          drop: [ALL]
      volumeMounts:
        - name: scratch
          mountPath: /scratch
  volumes:
    - name: scratch
      emptyDir: {}

Select a user ID supported by your application image and ensure its working directories are writable. A template configures the driver only; use an executor template for executor pod settings.

from spark_on_k8s.client import SparkOnK8S

SparkOnK8S().submit_app(
    image="registry.example.com/team/spark-job:1.0",
    app_path="local:///opt/spark/work-dir/job.py",
    namespace="spark",
    service_account="spark",
    driver_pod_template="./driver.yaml",
    app_waiter="log",
)
spark-on-k8s app submit \
  --image registry.example.com/team/spark-job:1.0 \
  --path local:///opt/spark/work-dir/job.py \
  --namespace spark \
  --service-account spark \
  --driver-pod-template ./driver.yaml \
  --logs

driver_pod_template accepts YAML text, a local path string, a pathlib.Path, or a Python mapping. The CLI accepts YAML text or a local path. Files are read on the machine submitting the application; this option does not fetch remote URLs.

Select the driver container

A template can contain additional containers. The client selects the container named driver, or the sole container if there is only one. Otherwise, specify driver_container_name="spark-main" or --driver-container-name spark-main. An explicit name must exist. An ambiguous or missing selection is an error.

The selected container becomes the first container in the submitted pod, retaining its name. Other containers keep their relative order and settings. Logs and kill operations target this selected container; the client also sets kubectl.kubernetes.io/default-container for interactive kubectl use.

Ordinary sidecars must exit for the pod to finish. A sidecar that keeps running also keeps pod-based waiting and Airflow tasks running. Where supported by your cluster, Kubernetes native sidecars in initContainers with restartPolicy: Always provide a lifecycle that ends with the application containers. Sidecar lifecycle is controlled by Kubernetes, not by this client.

Merge rules

The template is the starting point. Submission arguments and their resolved configuration defaults supply the generated fields below. In particular, omitting an argument does not make a template image, service account or CPU/memory setting override the client's configured default. Input mappings are not modified.

Field Result
Pod name and namespace Generated application pod name and submission namespace.
spark-app-id, spark-app-name, spark-role, spark-ui-proxy labels Managed application identity and proxy settings; template values are discarded.
Other labels and annotations Template entries are retained; explicit driver entries override matching keys.
Service account and restart policy Submission service account and Never; the deprecated serviceAccount alias is removed.
activeDeadlineSeconds The submission's max_runtime when set; otherwise the template value, if any, is retained.
Selected container image, image pull policy and arguments Generated from submission options and Spark configuration.
Selected container command Removed, so the application image's Spark entrypoint runs the generated driver arguments.
Selected container CPU and memory requests/limits Generated from driver_resources or configured defaults. Other resources, such as ephemeral storage or GPU limits, are retained.
Environment variables Merged by name; generated values win, including spark.kubernetes.driverEnv.* properties and the managed SPARK_DRIVER_BIND_ADDRESS. See driver environment variables for precedence and validation.
Environment sources (envFrom) Template sources first, then generated secret references; identical entries are not duplicated.
Volumes, init containers Merged by name; an explicit matching entry replaces the entire template entry.
Driver volume mounts Merged by mount path; an explicit matching entry replaces the entire template entry.
Container ports Merged by name, or by port/protocol for unnamed entries; generated driver/UI ports win on matching keys.
Node selector Merged by key, with explicit driver selectors winning.
Host aliases Merged by IP, with explicit driver aliases winning.
Tolerations Template entries followed by explicit driver entries, without exact duplicates.
Other pod/container fields Preserved, including security contexts, affinity, image pull secrets and sidecar settings.

Lists with duplicate merge keys are rejected rather than resolved by position. Server-assigned metadata, owner references, generateName, and status are not accepted. Templates cannot supply annotations in the reserved spark-on-k8s.io/ namespace. Keep that namespace available for project-managed ownership metadata; use your own annotation prefix for application metadata.

Loading, container selection and merge validation finish before any Kubernetes Secret, ConfigMap, Pod or Service is created. This is not a complete Kubernetes schema validator: the API server still validates other fields and enforces cluster admission policies. Template settings do not bypass those policies.

Airflow

Both SparkOnK8SOperator and SparkSqlOnK8SOperator accept the same template and container-selection arguments. These fields support Airflow templating and DAG serialization on Airflow 2.11 and Airflow 3.

from spark_on_k8s.airflow.operators import SparkOnK8SOperator

application = SparkOnK8SOperator(
    task_id="application",
    image="registry.example.com/team/spark-job:1.0",
    app_path="local:///opt/spark/work-dir/job.py",
    namespace="spark",
    service_account="spark",
    driver_pod_template={
        "apiVersion": "v1",
        "kind": "Pod",
        "metadata": {"labels": {"run-date": "{{ ds }}"}},
        "spec": {"containers": [{"name": "driver"}]},
    },
)

For a file path, Airflow renders the path string, then the SDK reads that file on the worker. File contents are not separately rendered by Airflow. Pass inline YAML or a mapping when the template contents themselves contain Jinja expressions. See the Airflow guide for connection and deployment setup.