Veri Bilimi Okulu

Apache Spark'ı Kubernetes Üzerinde Çalıştırmak: Sıfırdan Canlı Ortama Tam Rehber
Apache Spark’ı Kubernetes Üzerinde Çalıştırmak: Sıfırdan Canlı Ortama Tam Rehber
spark-kubernetes-kapak

Loading

Eğer büyük veri (big data) dünyasının içindeysek, Apache Spark’ın adını mutlaka duymuşuzdur. Yıllardır YARN üzerinde, standalone modda veya Mesos ile çalıştırdığımız bu güçlü dağıtık hesaplama motorunu (distributed computing engine) artık Kubernetes üzerinde, hem de “native” yani yerel olarak çalıştırabiliyoruz. Spark 2.3 ile başlayan bu yolculuk, 2026 yılında Spark 4.1’e ve Apache vakfının resmi Spark Kubernetes Operator‘üne kadar geldi [1][2].

Bu yazıda, Spark’ı Kubernetes üzerinde çalıştırmanın inceliklerini tek tek ele alacağız. Mimariden başlayıp pod template’lere, dinamik kaynak tahsisinden (dynamic resource allocation) shuffle servisine, custom scheduler’lardan GPU desteğine kadar her konuya gireceğiz. Hem klasik spark-submit yaklaşımını hem de operator pattern’i karşılaştırmalı olarak inceleyeceğiz. Hadi başlayalım.


İçindekiler

  1. Neden Spark’ı Kubernetes’te Çalıştıralım?
  2. Mimariyi Anlamak: Driver, Executor ve Pod’lar
  3. Docker İmajları: Spark’ın Konteyner Hali
  4. En Basit Hali: spark-submit ile İş Göndermek
  5. Pod Template: İnce Ayar İçin Süper Güç
  6. Volume ve Storage Yönetimi
  7. Bağımlılık Yönetimi (Dependency Management)
  8. Secret Yönetimi
  9. Dynamic Resource Allocation (DRA): Ölçeklenebilirliğin Kalbi
  10. Remote / External Shuffle Service: Apache Celeborn ile Tanışın
  11. Operator Pattern: Deklaratif Yaklaşımla Tanışın
  12. Custom Scheduler’lar: Volcano ve Apache YuniKorn
  13. İzleme ve Gözlemlenebilirlik (Observability)
  14. Cluster Otomatik Ölçeklendirme: Cluster Autoscaler ve Karpenter
  15. GPU Desteği
  16. IPv4/IPv6 Dual Stack
  17. Güvenlik
  18. Spark 4.x ve Yeni Özellikler
  19. Canlı Ortam İçin Best Practices
  20. Bulut Sağlayıcı Entegrasyonları
  21. Sorun Giderme İpuçları
  22. Sonuç
  23. Kaynaklar

1. Neden Spark’ı Kubernetes’te Çalıştıralım?

Spark uzun yıllar boyunca Hadoop YARN ile evlenmişti. Bu çiftin işi gayet iyi görüyordu ama bulut-doğal (cloud-native) dünyaya geçtikçe bazı sınırlamalar hissedilmeye başladı. Kubernetes, konteyner orkestrasyonunun (container orchestration) fiili standardı haline geldi ve veri ekipleri zaten uygulamalarının çoğunu Kubernetes’te çalıştırıyordu. Spark’ı da aynı altyapıya taşımak çok mantıklıydı [3].

Kubernetes’in getirdiği avantajlar şunlar [9][10]:

  • Birleşik platform (unified platform): Mikroservislerimiz, makine öğrenmesi (machine learning) iş yüklerimiz ve Spark işlerimiz aynı cluster üzerinde çalışıyor. Ayrı YARN cluster’ı bakmaya gerek yok.
  • Konteyner izolasyonu (container isolation): Her Spark uygulaması kendi imajını (image), kendi bağımlılıklarını ve kendi Python sürümünü kullanabiliyor. “Bağımlılık cehennemi” (dependency hell) sorunu büyük ölçüde çözülüyor.
  • Esneklik (elasticity): Kubernetes Cluster Autoscaler veya Karpenter gibi araçlar, talebe göre node’ları otomatik açıp kapatıyor. İdle (boşta) Spark cluster’ı tutmak zorunda kalmıyoruz.
  • Çok kiracılı (multi-tenant) yapı: Namespace, ResourceQuota ve RBAC kullanarak farklı ekiplerin kaynaklarını adil ve izole şekilde paylaştırabiliyoruz.
  • Hata toleransı (fault tolerance): Pod yeniden başlatma, node taşıma gibi Kubernetes’in yerleşik yetenekleri Spark’a da uygulanıyor [10].

Tek bir uyarı: Spark’ı Kubernetes’te çalıştırmak “tak çalıştır” değil. Shuffle yönetimi, pod startup süresi, image build pipeline’ı gibi konularda kafa yormak gerekiyor. Bu yazının amacı tam da bu kafa yormayı kolaylaştırmak.


2. Mimariyi Anlamak: Driver, Executor ve Pod’lar

Spark’ın bilindik mimarisini hatırlayalım: Bir driver (sürücü) süreç vardır, bu işi koordine eder; bir veya daha fazla executor (çalıştırıcı) süreç vardır, bunlar gerçek hesaplamayı yapar. Kubernetes üzerinde bu mimari birebir korunuyor, sadece her bileşen artık bir pod olarak çalışıyor [2][13].

İş akışı şöyle işliyor [2]:

  1. spark-submit komutu, Kubernetes API server’a bir driver pod oluşturma isteği gönderiyor.
  2. Driver pod ayağa kalkıyor ve içindeki Spark driver süreci başlıyor.
  3. Driver, Kubernetes API’sine yeni executor pod’ları oluşturma istekleri gönderiyor (fabric8 kütüphanesi üzerinden).
  4. Executor pod’lar driver’a bağlanıyor ve görevleri çalıştırmaya başlıyor.
  5. Uygulama bittiğinde executor’lar siliniyor ama driver pod “Completed” durumunda kalıyor — logları incelemek için. Bu durumdayken CPU veya bellek tüketmiyor.

Bir önemli detay: Driver pod bir kez “Completed” duruma geçtikten sonra Kubernetes’in normal çöp toplama (garbage collection) mekanizmaları devreye girene kadar veya elle silene kadar API server’da kalıyor. Bunun farkında olmamız önemli, yoksa namespace’ler birikmiş driver pod’larıyla dolup taşıyor.

2.1 Cluster Mode vs Client Mode

Spark’ın iki dağıtım modu Kubernetes’te de mevcut:

Cluster mode: Driver, cluster içinde bir pod olarak çalışıyor. Canlı ortam için tercih edilen mod budur — spark-submit komutu işi başlattıktan sonra çıkabilir, driver cluster’da yaşamına devam eder [2].

Client mode: Driver, spark-submit‘i çalıştırdığımız makinede (veya bir pod içinde ama dışarıdaki bir süreç olarak) çalışıyor. Spark Connect, Jupyter notebook, interaktif analiz gibi senaryolarda işe yarıyor. Burada dikkat etmemiz gereken birkaç nokta var [2]:

  • Executor’lar driver’a bağlanabilmeli, dolayısıyla driver’ın hostname’i ve portu executor’lardan erişilebilir olmalı. Bunun için “headless service” kullanmak yaygın bir kalıp.
  • Eğer driver bir pod içinde çalışıyorsa, spark.kubernetes.driver.pod.name özelliğini ayarlamayı unutmayalım. Bu sayede executor’lara OwnerReference atanır ve driver silindiğinde executor’lar otomatik olarak temizlenir.

3. Docker İmajları: Spark’ın Konteyner Hali

Spark, kendi Dockerfile’larıyla geliyor. kubernetes/dockerfiles/ dizininde bunları bulabilir, ihtiyaca göre özelleştirebiliriz [2]. Dahili bin/docker-image-tool.sh script’i imajı build edip registry’ye push etmemizi kolaylaştırıyor:

$ ./bin/docker-image-tool.sh -r myregistry.com/team -t 4.1.0 build
$ ./bin/docker-image-tool.sh -r myregistry.com/team -t 4.1.0 push

PySpark veya SparkR için ek imajlar gerekiyorsa -p ve -R parametrelerini kullanmamız gerekiyor [2]. Hazır imaj kullanmak istiyorsak Docker Hub’da apache/spark:4.1.0 gibi resmi imajlar mevcut [2].

Güvenlik açısından dikkat: Resmi imajlar varsayılan olarak UID 185 kullanıyor [2]. Canlı ortamda kendi UID/GID’mizle, root grubunu da supplementary group olarak ekleyerek özel imajlar build etmemiz öneriliyor. Pod Security Admission Controller’ı kullanarak hostPath gibi riskli volume mount’larını da kısıtlamak iyi bir fikir.


4. En Basit Hali: spark-submit ile İş Göndermek

Bir Spark Pi örneğini cluster mode’da göndermek aslında çok basit:

$ ./bin/spark-submit \
    --master k8s://https://<k8s-apiserver-host>:<k8s-apiserver-port> \
    --deploy-mode cluster \
    --name spark-pi \
    --class org.apache.spark.examples.SparkPi \
    --conf spark.executor.instances=5 \
    --conf spark.kubernetes.container.image=apache/spark:4.1.0 \
    local:///opt/spark/examples/jars/spark-examples_2.13-4.1.0.jar

Buradaki ipucu: --master parametresinin k8s:// ile başladığını ve port mutlaka belirtilmesi gerektiğini unutmayalım. Eğer protokol yazmazsak HTTPS varsayılıyor, dolayısıyla k8s://example.com:443 ile k8s://https://example.com:443 aynı anlama geliyor [2].

Uygulamayı bulmak için API server URL’sini şöyle alabiliriz:

$ kubectl cluster-info
Kubernetes master is running at http://127.0.0.1:6443

Veya kubectl proxy çalıştırıp --master k8s://http://127.0.0.1:8001 diyebiliriz [2]. Proxy yöntemi yerel geliştirmede oldukça pratik.

4.1 Servis Hesabı (Service Account) ve RBAC

Driver pod, executor’ları yaratmak için Kubernetes API’sine erişmek zorunda. Bu erişim, pod’un kullandığı service account üzerinden yetkilendiriliyor (RBAC) [2]. Varsayılan service account genellikle yeterli izinlere sahip değil, kendi service account’umuzu oluşturup edit ClusterRole’ünü atamamız gerekiyor:

$ kubectl create serviceaccount spark
$ kubectl create clusterrolebinding spark-role \
    --clusterrole=edit \
    --serviceaccount=default:spark \
    --namespace=default

Sonra --conf spark.kubernetes.authenticate.driver.serviceAccountName=spark parametresiyle bu service account’u kullanmasını sağlıyoruz [2]. Dikkat edilmesi gereken nokta: Driver, executor pod’larını sadece kendi namespace’inde yarattığı için bir Role da yeterli, ClusterRole şart değil. Canlı ortamda minimum yetki ilkesini (least privilege) uygulamak iyi olur.

4.2 Namespace ve Resource Quota

Kubernetes namespace’leri farklı kiracılar arasında izolasyon sağlamamızı kolaylaştırıyor. spark.kubernetes.namespace ile Spark uygulamamızın hangi namespace’te çalışacağını belirleyebiliyoruz [2]. ResourceQuota ile namespace bazında CPU, bellek, pod sayısı gibi sınırlar koyabiliyoruz [9]. Bu, çok kiracılı (multi-tenant) ortamlarda altın değerinde bir özellik.


5. Pod Template: İnce Ayar İçin Süper Güç

Spark’ın doğrudan desteklemediği pod özelliklerini ayarlamak için pod template dosyaları kullanabiliyoruz. Driver ve executor için ayrı template’ler tanımlayabiliyoruz [2]:

--conf spark.kubernetes.driver.podTemplateFile=s3a://bucket/driver.yml
--conf spark.kubernetes.executor.podTemplateFile=s3a://bucket/executor.yml

Bu template’ler bir başlangıç noktası gibi düşünülebilir — Spark bazı alanları (örneğin pod adı, namespace, restart policy, container imajı) zorla override ediyor [2]. Ama node selector, affinity, toleration, init container, sidecar container, security context gibi pek çok alanı template üzerinden esnek şekilde ayarlayabiliyoruz.

Pratik bir örnek olarak şunu söyleyebiliriz: GPU node’larına yönlendirme, log sidecar ekleme, init container ile dosya indirme, security context ile non-root kullanıcı zorlama gibi pek çok şeyi pod template ile yapıyoruz.


6. Volume ve Storage Yönetimi

Spark on Kubernetes dört tip Kubernetes volume’u destekliyor: hostPath, emptyDir, nfs ve persistentVolumeClaim [2]. Mount etmek şu formatla yapılıyor:

--conf spark.kubernetes.driver.volumes.persistentVolumeClaim.checkpoint.mount.path=/checkpoint
--conf spark.kubernetes.driver.volumes.persistentVolumeClaim.checkpoint.options.claimName=spark-pvc

İlginç bir özellik: Executor’lar için OnDemand claim adı kullanırsak, her executor için dinamik olarak bir PVC oluşturuluyor [2]:

spark.kubernetes.executor.volumes.persistentVolumeClaim.data.options.claimName=OnDemand
spark.kubernetes.executor.volumes.persistentVolumeClaim.data.options.storageClass=gp3
spark.kubernetes.executor.volumes.persistentVolumeClaim.data.options.sizeLimit=500Gi

6.1 PVC-Oriented Executor Allocation

Spark 3.4 ile gelen güzel bir özellik: Driver, on-demand PVC’lerin sahibi olabiliyor ve bu PVC’ler executor’lar arasında yeniden kullanılabiliyor [2]:

spark.kubernetes.driver.ownPersistentVolumeClaim=true
spark.kubernetes.driver.reusePersistentVolumeClaim=true
spark.kubernetes.driver.waitToReusePersistentVolumeClaim=true

Bu özellik özellikle dynamic allocation senaryolarında PVC oluşturma/silme yükünü azaltıyor. Birden fazla executor aynı PVC’yi sırayla kullanabiliyor.

6.2 Local Storage ve tmpfs

Volume adı spark-local-dir- ile başlıyorsa Spark bunu shuffle ve spill için yerel depolama olarak kullanıyor [2]:

spark.kubernetes.executor.volumes.persistentVolumeClaim.spark-local-dir-1.options.claimName=OnDemand
spark.kubernetes.executor.volumes.persistentVolumeClaim.spark-local-dir-1.options.storageClass=gp3
spark.kubernetes.executor.volumes.persistentVolumeClaim.spark-local-dir-1.mount.path=/data

Eğer hiçbir volume tanımlamazsak Spark emptyDir kullanıyor ve bu da node’un disk’ine düşüyor. Diskless node’larda (örneğin remote storage kullanan ortamlarda) spark.kubernetes.local.dirs.tmpfs=true ile bu volume’leri RAM-backed (tmpfs) yapabiliyoruz [2]. Tabii bu durumda bellek hesabını da güncellememiz gerekiyor — spark.driver.memoryOverheadFactor ve spark.executor.memoryOverheadFactor değerlerini artırmamız öneriliyor.


7. Bağımlılık Yönetimi (Dependency Management)

Spark uygulamamızın bağımlılıklarını birkaç farklı yolla yönetebiliyoruz [2]:

  • local:// URI: Bağımlılık zaten Docker imajının içinde. En performanslı seçenek.
  • http://, s3a://, hdfs://: Uzak bir kaynaktan indiriliyor.
  • file:// veya tam yol: spark-submit‘i çalıştıran istemcideki dosya, S3 gibi bir Hadoop uyumlu dosya sistemine upload ediliyor (spark.kubernetes.file.upload.path ile).

S3 üzerinden upload örneği:

--packages org.apache.hadoop:hadoop-aws:3.4.1
--conf spark.kubernetes.file.upload.path=s3a://my-bucket/spark-uploads
--conf spark.hadoop.fs.s3a.access.key=...
--conf spark.hadoop.fs.s3a.secret.key=....
file:///full/path/to/app.jar

Spark, JAR dosyasını rastgele bir alt dizine yüklüyor — bu sayede paralel çalışan iş’lerin birbiriyle çakışması önleniyor [2]. Ama uyarı: Tüm istemci tarafı bağımlılıklar düz bir dizin yapısıyla yükleniyor, dolayısıyla dosya adlarının benzersiz olması önemli.

Spark 4.0 ile gelen güzel bir özellik: spark.kubernetes.jars.avoidDownloadSchemes ile büyük JAR’ların driver disk’ine indirilmemesini sağlayabiliyoruz [2]. Yüksek executor sayılarında eşzamanlı indirme ağı doyurabiliyor; bu özellik o sıkıntıyı önlüyor.


8. Secret Yönetimi

Kubernetes Secret’lerini Spark’ın driver ve executor’larına mount etmek oldukça basit [2]:

--conf spark.kubernetes.driver.secrets.spark-secret=/etc/secrets
--conf spark.kubernetes.executor.secrets.spark-secret=/etc/secrets

Ortam değişkeni olarak inject etmek istersek:

--conf spark.kubernetes.driver.secretKeyRef.DB_PASSWORD=db-secret:password

Kerberos için de ayrı destek var: spark.kubernetes.kerberos.krb5.path veya spark.kubernetes.kerberos.krb5.configMapName ile krb5.conf’u mount edebiliyoruz [2]. Hadoop konfigürasyonu için spark.kubernetes.hadoop.configMapName kullanılıyor.


9. Dynamic Resource Allocation (DRA): Ölçeklenebilirliğin Kalbi

Spark’ın güzelliklerinden biri, iş yüküne göre executor sayısını dinamik olarak değiştirebilmesi. YARN üzerinde bunun için External Shuffle Service (ESS) gerekiyordu. Kubernetes’te ESS şu an mevcut değil [11][12], ama bunun yerine başka çözümler var.

9.1 Shuffle Tracking: Native Çözüm

Spark 3.0 ile (SPARK-27963) ile birlikte, dynamic allocation’ı external shuffle service olmadan kullanabilmek için Shuffle Tracking özelliği geldi [12][20]. İşin mantığı şu: Spark, hangi executor’ın hangi shuffle dosyalarını tuttuğunu izliyor ve shuffle dosyaları gerekli olmadığında executor’ı kaldırıyor.

Kullanmak için:

spark.dynamicAllocation.enabled=true
spark.dynamicAllocation.shuffleTracking.enabled=true
spark.dynamicAllocation.shuffleTracking.timeout=30min
spark.dynamicAllocation.minExecutors=1
spark.dynamicAllocation.maxExecutors=100

Önemli not: shuffleTracking.timeout varsayılan olarak infinity. Bu, executor’lar shuffle verisini tuttuğu sürece kaldırılmıyor demek. Canlı ortamda mantıklı bir timeout (örneğin 30 dakika) belirlemek iyi bir fikir, ama bu durumda shuffle verisi gerekirse yeniden hesaplanmak zorunda kalabilir [12].

Bir de spark.cleaner.periodicGC.interval=5min gibi bir ayarla Spark’ın shuffle verilerini daha aktif şekilde GC etmesini sağlamak öneriliyor [20].

9.2 KubernetesLocalDiskShuffleDataIO: Shuffle Veri Kurtarma

Spark, shuffle verilerini executor crash’lerinden kurtarmak için KubernetesLocalDiskShuffleDataIO adında dahili bir plugin sunuyor [2]:

spark.kubernetes.executor.volumes.persistentVolumeClaim.spark-local-dir-1.mount.path=/data/spark-x/executor-x
spark.shuffle.sort.io.plugin.class=org.apache.spark.shuffle.KubernetesLocalDiskShuffleDataIO

spark.kubernetes.driver.waitToReusePersistentVolumeClaim=true ile birleştirildiğinde, bir executor’un shuffle verileri başka bir executor tarafından devralınabiliyor. Spot/preemptible node senaryolarında çok değerli.


10. Remote / External Shuffle Service: Apache Celeborn ile Tanışın

Shuffle Tracking güzel ama bazı sınırlamaları var: Executor shuffle verisini tuttuğu sürece scale-down yapılamıyor, bu da kaynak verimliliğini düşürüyor. Büyük ölçekli, shuffle-yoğun iş yükleri için Remote Shuffle Service (RSS) çözümleri devreye giriyor [21][26].

Açık kaynak dünyasında birkaç RSS projesi var [22]:

  • Apache Celeborn (eski adıyla Alibaba RSS) — En olgun ve aktif olarak geliştirilen seçenek
  • Apache Uniffle (eski Tencent)
  • LinkedIn Magnet (Spark’a katkıda bulunuldu)
  • Uber Zeus ve Facebook Riffle (daha az kullanılan)

10.1 Apache Celeborn Mimarisi

Celeborn üç ana bileşenden oluşuyor [26]:

  • Master: Tüm kaynakları yönetiyor, durumu Raft ile sync ediyor
  • Worker: Yazma/okuma isteklerini işliyor, her reducer için veri merge ediyor
  • LifecycleManager: Spark driver içinde çalışıyor, her shuffle’ın metadata’sını tutuyor

Çalışma akışı push-based shuffle write ve merge-based shuffle read mantığında [21]. Mapper’lar veriyi yerel diske yazmak yerine doğrudan worker’lara gönderiyor; worker’lar veriyi merge edip diske yazıyor. Bu sayede:

  • Storage ve compute ayrışıyor (disaggregated) — Cloud-native mimariye çok uygun
  • MxN ağ bağlantıları azaltılıyor — Daha az random küçük dosya I/O’su
  • Executor’lar shuffle verisini tutmadığı için DRA çok daha verimli çalışıyor

Celeborn ayrıca worker’lar arasında veriyi replikasyon ile koruyor (asenkron olarak), high availability sunuyor [22].

10.2 Spark ile Celeborn Konfigürasyonu

Spark 3.5+ ile Celeborn’u şöyle ayarlıyoruz [21][23]:

spark.shuffle.manager=org.apache.spark.shuffle.celeborn.SparkShuffleManager
spark.serializer=org.apache.spark.serializer.KryoSerializer
spark.celeborn.master.endpoints=clb-1:9097,clb-2:9097,clb-3:9097
spark.shuffle.sort.io.plugin.class=org.apache.spark.shuffle.celeborn.CelebornShuffleDataIO
spark.dynamicAllocation.enabled=true
spark.dynamicAllocation.shuffleTracking.enabled=false  # Celeborn varken kapalı tutuyoruz
spark.celeborn.client.push.replicate.enabled=true

Spark 3.4+ için shuffleTracking.enabled=false olmalı ki idle executor’lar hızlıca serbest bırakılabilsin [20]. Celeborn 0.4.0 itibarıyla Spark 2.4’ten 4.0’a kadar geniş destek sunuyor [26].


11. Operator Pattern: Deklaratif Yaklaşımla Tanışın

Buraya kadar spark-submit ile çalıştık. Bu yöntem işe yarıyor ama bazı sıkıntıları var:

  • Her iş için bir CI/CD pipeline veya elle çağrı gerekiyor
  • Cron tabanlı zamanlanmış işleri yönetmek zor
  • “Bu uygulamanın durumu ne?” sorusunu yanıtlamak için Kubernetes nesnelerini elle takip etmek gerekiyor
  • Otomatik yeniden deneme (retry), restart policy, başarısızlık yönetimi gibi özellikler için ek araçlar yazmak gerekiyor

İşte bu noktada Kubernetes’in ünlü Operator Pattern‘ı devreye giriyor [3]. Operator, bir CustomResourceDefinition (CRD) ve onu izleyen bir controller’dan oluşuyor. Spark için iki büyük operator var.

11.1 Kubeflow Spark Operator (Eski Google Operator)

Bu operator’ün ilginç bir tarihi var. Başlangıçta Google Cloud Platform tarafından geliştirildi (GoogleCloudPlatform/spark-on-k8s-operator). 2.3k+ GitHub yıldızı ve 1.3k+ fork’la oldukça popülerdi. Nisan 2024’te proje Kubeflow’a devredildi ve kubeflow/spark-operator adıyla yeni bir döneme girdi [5].

Özellikleri [3][4]:

  • Spark 2.3 ve sonrasını destekliyor
  • SparkApplication ve ScheduledSparkApplication (cron) CRD’leri var
  • Kullanıcı adına otomatik spark-submit çalıştırıyor
  • Mutating admission webhook ile pod’lara ConfigMap mount, affinity/anti-affinity, toleration ekliyor
  • Otomatik yeniden submit ve restart policy’si
  • Doğrusal back-off ile otomatik retry
  • Prometheus’a metrik export

Helm ile kurulumu basit [4]:

helm repo add --force-update spark-operator https://kubeflow.github.io/spark-operator
helm install spark-operator spark-operator/spark-operator \
  --namespace spark-operator \
  --create-namespace \
  --wait

Bir SparkApplication örneği:

apiVersion: sparkoperator.k8s.io/v1beta2
kind: SparkApplication
metadata:
  name: spark-pi
  namespace: spark-jobs
spec:
  type: Scala
  mode: cluster
  image: docker.io/library/spark:4.0.0
  imagePullPolicy: IfNotPresent
  mainClass: org.apache.spark.examples.SparkPi
  mainApplicationFile: local:///opt/spark/examples/jars/spark-examples.jar
  arguments:
    - "5000"
  sparkVersion: 4.0.0
  driver:
    cores: 1
    memory: 512m
    serviceAccount: spark-operator-spark
    securityContext:
      runAsGroup: 185
      runAsUser: 185
      runAsNonRoot: true
      allowPrivilegeEscalation: false
  executor:
    instances: 3
    cores: 1
    memory: 512m

Ardından kubectl apply -f spark-pi.yaml ile gönderiyoruz, kubectl get sparkapp ile durumunu izliyoruz.

Performans açısından da fena değil. Kubeflow’un kendi benchmark’larına göre 6000 Spark uygulamasını dakikada 1000 oranında submit ettiğinde tek bir operator instance bile bu yükü kaldırabiliyor (yeterli kaynak verildiğinde) [6]. Tabii çok yüksek throughput’a ihtiyaç duyuluyorsa controller.workers parametresini artırmak veya birden fazla operator instance kullanmak gerekiyor.

11.2 Apache Spark Kubernetes Operator (Yeni Resmi)

Apache Spark projesi 2024 yılında apache/spark-kubernetes-operator adında yeni bir alt-proje (subproject) başlattı [1]. Bu operator henüz görece yeni — Ocak 2026 itibarıyla 0.7.0 sürümünde [1] — ama önemli bir farkı var: Doğrudan Apache Spark projesi tarafından geliştiriliyor ve sürdürülüyor. Yani Spark’ın ana kod tabanıyla daha sıkı entegre.

Özellikleri ve farkları:

  • Java 17+ ile yazılmış (Kubeflow operator Go ile yazılmış)
  • İki CRD sunuyor: SparkApplication ve SparkCluster
  • SparkCluster, Spark Standalone modunda kalıcı bir cluster ayağa kaldırmamızı sağlıyor [1]
  • Apache YuniKorn entegrasyonu hazır geliyor

Kurulum yine Helm ile [1]:

helm repo add spark https://apache.github.io/spark-kubernetes-operator
helm repo update
helm install spark spark/spark-kubernetes-operator

Bir SparkApplication göndermek:

$ kubectl apply -f examples/pi.yaml
$ kubectl get sparkapp
NAME   CURRENT STATE      AGE
pi     ResourceReleased   4m10s

İlginç olan kısım: SparkCluster CRD’si ile uzun ömürlü bir Spark Standalone cluster ayağa kaldırabiliyoruz [1]:

$ kubectl apply -f examples/prod-cluster-with-three-workers.yaml
$ kubectl get sparkcluster
NAME   CURRENT STATE    AGE
prod   RunningHealthy   10s

$ kubectl port-forward prod-master-0 6066 &
$ ./examples/submit-pi-to-prod.sh
{
  "action" : "CreateSubmissionResponse",
  "message" : "Driver successfully submitted as driver-20260110030233-0000",
  "serverSparkVersion" : "4.1.1",
  "submissionId" : "driver-20260110030233-0000",
  "success" : true
}

Bu, geleneksel Spark Standalone deneyimini Kubernetes üzerinde elde etmemizi sağlıyor — özellikle interaktif iş yükleri veya yeniden kullanılabilir cluster’lar için faydalı bir model [1].

11.3 Hangi Operator’ü Seçelim?

Şu an için (2026 başı):

  • Olgunluk ve ekosistem: Kubeflow Spark Operator daha olgun. Canlı ortamda yıllardır kullanılıyor, geniş bir kullanıcı tabanı var, dokümantasyon zengin.
  • Resmi destek: Apache’nin yeni operator’ü Spark projesinin kendisi tarafından geliştiriliyor; uzun vadede stratejik tercih olabilir.
  • SparkCluster CRD: Standalone cluster ihtiyacımız varsa Apache operator avantajlı.
  • Mutating webhook: Kubeflow’un webhook’u oldukça esnek özelleştirme sunuyor.

Yeni başlayan projeler için Apache operator’üne göz atmak mantıklı olabilir, ama canlı ortama geçişte mevcut Kubeflow operator’üne sadık kalmak da makul.


12. Custom Scheduler’lar: Volcano ve Apache YuniKorn

Kubernetes’in default scheduler’ı pod-by-pod (pod bazında) çalışıyor. Spark gibi gang scheduling (toplu zamanlama) gerektiren iş yükleri için bu yetersiz kalabiliyor. Düşünelim: Spark işimizin minimum 10 executor’a ihtiyacı var. Default scheduler 7 tanesini schedule eder, 3 tanesi pending kalır. Sonuç? 7 executor boşa kaynak tutar, iş ilerleyemez [16].

İşte bu noktada custom scheduler’lar devreye giriyor.

12.1 Apache Volcano

Apache Volcano (Huawei tarafından başlatılan, CNCF altında olan bir proje), HPC, AI/ML ve büyük veri iş yükleri için tasarlanmış bir scheduler [17][18]. Spark 3.3 ile Volcano, Spark on Kubernetes için resmi olarak desteklenen ilk batch scheduler oldu [18].

Volcano’nun sunduğu temel avantajlar:

  • Gang scheduling: “Tümü ya da hiçbiri” mantığı. Driver ve gerekli minimum executor sayısı hep birlikte schedule ediliyor
  • Resource reservation: Kuyruk içi kaynak rezervasyonu, açlık (starvation) sorununu önlüyor
  • Backfill: Rezerve edilmiş ama kullanılmayan kaynaklara küçük işler yerleştiriliyor
  • Queue scheduling, fair-share, priority scheduling

Spark’ta kullanmak için [2]:

--conf spark.kubernetes.scheduler.name=volcano
--conf spark.kubernetes.scheduler.volcano.podGroupTemplateFile=/path/to/podgroup-template.yaml
--conf spark.kubernetes.driver.pod.featureSteps=org.apache.spark.deploy.k8s.features.VolcanoFeatureStep
--conf spark.kubernetes.executor.pod.featureSteps=org.apache.spark.deploy.k8s.features.VolcanoFeatureStep

PodGroup template örneği [2]:

apiVersion: scheduling.volcano.sh/v1beta1
kind: PodGroup
spec:
  minMember: 1
  minResources:
    cpu: "2"
    memory: "3Gi"
  priorityClassName: system-node-critical
  queue: default

minMember ve minResources ile Spark işinin başlayabilmesi için gereken minimum kaynakları belirtiyoruz. Bu sayede driver schedule edilip executor’lar pending kalmıyor — ya tamamı çalışır, ya hiçbiri.

12.2 Apache YuniKorn

YuniKorn da bir alternatif (Cloudera, Apple, Pinterest, Visa, Uber gibi şirketler kullanıyor) [16]. YuniKorn’un farkları:

  • Hiyerarşik kuyruklar (root.engineering.team-a gibi)
  • Kuyruk min/max kapasitesi
  • Application-aware scheduling (uygulama bütünlüğünü gözeten zamanlama)
  • Hem Kubernetes hem YARN ile çalışabiliyor (hibrit ortamlar için ideal)

YuniKorn ile Spark işi göndermek [2]:

helm repo add yunikorn https://apache.github.io/yunikorn-release
helm install yunikorn yunikorn/yunikorn --namespace yunikorn \
  --version 1.7.0 --create-namespace --set embedAdmissionController=false

# Spark işi:
--conf spark.kubernetes.scheduler.name=yunikorn
--conf spark.kubernetes.driver.label.queue=root.default
--conf spark.kubernetes.executor.label.queue=root.default
--conf spark.kubernetes.driver.annotation.yunikorn.apache.org/app-id={{APP_ID}}
--conf spark.kubernetes.executor.annotation.yunikorn.apache.org/app-id={{APP_ID}}

YuniKorn’un Cloudera blog’undan öğrendiğimiz güzel bir pattern: Placeholder pod’lar [16]. Cluster cold-start senaryolarında YuniKorn placeholder pod oluşturup cluster autoscaler’ı tetikliyor; gerekli node’lar ayağa kalktığında gerçek pod’lar yerleşiyor. Bu sayede Spark’ın executor’ları batch batch oluşturmasından kaynaklanan gecikme ortadan kalkıyor.

Apache Spark Kubernetes Operator zaten YuniKorn entegrasyonuyla geliyor [1]:

$ kubectl apply -f examples/pi-on-yunikorn.yaml
$ kubectl describe pod pi-on-yunikorn-0-driver
...
Events:
  Normal  Scheduling         1s    yunikorn  pi-on-yunikorn-0-driver is queued and waiting for allocation
  Normal  Scheduled          1s    yunikorn  Successfully assigned to node docker-desktop
  Normal  PodBindSuccessful  1s    yunikorn  Pod successfully bound

12.3 Volcano mu YuniKorn mu Kueue mu?

Hızlı karşılaştırma [17]:

  • Volcano: AI/ML, HPC, deep learning için ideal. Gang scheduling ve job dependency management’ta güçlü.
  • YuniKorn: Çok kiracılı ortamlar, Kubernetes’in default scheduler’ını tamamen değiştirmek isteyenler için ideal. Hiyerarşik fairness’a güçlü vurgu.
  • Kueue: Kubernetes-native, batch için sade ve hafif. Gerekli temel özellikleri (kuyruk, kota, öncelik) sade bir API ile sunuyor.

Sektördeki yaygın kullanım göz önüne alındığında Spark için Volcano ve YuniKorn iki güçlü tercih.


13. İzleme ve Gözlemlenebilirlik (Observability)

Spark uygulamalarını canlı ortamda çalıştırırken metrikleri ve logları toplamak şart. Şanslıyız ki Spark bu konuda epey iyi destek sunuyor.

13.1 Spark UI

Driver pod’unun 4040 portu Spark UI’yi sunuyor. Erişmek için port-forward yeterli [2]:

$ kubectl port-forward <driver-pod-name> 4040:4040

Ardından http://localhost:4040. Spark 4.0 ile birlikte driver loglarını da UI üzerinden görebiliyoruz [2]:

spark.driver.log.localDir=/tmp
# http://localhost:4040/logs/

13.2 Spark History Server

Spark UI sadece uygulama çalıştığı sürece var oluyor. Uygulama bittikten sonra geçmiş işleri inceleyebilmek için History Server gerekiyor [28]:

sparkConf:
  "spark.eventLog.enabled": "true"
  "spark.eventLog.dir": "s3a://my-bucket/spark-event-logs/"

History Server’ı bir Helm chart ile kurabiliyor, S3/EFS/Azure Blob/NFS gibi dayanıklı bir storage backend kullanıyoruz. Sonra kubectl port-forward services/spark-history-server 18085:80 ile UI’ya erişiyoruz.

13.3 Prometheus Entegrasyonu

Spark 3.0 ile birlikte yerleşik PrometheusServlet geldi [28]. Bu, harici JMX exporter’a olan ihtiyacı ortadan kaldırıyor:

spark.ui.prometheus.enabled=true
spark.executor.processTreeMetrics.enabled=true
spark.kubernetes.driver.annotation.prometheus.io/scrape=true
spark.kubernetes.driver.annotation.prometheus.io/path=/metrics/executors/prometheus/
spark.kubernetes.driver.annotation.prometheus.io/port=4040

Sonra Kubernetes’te bir ServiceMonitor veya PodMonitor (Prometheus Operator kullanıyorsak) tanımlayarak Prometheus’un Spark metriklerini scrape etmesini sağlıyoruz. Endpoint’ler şunlar [28]:

  • /metrics/applications/prometheus — Application metrics
  • /metrics/executors/prometheus — Executor metrics
  • /metrics/master/prometheus — Master metrics (Standalone modunda)
  • /metrics/prometheus — Driver/Executor metrics

İçeride task metrics, JVM heap, GC, executor memory peak gibi metrikler bulunuyor [28]. Grafana ile görselleştirme bu metriklerle çok güzel oluyor.

13.4 Loglama

Pod logları kubectl logs ile alınabiliyor:

$ kubectl -n spark-jobs logs -f spark-pi-driver

Canlı ortamda bunu Fluentd, Promtail, Vector gibi log shipper’larla Loki, Elasticsearch gibi merkezi sistemlere göndermek standart pattern. Ephemeral pod’larda log kaybını önlemek için bu şart.

Bonus özellik: Spark UI’nın Executors sekmesinde executor logları için custom URL şablonu tanımlayabiliyoruz [2]:

spark.ui.custom.executor.log.url='https://log-server/log?appId=&execId='

Bu sayede UI’dan doğrudan log sistemine link verebiliyoruz.


14. Cluster Otomatik Ölçeklendirme: Cluster Autoscaler ve Karpenter

Spark’ın esnekliğini tam yaşayabilmek için Kubernetes node sayısının da iş yüküne göre değişmesi gerekiyor.

14.1 Cluster Autoscaler

Klasik çözüm. Auto Scaling Group’larla (AWS), MIG’lerle (GCP) veya VMSS’lerle (Azure) konuşarak node sayısını ayarlıyor. Stabil ama görece yavaş ve önceden tanımlanmış node group’lara bağımlı.

14.2 Karpenter: Modern Alternatif

Karpenter (orijinal olarak AWS tarafından, ama artık başka cloud sağlayıcılarda da çalışıyor) çok daha modern bir yaklaşım sunuyor [25]. Pre-defined ASG’lere ihtiyaç duymuyor, doğrudan EC2 Fleet API’sini (veya muadilini) çağırarak ihtiyaç duyduğumuz tam instance type’ı saniyeler içinde ayağa kaldırıyor [30].

Karpenter’ın Spark için faydaları:

  • Bin packing: Pod’ları en verimli şekilde mevcut node’lara yerleştiriyor
  • Spot desteği: Spot fiyat değişimlerini izleyip daha ucuz spot’lara geçebiliyor
  • Hızlı provisioning: Sub-1-minute node ekleme
  • Karışık instance type: Tek bir node pool farklı CPU, bellek, GPU konfigürasyonlarını kapsayabiliyor

Bir Karpenter NodePool örneği [25]:

apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: spark-nodes
spec:
  template:
    spec:
      requirements:
        - key: kubernetes.io/arch
          operator: In
          values: ["amd64"]
        - key: karpenter.sh/capacity-type
          operator: In
          values: ["spot", "on-demand"]
        - key: karpenter.k8s.aws/instance-category
          operator: In
          values: ["c", "m", "r"]
  disruption:
    consolidationPolicy: WhenEmptyOrUnderutilized
    consolidateAfter: 1m

Karpenter’ın 2026 itibarıyla Kubernetes 1.35’e kadar uyumlu olduğunu ve geleneksel Cluster Autoscaler’a göre daha hızlı kaynak provisioning yapabildiğini görüyoruz [25].

14.3 Spot/Preemptible Node Üzerinde Spark

Cost optimization için Spot instance’lar harika ama interruption riski var. Spark, bu konuda da iyileştirmeler yaptı [30]:

Node Decommissioning (Spark 3.1+): Bir executor decommission edildiğinde, shuffle ve RDD verilerini başka executor’a taşımaya çalışıyor:

spark.decommission.enabled=true
spark.storage.decommission.shuffleBlocks.enabled=true
spark.storage.decommission.rddBlocks.enabled=true

PVC Reuse (Spark 3.2+): Bir executor’un PVC’si başka bir executor tarafından devralınabiliyor.

İkisini birleştirince Spot interruption’larında veri kaybı minimize oluyor, recompute yükü azalıyor.


15. GPU Desteği

ML iş yüklerinde GPU kullanımı artık standart. Spark on Kubernetes, GPU’yu Kubernetes’in custom resource pattern’i üzerinden destekliyor [2]:

spark.driver.resource.gpu.amount=1
spark.driver.resource.gpu.vendor=nvidia.com
spark.executor.resource.gpu.amount=1
spark.executor.resource.gpu.vendor=nvidia.com
spark.executor.resource.gpu.discoveryScript=/opt/sparkRapidsPlugin/getGpusResources.sh

Discovery script, executor başlangıcında çalışıp hangi GPU’ların atandığını JSON formatında STDOUT’a yazıyor [2]. NVIDIA’nın device plugin’i ile birlikte kullanılıyor.

15.1 Stage Level Scheduling

Spark’ın güzel özelliklerinden biri de stage-level scheduling [2]. Farklı stage’lerin farklı kaynak gereksinimlerini belirtebiliyoruz — örneğin ETL stage’i CPU-only executor’larla, ML training stage’i GPU executor’larla çalışabiliyor. Dynamic allocation ile birlikte, Spark gerekli profile’lara göre executor talep ediyor.

Önemli bir kısıtlama: Bu özellik dynamic allocation ile birleştirildiğinde spark.dynamicAllocation.shuffleTracking.enabled=true gerektiriyor [2].


16. IPv4/IPv6 Dual Stack

Spark 3.4 ile birlikte IPv6-only ve dual-stack ortamlar destekleniyor [2]:

--conf spark.kubernetes.driver.service.ipFamilyPolicy=PreferDualStack
--conf spark.kubernetes.driver.service.ipFamilies=IPv4,IPv6

IPv6-only için JVM’e -Djava.net.preferIPv6Addresses=true, Python için SPARK_PREFER_IPV6=true eklemek gerekiyor [2].


17. Güvenlik

Canlı ortamda atlanmaması gereken konular:

Image güvenliği: Resmi Spark imajları root grubuyla çalışıyor (UID 185). Kendi imajlarımızı build edip, mümkünse non-root, read-only filesystem ile çalıştırmak iyi pratik [2].

Pod Security Admission: Cluster admin’lerinin hostPath volume mount’larını ve runAsRoot‘u kısıtlaması öneriliyor [2].

Secret yönetimi: Hassas verileri ortam değişkeni olarak değil, mounted secret olarak vermek tercih edilmeli. Vault, AWS Secrets Manager, External Secrets Operator gibi araçlarla daha gelişmiş yönetim yapılabilir.

Network policies: Spark driver ve executor pod’ları arasındaki ağ trafiğini kısıtlamak için NetworkPolicy tanımlamak iyi olur.

RBAC minimum yetki: Driver service account’una sadece kendi namespace’inde pod/service/configmap oluşturma yetkisi vermek yeterli [2].


18. Spark 4.x ve Yeni Özellikler

Spark 4.0 ve 4.1 ile gelen göze çarpan özellikler:

Spark Declarative Pipelines (SDP): Spark 4.1 ile gelen büyük yenilik [27][29]. Imperatif “şunu yap, sonra bunu yap” yaklaşımından deklaratif “şu tablo şu sorguyu sonucu olsun” yaklaşımına geçiş. SQL veya Python decorator’leri ile pipeline tanımlıyoruz, Spark dependency graph’ı çıkarıp execution’ı optimize ediyor:

from pyspark import pipelines as dp

@dp.materialized_view
def trips_summary():
    return spark.table("trips").groupBy("city").count()

spark-pipelines CLI’si ile init, run, dry-run komutları mevcut [27].

Real-Time Mode (RTM): Structured Streaming için single-digit millisecond latency.

Arrow-native UDFs ve UDTFs: PySpark’ta serialization overhead’ini ortadan kaldırıyor.

Spark Connect ML: Makine öğrenmesi iş yükleri için stabilite iyileştirmeleri.

SQL Scripting GA: SQL’de IF, WHILE, exception handling gibi kontrol akışı yapıları artık canlı ortama hazır.

VARIANT data type GA: Yarı-yapılı veri (JSON gibi) için optimized depolama ve sorgulama; “shredding” özelliği ile commonly accessed alanlar Parquet kolon olarak saklanıyor.


19. Canlı Ortam İçin Best Practices

Tüm bu bilgileri toparlarsak, canlı ortam Spark on Kubernetes deployment’ları için bazı altın kurallar [7][8]:

Image yönetimi: Versiyonlanmış, immutable imajlar kullanın. Base image’ı küçük tutun; gerekli olmayan kütüphaneleri eklemeyin. Multi-stage Dockerfile kullanarak build artifact’leri runtime’a taşımayın.

Resource isolation: Spark workload’ları için ayrı node pool’lar oluşturun. Taint/toleration ile kritik workload’larla karışmasını engelleyin. ResourceQuota ile namespace’leri sınırlayın.

Helm + GitOps: Spark uygulamalarınızı Helm chart’larla template’leyin, ArgoCD veya Flux ile GitOps pipeline’ına bağlayın. SparkApplication YAML’larını versiyon kontrolünde tutun.

Driver pod cleanup: Tamamlanmış driver pod’ları biriktirmeyin — düzenli temizlik için cron job veya operator’ün TTL özelliğini kullanın.

Logging dışa aktarımı: Pod logları yok olmadan Loki/Elasticsearch’e aktarın. Spark event log’larını S3’e yazıp History Server ile geçmiş incelemeyi mümkün kılın.

Shuffle stratejisi: İş yükünüzün shuffle yoğunluğuna göre karar verin. Küçük/orta iş yüklerinde shuffle tracking yeterli, büyük TPCDS-tarzı iş yüklerinde Apache Celeborn gibi RSS düşünün.

Monitoring: Prometheus + Grafana standartı kurun. Failed job, long-running task, OOM kill gibi alert’ler tanımlayın.

Spot kullanımı: Cost için Spot kullanın ama node decommissioning, PVC reuse, RSS gibi resilience özelliklerini de etkinleştirin.

Image pull bottleneck: Büyük cluster’larda eşzamanlı image pull, registry’yi doyurabiliyor. ImagePullPolicy=IfNotPresent kullanın, node’lara image pre-fetch yapın, registry pull-through cache (örneğin AWS ECR Pull Through Cache) düşünün.

Pod startup süresi: Spark pod’ları büyük JVM süreçleri başlatıyor; cold start önemli olabiliyor. Init container’larla bağımlılıkları önceden indirmek, tmpfs kullanmak, spark-image içindeki gereksiz şeyleri silmek startup’ı hızlandırabiliyor.


20. Bulut Sağlayıcı Entegrasyonları

Her büyük bulut sağlayıcının managed Spark on Kubernetes çözümleri var:

  • AWS: EMR on EKS — Spark Operator ile veya doğrudan EMR API’si üzerinden [30]. Karpenter, Spot Instance, Celeborn entegrasyonu için zengin örnekler mevcut.
  • GCP: GKE üzerinde Dataproc Serverless veya self-managed Spark Operator. BigQuery, GCS entegrasyonları kolay.
  • Azure: AKS üzerinde Spark Operator. Synapse Analytics da Spark sunuyor ama bu daha kapsamlı bir managed servis.
  • Alibaba Cloud: ACK üzerinde ack-spark-operator, ack-celeborn entegre olarak geliyor [21].

Bunların hepsi temelde aynı upstream open-source bileşenleri kullanıyor — yani burada öğrendiklerimiz birebir geçerli.


21. Sorun Giderme İpuçları

Bir Spark işi başarısız olduğunda izleyeceğimiz adımlar:

# Driver pod'un schedule olamadığını mı, başlatılırken mi hata aldığını anlamak için:
kubectl describe pod <driver-pod>

# Driver loglarına bakmak için:
kubectl logs <driver-pod>

# Executor pod'larının durumu:
kubectl get pods -l spark-app-selector=<app-id>
kubectl logs <executor-pod>

# Operator kullanıyorsak SparkApplication durumu:
kubectl describe sparkapp <app-name>

Sık karşılaşılan sorunlar:

  • Pod Pending: Resource quota dolu, taint/toleration uyuşmazlığı, node selector eşleşmiyor
  • ImagePullBackOff: Registry erişim sorunu, imaj adı yanlış, pull secret eksik
  • OOMKilled: spark.driver.memory veya spark.executor.memory yetersiz, memoryOverheadFactor artırılmalı
  • Shuffle FetchFailed: Executor erken silinmiş, shuffle tracking veya RSS düşünmeli
  • Service account permission denied: RBAC eksik, driver service account’una pod yaratma yetkisi verilmeli

22. Sonuç

Spark on Kubernetes artık deneysel bir yaklaşım değil, canlı ortama hazır bir mimari. 2026 yılında Apache Spark 4.1, resmi Apache Spark Kubernetes Operator, Apache Celeborn, Karpenter, Volcano gibi projelerin olgunlaşması ile birlikte, geleneksel YARN deployment’larından farkı ciddi şekilde kapandı. Hatta bazı senaryolarda — özellikle çok kiracılı, cloud-native, ML iş yüklerini de barındıran ortamlarda — Kubernetes açık ara önde.

Bu yazıda baştan sona neredeyse tüm konulara değindik: mimari, pod template, volume yönetimi, dynamic allocation, shuffle stratejileri, operator pattern, custom scheduler’lar, monitoring, autoscaling, güvenlik, Spark 4.x özellikleri ve canlı ortam önerileri. Eğer Spark on Kubernetes yolculuğunuza yeni başlıyorsanız, küçük bir minikube cluster’ında spark-pi örneğiyle başlamanızı, ardından Kubeflow Spark Operator (veya Apache’nin yeni operator’ünün) ile deklaratif yaklaşıma geçmenizi öneririm.

Spark’ı Kubernetes üzerinde çalıştırılması dahil tüm yönleriyle detaylı ve uygulamalı öğrenmek isterseniz VBO Data Engineering Bootcamp‘i öneririm.

İyi çalışmalar!


Kaynaklar

  1. Apache Spark Kubernetes Operator (GitHub)
  2. Running Spark on Kubernetes — Spark 4.1 Documentation
  3. Kubernetes Operator for Apache Spark — Overview (Kubeflow)
  4. Kubeflow Spark Operator (GitHub)
  5. Announcing the Kubeflow Spark Operator (Kubeflow Blog)
  6. Kubeflow Spark Operator Benchmarks
  7. Optimizing Apache Spark Workflows on Kubernetes (Springer)
  8. Production-Ready Apache Spark on Kubernetes (Medium)
  9. Optimizing Spark performance on Kubernetes (AWS Containers Blog)
  10. Spark, MinIO and Kubernetes (MinIO Blog)
  11. Dynamic Resource Allocation (AWS EMR Containers Best Practices)
  12. Spark Dynamic Resource Allocation (DRA) in Kyuubi
  13. HOW TO: Configure and Run Spark on Kubernetes (Chaos Genius)
  14. Job Scheduling — Spark 4.1.1 Documentation
  15. Getting Started with Spark Operator (Kubeflow)
  16. Spark on Kubernetes – Gang Scheduling with YuniKorn (Cloudera)
  17. Batch Scheduling on Kubernetes: YuniKorn vs Volcano vs Kueue (InfraCloud)
  18. Why Spark chooses Volcano as built-in batch scheduler (CNCF Blog)
  19. YuniKorn Integration with Spark Operator (Kubeflow)
  20. Configure Dynamic Resource Allocation for Spark Jobs (Alibaba Cloud)
  21. Use Celeborn as Remote Shuffle Service (Alibaba Cloud)
  22. Apache Kyuubi & Celeborn Helps Spark Embrace Cloud Native (Medium)
  23. Apache Celeborn Deploy Documentation
  24. Quick Start Guide — Spark Operator
  25. Migrating from Cluster Autoscaler to Karpenter
  26. Apache Celeborn (GitHub)
  27. Spark Declarative Pipelines Programming Guide — Spark 4.1.1
  28. Monitoring and Instrumentation — Spark 4.1.1
  29. Apache Spark Declarative Pipelines (DZone)
  30. Run fault tolerant and cost-optimized Spark clusters with Spot Instances (AWS)
0

Bir yanıt yazın

Password Requirements:

  • At least 8 characters
  • At least 1 lowercase letter
  • At least 1 uppercase letter
  • At least 1 numerical number
  • At least 1 special character