Hướng dẫn toàn diện về Spark Operator cho DevOps. Triển khai Apache Spark trên Kubernetes với Spark Operator: Driver, Executor và Dynamic Allocation

Giới thiệu
Apache Spark là một trong những nền tảng xử lý dữ liệu lớn mạnh mẽ nhất hiện nay. Tuy nhiên, việc triển khai Spark trên Kubernetes trước đây đòi hỏi nhiều thao tác thủ công. Spark Operator ra đời đã giúc giải quyết bài toán này bằng cách cung cấp một cách triển khai declarative dựa trên Custom Resource Definition (CRD) trong Kubernetes.
Khi triển khai Apache Spark trong môi trường Kubernetes, chúng ta sử dụng Spark Operator để giúp đơn giản hoá việc quản lý và chạy các ứng dụng Spark. Spark Operator hoạt động dựa trên CRD (CustomResourceDefinition) có tên là SparkApplication
, cho phép bạn định nghĩa các ứng dụng Spark bằng YAML tương tự như các tài nguyên Kubernetes khác.
Spark Operator là gì?
Spark Operator là một Kubernetes Operator được Google phát triển, giúc quản lý và vận hành Spark job trên Kubernetes thông qua YAML CRD. Khi sử dụng, bạn chỉ cần viết một đối tượng SparkApplication
và Spark Operator sẽ lo toàn bộ vòng đời job.
Kiến trúc Spark Operator
Spark Operator bao gồm hai thành phần:
Controller: Theo dõi các đối tượng
SparkApplication
, submit job, theo dõi trạng thái, restart job...Webhook (tuỳ chọn): Hỗ trợ validate và mutate các CRD SparkApplication.
Quy trình hoạt động:
DevOps tạo một đối tượng SparkApplication.
Operator submit job cho Spark driver pod.
Driver tạo các executor pod.
Operator theo dõi trạng thái job.
Cài đặt Spark Operator bằng Helm
helm repo add spark-operator https://googlecloudplatform.github.io/spark-on-k8s-operator
helm repo update
helm install spark-operator spark-operator/spark-operator \
--namespace spark-operator \
--create-namespace \
--set sparkJobNamespace=default \
--set webhook.enable=true
Lưu ý: Tạo sẵn service account
spark
và role binding nếu cần thiết.
Viết SparkApplication
Ví dụ chạy Spark Pi (Scala):
apiVersion: sparkoperator.k8s.io/v1beta2
kind: SparkApplication
metadata:
name: spark-pi
namespace: default
spec:
type: Scala
mode: cluster
image: gcr.io/spark-operator/spark:v3.3.0
imagePullPolicy: Always
mainClass: org.apache.spark.examples.SparkPi
mainApplicationFile: local:///opt/spark/examples/jars/spark-examples_2.12-3.3.0.jar
sparkVersion: "3.3.0"
restartPolicy:
type: Never
driver:
cores: 1
memory: "512m"
serviceAccount: spark
executor:
cores: 1
instances: 2
memory: "512m"
Ví dụ chạy Spark job Python:
spec:
type: Python
pythonVersion: "3"
mainApplicationFile: local:///opt/spark/app/wordcount.py
File .py cần được đóng gói trong Docker image.
1. Driver là gì?
Driver là thành phần trung tâm của ứng dụng Spark. Nó có trách nhiệm:
Lập kế hoạch thực thi DAG.
Gửi các task tới các executor.
Theo dõi và giám sát quá trình thực thi.
Trên Kubernetes, Driver sẽ được triển khai dưới dạng một Pod, có thể sử dụng serviceAccount để có quyền tương tác với Kubernetes API nhằm tạo ra các executor Pod.
2. Executor là gì?
Executor là nơi thực thi thực tế các task Spark. Mỗi executor là một Pod độc lập trên Kubernetes, có tài nguyên (CPU, RAM) riêng biệt. Mỗi executor thực thi một phần công việc của toàn bộ ứng dụng Spark.
Khi ứng dụng kết thúc, các executor sẽ được tự động xoá để giải phóng tài nguyên.
🧱 Cách hoạt động của Spark trên Kubernetes
Spark Operator nhận YAML (kiểu
SparkApplication
) → tạo Pod Driver.Driver Pod khởi động:
Tự đăng ký với Kubernetes.
Yêu cầu Kubernetes tạo các Executor Pod.
Executor Pod được tạo (theo cấu hình trong YAML).
Driver gửi task cho Executor → Executor xử lý và trả kết quả.
Khi job hoàn thành:
Spark Operator theo dõi trạng thái job và đánh dấu thành công/thất bại.
Các Pod không còn cần thiết sẽ bị xoá.
Static và Dynamic Executor Allocation
1. Static Executor Allocation
Đây là cách đơn giản và phổ biến nhất khi chạy Spark trên Kubernetes. Bạn khai báo số lượng executor cố định từ đầu trong YAML.
Ví dụ:
spec:
executor:
instances: 3
Điều này sẽ tạo ra 3 executor pod, và giữ nguyên trong suốt vòng đời của ứng dụng.
2. Dynamic Executor Allocation
Đây là cơ chế thông minh hơn, cho phép Spark tự động tăng hoặc giảm số lượng executor tùy theo workload. Tuy nhiên, trên Kubernetes, tính năng này cần được cấu hình thêm do Spark mặc định yêu cầu External Shuffle Service.
Từ Spark 3.2+, bạn có thể bật tính năng shuffle tracking
để sử dụng dynamic allocation mà không cần external shuffle service.
Cấu hình cần thiết:
sparkConf:
"spark.dynamicAllocation.enabled": "true"
"spark.dynamicAllocation.shuffleTracking.enabled": "true"
"spark.shuffle.service.enabled": "false"
"spark.dynamicAllocation.minExecutors": "1"
"spark.dynamicAllocation.maxExecutors": "5"
III. Ví dụ thực tế với Spark 3.3.0
1. SparkApplication dùng static executor
apiVersion: sparkoperator.k8s.io/v1beta2
kind: SparkApplication
metadata:
name: spark-pi-static
namespace: default
spec:
type: Scala
mode: cluster
image: gcr.io/spark-operator/spark:v3.3.0
imagePullPolicy: Always
mainClass: org.apache.spark.examples.SparkPi
mainApplicationFile: "local:///opt/spark/examples/jars/spark-examples_2.12-3.3.0.jar"
sparkVersion: "3.3.0"
restartPolicy:
type: Never
driver:
cores: 1
coreLimit: "1200m"
memory: "512m"
serviceAccount: spark
executor:
cores: 1
instances: 3
memory: "512m"
Thành phần | Đặc điểm khi chạy trên Kubernetes |
Driver | Là một Pod, khởi tạo bởi Spark Operator |
Executor | Mỗi executor là một Pod riêng biệt |
Static Allocation | Dễ dùng, cấu hình ổn định |
Dynamic Allocation | Phức tạp hơn, cần cấu hình shuffle |
2. SparkApplication dùng dynamic executor
apiVersion: sparkoperator.k8s.io/v1beta2
kind: SparkApplication
metadata:
name: spark-pi-dynamic
namespace: default
spec:
type: Scala
mode: cluster
image: gcr.io/spark-operator/spark:v3.3.0
imagePullPolicy: Always
mainClass: org.apache.spark.examples.SparkPi
mainApplicationFile: "local:///opt/spark/examples/jars/spark-examples_2.12-3.3.0.jar"
sparkVersion: "3.3.0"
restartPolicy:
type: Never
sparkConf:
"spark.dynamicAllocation.enabled": "true"
"spark.dynamicAllocation.shuffleTracking.enabled": "true"
"spark.shuffle.service.enabled": "false"
"spark.dynamicAllocation.minExecutors": "1"
"spark.dynamicAllocation.maxExecutors": "5"
driver:
cores: 1
memory: "512m"
serviceAccount: spark
executor:
cores: 1
memory: "512m"
Nếu bạn muốn dynamic executor allocation trên Kubernetes với Spark 3.3.0, bạn cần:
Bật dynamic allocation trong
sparkConf
.Tắt external shuffle service (hoặc dùng workaround với shuffle local).
Cho phép executor pod được tạo động.
IV. Cấu hình ServiceAccount cho Driver
Để Driver có thể tạo được các Executor Pod, bạn cần tạo một ServiceAccount và cấp quyền edit
như sau:
kubectl create serviceaccount spark
kubectl create clusterrolebinding spark-role --clusterrole=edit --serviceaccount=default:spark --namespace=default
V. Cài đặt Spark Operator bằng Helm
Bạn có thể triển khai Spark Operator dễ dàng bằng Helm:
helm repo add spark-operator https://googlecloudplatform.github.io/spark-on-k8s-operator
helm install spark-operator spark-operator/spark-operator \
--namespace spark-operator --create-namespace \
--set sparkJobNamespace=default
Subscribe to my newsletter
Read articles from Kilo directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
