Topik ini menjelaskan cara menjalankan pekerjaan Spark di ACK menggunakan resource Elastic Container Instance (ECI). Dengan mengonfigurasi strategi penjadwalan yang sesuai, Anda dapat membuat Pod ECI sesuai permintaan dan hanya membayar resource yang dikonsumsi, sehingga mengurangi biaya idle serta menjalankan pekerjaan Spark secara lebih ekonomis.
Prasyarat
Anda memerlukan:
-
ack-virtual-node diterapkan di kluster (mengekspos kapasitas ECI sebagai node virtual).
Cara kerja
Saat ack-virtual-node diterapkan, setiap node ECI memiliki taint virtual-kubelet.io/provider=alibabacloud:NoSchedule. Tanpa toleransi yang sesuai, penjadwal akan melewati node ECI dan menempatkan semua pod di ECS. Untuk mengarahkan pod Spark ke ECI, tambahkan toleransi dan aturan afinitas node ke spesifikasi SparkApplication.
ECI menjalankan setiap container dalam sandbox virtual ringan yang sepenuhnya mengisolasi pod. Dengan penagihan pay-as-you-go, Anda hanya membayar CPU dan memori yang dikonsumsi setiap pod selama berjalan—bukan kapasitas node idle.
Penempatan driver vs. executor
Pod driver dan executor gagal dengan cara berbeda, yang memengaruhi penempatannya:
-
Jika executor gagal, Spark secara otomatis menggantinya. Executor bersifat stateless dan toleran terhadap kesalahan.
-
Jika driver gagal, seluruh pekerjaan gagal dan dimulai ulang dari awal. Pastikan driver tetap stabil.
Simpan driver di node ECS yang andal dan arahkan executor ke instans ECI atau preemptible berbiaya lebih rendah saat biaya menjadi pertimbangan utama.
Karakteristik ECI untuk beban kerja Spark:
| Karakteristik | Nilai |
|---|---|
| Skala | Lebih dari 50.000 pod dalam kluster ACK Serverless; tidak perlu konfigurasi tambahan |
| Kecepatan provisioning | Ribuan pod dalam hitungan detik |
| Penagihan | Pay-as-you-go; tersedia instans preemptible untuk pengurangan biaya lebih lanjut |
Pilih strategi penjadwalan
Tiga strategi mencakup skenario penerapan umum:
| Strategi | Kapan digunakan | Penempatan driver | Penempatan executor |
|---|---|---|---|
| ECS only | Beban kerja stabil dan dapat diprediksi | ECS | ECS |
| ECI only | Pekerjaan batch atau burst yang membutuhkan elastisitas penuh | ECI | ECI |
| ECS-first with ECI fallback | Beban normal di ECS; memperluas kapasitas ke ECI secara otomatis saat puncak | ECS (disarankan) | ECS (disarankan), ECI (overflow) |
Untuk kontrol detail halus, seperti membatasi jumlah pod per jenis resource, gunakan ResourcePolicy.
Jadwalkan pekerjaan Spark di node ECS dan ECI
Semua contoh menggunakan SparkApplication (CRD sparkoperator.k8s.io/v1beta2) dengan pengaturan dasar berikut:
| Bidang | Nilai |
|---|---|
| Image | registry-cn-hangzhou.ack.aliyuncs.com/ack-demo/spark:3.5.2 |
mainClass |
org.apache.spark.examples.SparkPi |
sparkVersion |
3.5.2 |
driver.serviceAccount |
spark-operator-spark |
ECS only
Tidak diperlukan toleransi atau afinitas. Taint ECI default mencegah penjadwal menempatkan pod di sana.
apiVersion: sparkoperator.k8s.io/v1beta2
kind: SparkApplication
metadata:
name: spark-pi-ecs-only
namespace: default
spec:
type: Scala
mode: cluster
image: registry-cn-hangzhou.ack.aliyuncs.com/ack-demo/spark:3.5.2
mainClass: org.apache.spark.examples.SparkPi
mainApplicationFile: local:///opt/spark/examples/jars/spark-examples_2.12-3.5.2.jar
arguments:
- "5000"
sparkVersion: 3.5.2
driver:
cores: 1
coreLimit: 1200m
memory: 512m
serviceAccount: spark-operator-spark
executor:
instances: 2
cores: 2
memory: 4g
Perilaku yang diharapkan: Semua pod driver dan executor dijadwalkan ke node ECS. Jika kapasitas ECS tidak mencukupi, pod tetap dalam status Pending hingga kapasitas tersedia.
ECI only
Tambahkan toleransi untuk taint ECI default dan aturan afinitas requiredDuringSchedulingIgnoredDuringExecution untuk mengunci pod hanya ke node ECI. Terapkan keduanya pada spesifikasi driver dan executor.
apiVersion: sparkoperator.k8s.io/v1beta2
kind: SparkApplication
metadata:
name: spark-pi-eci-only
namespace: default
spec:
type: Scala
mode: cluster
image: registry-cn-hangzhou.ack.aliyuncs.com/ack-demo/spark:3.5.2
mainClass: org.apache.spark.examples.SparkPi
mainApplicationFile: local:///opt/spark/examples/jars/spark-examples_2.12-3.5.2.jar
arguments:
- "5000"
sparkVersion: 3.5.2
driver:
cores: 1
coreLimit: 1200m
memory: 512m
serviceAccount: spark-operator-spark
affinity:
nodeAffinity:
# Kunci driver hanya ke node ECI.
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: type
operator: In
values:
- virtual-kubelet
tolerations:
# Toleransi terhadap taint ECI default.
- key: virtual-kubelet.io/provider
operator: Equal
value: alibabacloud
effect: NoSchedule
executor:
instances: 2
cores: 2
memory: 4g
affinity:
nodeAffinity:
# Kunci executor hanya ke node ECI.
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: type
operator: In
values:
- virtual-kubelet
tolerations:
# Toleransi terhadap taint ECI default.
- key: virtual-kubelet.io/provider
operator: Equal
value: alibabacloud
effect: NoSchedule
Perilaku yang diharapkan: Semua pod dijadwalkan ke node ECI dan pekerjaan berjalan dalam mode sepenuhnya serverless. Jika kapasitas ECI di wilayah tersebut terbatas, pod tetap dalam status Pending hingga resource tersedia.
ECS-first with ECI fallback
Gunakan afinitas preferredDuringSchedulingIgnoredDuringExecution untuk mengutamakan ECS sekaligus memungkinkan overflow ke ECI. Tambahkan toleransi ECI agar penjadwal dapat menempatkan pod di ECI saat kapasitas ECS penuh.
apiVersion: sparkoperator.k8s.io/v1beta2
kind: SparkApplication
metadata:
name: spark-pi-ecs-first
namespace: default
spec:
type: Scala
mode: cluster
image: registry-cn-hangzhou.ack.aliyuncs.com/ack-demo/spark:3.5.2
mainClass: org.apache.spark.examples.SparkPi
mainApplicationFile: local:///opt/spark/examples/jars/spark-examples_2.12-3.5.2.jar
arguments:
- "5000"
sparkVersion: 3.5.2
driver:
cores: 1
coreLimit: 1200m
memory: 512m
serviceAccount: spark-operator-spark
affinity:
nodeAffinity:
# Utamakan node ECS; alihkan ke ECI jika kapasitas ECS habis.
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: type
operator: NotIn
values:
- virtual-kubelet
tolerations:
# Izinkan penjadwalan ke node ECI bila diperlukan.
- key: virtual-kubelet.io/provider
operator: Equal
value: alibabacloud
effect: NoSchedule
executor:
instances: 2
cores: 2
memory: 4g
affinity:
nodeAffinity:
# Utamakan node ECS; alihkan ke ECI jika kapasitas ECS habis.
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: type
operator: NotIn
values:
- virtual-kubelet
tolerations:
# Izinkan penjadwalan ke node ECI bila diperlukan.
- key: virtual-kubelet.io/provider
operator: Equal
value: alibabacloud
effect: NoSchedule
Perilaku yang diharapkan: Pod ditempatkan di ECS jika kapasitas tersedia. Saat ECS penuh, pod overflow dijadwalkan ke ECI. Hal ini menghindari antrian pekerjaan saat puncak tanpa harus menyediakan resource ECI secara permanen.
Lihat Konfigurasi alokasi sumber daya berdasarkan instans ECS dan elastic container instances untuk informasi tentang taint, toleransi, dan afinitas node.
Konfigurasi penjadwalan resource berbasis prioritas
Gunakan ResourcePolicy untuk mendefinisikan unit penjadwalan dengan batas pod per unit. Penjadwal ACK mengisi unit sesuai urutan prioritas saat memperluas kapasitas dan menghapus pod dalam urutan terbalik saat skala-masuk. Lihat Konfigurasi penjadwalan resource berbasis prioritas.
-
Buat
resourcepolicy.yamluntuk pod Spark Operator di namespacedefault(maksimal 2 di ECS AMD64, lalu 3 di ECI):apiVersion: scheduling.alibabacloud.com/v1alpha1 kind: ResourcePolicy metadata: name: sparkapplication-resource-policy namespace: default # Hanya berlaku untuk pod di namespace ini. spec: ignorePreviousPod: true ignoreTerminatingPod: false matchLabelKeys: - sparkoperator.k8s.io/submission-id # Kelompokkan pod berdasarkan ID pengiriman pekerjaan Spark. preemptPolicy: AfterAllUnits # Lakukan preemption hanya setelah semua unit habis. selector: sparkoperator.k8s.io/launched-by-spark-operator: "true" strategy: prefer units: - max: 2 # Maksimal 2 pod di node ECS AMD64 (prioritas pertama). resource: ecs nodeSelector: kubernetes.io/arch: amd64 - max: 3 # Maksimal 3 pod di ECI (prioritas kedua). resource: eci -
Terapkan ResourcePolicy:
kubectl apply -f resourcepolicy.yaml -
Buat
spark-pi.yaml. SparkApplication ini meminta 1 driver dan 5 executor, semuanya mentoleransi taint ECI sehingga ResourcePolicy dapat mendistribusikannya ke kedua jenis unit.apiVersion: sparkoperator.k8s.io/v1beta2 kind: SparkApplication metadata: name: spark-pi namespace: default spec: type: Scala mode: cluster image: registry-cn-hangzhou.ack.aliyuncs.com/ack-demo/spark:3.5.2 mainClass: org.apache.spark.examples.SparkPi mainApplicationFile: local:///opt/spark/examples/jars/spark-examples_2.12-3.5.2.jar arguments: - "5000" sparkVersion: 3.5.2 driver: cores: 1 coreLimit: 1200m memory: 512m serviceAccount: spark-operator-spark tolerations: - key: virtual-kubelet.io/provider # Izinkan driver dijadwalkan ke ECI jika diperlukan. operator: Equal value: alibabacloud effect: NoSchedule executor: instances: 5 cores: 1 coreLimit: 1200m memory: 512m tolerations: - key: virtual-kubelet.io/provider # Izinkan executor dijadwalkan ke ECI. operator: Equal value: alibabacloud effect: NoSchedule -
Kirim pekerjaan Spark:
kubectl apply -f spark-pi.yaml -
Verifikasi hasil penjadwalan:
kubectl get pods -o wide -l sparkoperator.k8s.io/app-name=spark-piOutput yang diharapkan:
NAME READY STATUS RESTARTS AGE IP NODE spark-pi-34c0998f9f832e61-exec-1 1/1 Running 0 28s 192.XXX.XX.34 cn-beijing.192.XXX.XX.250 spark-pi-34c0998f9f832e61-exec-2 1/1 Running 0 28s 192.XXX.XX.87 virtual-kubelet-cn-beijing-i spark-pi-34c0998f9f832e61-exec-3 1/1 Running 0 28s 192.XXX.XX.88 virtual-kubelet-cn-beijing-i spark-pi-34c0998f9f832e61-exec-4 1/1 Running 0 28s 192.XXX.XX.86 virtual-kubelet-cn-beijing-i spark-pi-34c0998f9f832e61-exec-5 0/1 Pending 0 28s <none> <none> spark-pi-driver 1/1 Running 0 34s 192.XXX.XX.37 cn-beijing.192.XXX.XXX.250Hasil: Driver dan exec-1 ditempatkan di unit ECS AMD64 (maksimal 2 pod). exec-2, exec-3, dan exec-4 ditempatkan di unit ECI (maksimal 3 pod). exec-5 tetap dalam status Pending karena kedua unit telah mencapai batas podnya.
Percepat pengambilan image dengan ImageCache
Mengambil image Spark besar saat startup setiap pod menambah latensi. ECI ImageCache melakukan pre-cache image di infrastruktur dasar, memangkas waktu startup pod dari sekitar 100 detik menjadi hampir instan saat cache tersedia. Lihat Gunakan ImageCache untuk mempercepat pembuatan elastic container instances.
Bandingkan startup dengan dan tanpa cache image
Tanpa cache, kubectl describe pod spark-pi-driver setelah mengirim SparkApplication menunjukkan:
Events:
...
Warning ImageCacheMissed 24m EciService [eci.imagecache]Missed image cache.
Normal ImageCacheAutoCreated 24m EciService [eci.imagecache]Image cache imc-2zeXXXXXXXXXXXXXXXXX is auto created
Normal Pulling 24m kubelet Pulling image "registry-cn-hangzhou.ack.aliyuncs.com/ack-demo/spark:3.5.2"
Normal Pulled 23m kubelet Successfully pulled image "registry-cn-hangzhou.ack.aliyuncs.com/ack-demo/spark:3.5.2" in 1m41.289s (1m41.289s including waiting)
...
Proses pengambilan image memakan waktu sekitar 100 detik. ECI secara otomatis membuat cache untuk eksekusi berikutnya.
Dengan cache hit, event menunjukkan:
Events:
...
Normal SuccessfulHitImageCache 23s EciService [eci.imagecache]Successfully hit image cache imc-2zeXXXXXXXXXXXXXXXXX, eci will be scheduled with this image cache.
Normal Pulled 4s kubelet Container image "registry-cn-hangzhou.ack.aliyuncs.com/ack-demo/spark:3.5.2" already present on machine
...
Tidak diperlukan pengambilan image.
Tentukan ID cache image
Tambahkan anotasi k8s.aliyun.com/eci-image-snapshot-id ke spesifikasi driver dan executor untuk mengunci cache image tertentu:
apiVersion: sparkoperator.k8s.io/v1beta2
kind: SparkApplication
metadata:
name: spark-pi-eci-only
namespace: default
spec:
type: Scala
mode: cluster
image: registry-cn-hangzhou.ack.aliyuncs.com/ack-demo/spark:3.5.2
mainClass: org.apache.spark.examples.SparkPi
mainApplicationFile: local:///opt/spark/examples/jars/spark-examples_2.12-3.5.2.jar
arguments:
- "5000"
sparkVersion: 3.5.2
driver:
annotations:
k8s.aliyun.com/eci-image-cache: "true" # Mengaktifkan pembuatan dan pencocokan cache gambar otomatis.
cores: 1
coreLimit: 1200m
memory: 512m
serviceAccount: spark-operator-spark
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: type
operator: In
values:
- virtual-kubelet
tolerations:
- key: virtual-kubelet.io/provider
operator: Equal
value: alibabacloud
effect: NoSchedule
executor:
annotations:
k8s.aliyun.com/eci-image-cache: "true" # Mengaktifkan pembuatan dan pencocokan cache gambar otomatis.
instances: 2
cores: 2
memory: 4g
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: type
operator: In
values:
- virtual-kubelet
tolerations:
- key: virtual-kubelet.io/provider
operator: Equal
value: alibabacloud
effect: NoSchedule
Aktifkan pembuatan dan pencocokan cache image otomatis
Untuk membiarkan ECI mengelola pembuatan dan pencocokan cache secara otomatis—tanpa ID cache—atur anotasi k8s.aliyun.com/eci-image-cache ke "true" pada driver dan executor:
apiVersion: sparkoperator.k8s.io/v1beta2
kind: SparkApplication
metadata:
name: spark-pi-eci-only
namespace: default
spec:
type: Scala
mode: cluster
image: registry-cn-hangzhou.ack.aliyuncs.com/ack-demo/spark:3.5.2
mainClass: org.apache.spark.examples.SparkPi
mainApplicationFile: local:///opt/spark/examples/jars/spark-examples_2.12-3.5.2.jar
arguments:
- "5000"
sparkVersion: 3.5.2
driver:
annotations:
k8s.aliyun.com/eci-image-cache: "true" # Aktifkan pembuatan dan pencocokan cache image otomatis.
cores: 1
coreLimit: 1200m
memory: 512m
serviceAccount: spark-operator-spark
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: type
operator: In
values:
- virtual-kubelet
tolerations:
- key: virtual-kubelet.io/provider
operator: Equal
value: alibabacloud
effect: NoSchedule
executor:
annotations:
k8s.aliyun.com/eci-image-cache: "true" # Aktifkan pembuatan dan pencocokan cache image otomatis.
instances: 2
cores: 2
memory: 4g
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: type
operator: In
values:
- virtual-kubelet
tolerations:
- key: virtual-kubelet.io/provider
operator: Equal
value: alibabacloud
effect: NoSchedule
Pada eksekusi pertama, ECI membuat cache secara otomatis. Eksekusi berikutnya akan mencocokkan cache tersebut dan melewati proses pengambilan image.
Penerapan di produksi
-
Gunakan strategi ECS-first with ECI fallback untuk pekerjaan produksi. Menjaga beban kerja sensitif latensi di node ECS persisten, sementara ECI menyerap trafik burst tanpa perlu menyediakan node tambahan di muka.
-
Jalankan driver di ECS, executor di ECI. Kegagalan driver menyebabkan seluruh pekerjaan dimulai ulang. Simpan driver di node ECS yang stabil dan arahkan executor tanpa status ke instans ECI atau preemptible berbiaya lebih rendah.
-
Aktifkan caching image otomatis untuk pekerjaan berulang. Eksekusi pertama membuat cache; eksekusi berikutnya melewati pengambilan image, memangkas waktu startup dari sekitar 100 detik menjadi hampir instan.
-
Gunakan ResourcePolicy saat distribusi pod lintas jenis node harus tepat. Bidang
maxper unit membatasi jumlah pod, berguna untuk membatasi pengeluaran ECI per pengiriman pekerjaan.