Running Apache Spark on Kubernetes (Spark-on-K8s)/Ch 1. Introduction to Apache Spark on Kubernetes

Chapter 1

Introduction to Apache Spark on Kubernetes

15 min read

0:00
1x

Chapter Summary

# Chapter 1: Introduction to Apache Spark on Kubernetes Welcome to the modern era of big data processing. If you are reading this, you likely understand the pain points of managing traditional Spark clusters: the rigid capacity of YARN, the complexity of maintaining HDFS, and the operational nightm...

Chapter 1: Introduction to Apache Spark on Kubernetes

Welcome to the modern era of big data processing. If you are reading this, you likely understand the pain points of managing traditional Spark clusters: the rigid capacity of YARN, the complexity of maintaining HDFS, and the operational nightmare of multi-tenancy on static hardware.

Running Apache Spark on Kubernetes (K8s) changes the game. It treats your data processing jobs as first-class citizens of the container orchestrator, bringing the elasticity of the cloud and the declarative power of Kubernetes to the world of distributed computing.

The Paradigm Shift: From Static to Dynamic

In a traditional Spark-on-YARN setup, you typically provision a cluster with a fixed number of worker nodes. You spend hours tuning resource queues and worrying about "noisy neighbors" stealing CPU cycles.

When you move to Spark-on-K8s, you stop thinking about "clusters" and start thinking about "workloads." Spark leverages the Kubernetes API to provision executors as native pods. When your job finishes, those pods vanish, returning resources to the pool.

"The primary value of Spark-on-K8s isn't just portability; it is the ability to align your data infrastructure with the same operational maturity used for your microservices. You are no longer running a Spark cluster; you are running Spark jobs as ephemeral, self-healing tasks."

How It Works Under the Hood

When you submit a Spark job via

text
spark-submit
to a Kubernetes cluster, the following lifecycle occurs:

  1. Driver Pod Creation: Spark creates a driver pod. This pod acts as the controller for the application.
  2. Executor Request: The driver communicates with the Kubernetes API server to request executor pods.
  3. Pod Scheduling: The K8s scheduler places these pods onto available nodes.
  4. Direct Communication: The driver and executors communicate directly via the K8s pod network to process data.
  5. Cleanup: Once the task is complete, executors exit, and the driver pod shuts down (or stays up if configured for history logging).

Example: The Minimal Submission

To run a job, you point your

text
spark-submit
command to the Kubernetes API server.

bash
# Example: Submitting a SparkPi job to K8s
spark-submit \
    --master k8s://https://<k8s-apiserver-host>:<port> \
    --deploy-mode cluster \
    --name spark-pi \
    --class org.apache.spark.examples.SparkPi \
    --conf spark.executor.instances=5 \
    --conf spark.kubernetes.container.image=my-repo/spark:3.4.0 \
    local:///opt/spark/examples/jars/spark-examples_2.12-3.4.0.jar

Real-World Scenario: The Multi-Tenant Data Platform

Imagine a financial services firm where the Data Science team needs to run heavy ETL pipelines while the Fraud Detection team needs real-time Spark Streaming jobs.

In a static cluster, these teams often fight for resources. With Spark-on-K8s, you use Namespaces and ResourceQuotas. You can carve out a specific namespace for the Data Science team, limiting their memory and CPU usage via K8s LimitRanges, ensuring that the Fraud team’s streaming jobs are never starved of resources.

Best Practices for Advanced Deployments

Moving from a local experiment to a production-grade Spark-on-K8s platform requires more than just a

text
spark-submit
command.

1. Image Management

Do not use the default Spark image for production. Create a custom Dockerfile that includes the specific JARs (like S3 or GCS connectors) your jobs require. Keep your images slim to minimize startup time—the faster a pod pulls an image, the faster your job starts.

dockerfile
# Optimized Dockerfile example
FROM apache/spark:3.4.0
USER root
RUN apt-get update && apt-get install -y --no-install-recommends \
    python3-pandas \
    && rm -rf /var/lib/apt/lists/*
COPY jars/my-custom-connector.jar /opt/spark/jars/
USER spark

2. Leverage Pod Templates

As you move to advanced setups,

text
spark-submit
flags become unmanageable. Use Pod Templates. They allow you to define the base configuration (sidecars, node affinity, volumes) in a YAML file, keeping your submission commands clean.

yaml
# pod-template.yaml
apiVersion: v1
kind: Pod
spec:
  containers:
    - name: spark-kubernetes-driver
      volumeMounts:
        - name: secret-volume
          mountPath: /etc/secrets
  volumes:
    - name: secret-volume
      secret:
        secretName: my-cloud-credentials

3. Graceful Decommissioning

One of the biggest challenges in distributed systems is handling node preemptions. Always enable Spark Decommissioning. This allows Spark to migrate state away from an executor before the K8s node kills it, significantly improving job reliability on spot/preemptible instances.

properties
# Add these to your Spark configuration
spark.decommission.enabled=true
spark.storage.decommission.enabled=true
spark.storage.decommission.rddBlocks.enabled=true

Performance Considerations

While Kubernetes provides flexibility, it introduces network overhead.

  • Data Locality: Unlike HDFS-aware Spark, Kubernetes generally lacks inherent data locality. Ensure your Spark jobs are processing data from high-throughput object stores (S3/GCS/Azure Blob) and that your worker nodes are geographically close to your data buckets to minimize latency.
  • Shuffle Service: The "External Shuffle Service" is a legacy concept in K8s. For large shuffles, favor the use of Remote Shuffle Service (like Apache Celeborn or uniffle) to decouple shuffle data from the executor pod's lifecycle.

Summary Checklist for Success

  1. Security: Never run Spark jobs as the
    text
    root
    user. Always define a ServiceAccount with RBAC rules scoped strictly to the namespace of the job.
  2. Observability: Implement a Prometheus/Grafana stack and ensure your Spark jobs are emitting metrics. The default Spark UI is helpful for debugging, but it disappears when the driver pod dies. Use the Spark History Server.
  3. Efficiency: Always use resource requests and limits. Kubernetes will evict pods that exceed their memory limits, which is a common cause of mysterious "Container Killed" errors in Spark.

Looking Ahead

In this book, we will dive deeper into tuning the JVM, managing complex dependency injection, orchestrating Spark workflows with tools like Apache Airflow and Kubeflow, and debugging the most cryptic network errors you will encounter in distributed systems.

You have already taken the first step by moving your compute to the cloud-native standard. Now, let's learn how to make it performant.

What You Learned

  • 1

    Running Apache Spark on Kubernetes replaces rigid, static clusters with elastic, workload-based scheduling.

  • 2

    Spark jobs should be treated as ephemeral, self-healing tasks that utilize Kubernetes pods for native resource management.

  • 3

    Transitioning to Kubernetes enables unified operational maturity by treating big data processing with the same declarative infrastructure patterns used for microservices.

📖 Key Terms

Spark Driver Pod

The containerized pod that hosts the Spark Driver process, responsible for task scheduling and coordination.

Spark Executor Pod

Worker pods created by the Driver to execute tasks and store data in memory or local disk.

Dynamic Resource Allocation

A Spark feature that scales the number of executor pods based on the workload demands within the Kubernetes cluster.

Container Image

The Docker or OCI-compliant image containing the Spark distribution, dependencies, and application code required to run the job.

Namespace

A logical Kubernetes cluster partition used to isolate Spark application resources and manage multi-tenancy.

Quiz requires login

Sign in to take the quiz and track your progress.