

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 使用 Volcano 作為 Amazon EMR on EKS 上 Apache Spark 的自訂排程器
<a name="tutorial-volcano"></a>

透過 Amazon EMR on EKS，可以將 Spark 運算子或 spark-submit 與 Kubernetes 自訂排程器搭配使用，以執行 Spark 作業。本教學課程介紹了如何在自訂佇列上使用 Volcano 排程器來執行 Spark 作業。

## 概觀
<a name="tutorial-volcano-overview"></a>

[Volcano](https://volcano.sh/en/) 可以透過諸如佇列排程、公平共用排程以及資源保留等進階功能來幫助管理 Spark 排程。如需有關 Volcano 優勢的詳細資訊，請參閱 The Linux Foundation 的 *CNCF 部落格*上的[為何 Spark 選擇 Volcano 作為 Kubernetes 上的內建批次排程器](https://www.cncf.io/blog/2022/06/30/why-spark-chooses-volcano-as-built-in-batch-scheduler-on-kubernetes/)。

## 安裝並設定 Volcano
<a name="tutorial-volcano-install"></a>

1. 根據您的架構需求，選擇下列其中一個 kubectl 命令來安裝 Volcano：

   ```
   # x86_64
   kubectl apply -f https://raw.githubusercontent.com/volcano-sh/volcano/v1.5.1/installer/volcano-development.yaml
   # arm64:
   kubectl apply -f https://raw.githubusercontent.com/volcano-sh/volcano/v1.5.1/installer/volcano-development-arm64.yaml
   ```

1. 準備 Volcano 佇列範例。佇列是 [PodGroups](https://volcano.sh/en/docs/podgroup/) 的集合。佇列採用 FIFO，是資源劃分的基礎。

   ```
   cat << EOF > volcanoQ.yaml
   apiVersion: scheduling.volcano.sh/v1beta1
   kind: Queue
   metadata:
     name: sparkqueue
   spec:
     weight: 4
     reclaimable: false
     capability:
       cpu: 10
       memory: 20Gi
   EOF
   
   kubectl apply -f volcanoQ.yaml
   ```

1. 將 PodGroup 清單檔案範例上傳到 Amazon S3。PodGroup 是一組具有強大關聯性的 Pod。您通常會使用 PodGroup 進行批次排程。將下列 PodGroup 範例提交到您在先前步驟中定義的佇列。

   ```
   cat << EOF > podGroup.yaml
   apiVersion: scheduling.volcano.sh/v1beta1
   kind: PodGroup
   spec:
     # Set minMember to 1 to make a driver pod
     minMember: 1
     # Specify minResources to support resource reservation. 
     # Consider the driver pod resource and executors pod resource.
     # The available resources should meet the minimum requirements of the Spark job 
     # to avoid a situation where drivers are scheduled, but they can't schedule 
     # sufficient executors to progress.
     minResources:
       cpu: "1"
       memory: "1Gi"
     # Specify the queue. This defines the resource queue that the job should be submitted to.
     queue: sparkqueue
   EOF
   
   aws s3 mv podGroup.yaml s3://bucket-name
   ```

## 使用 Volcano 排程器和 Spark Operator 來執行 Spark 應用程式
<a name="tutorial-volcano-sparkoperator"></a>

1. 如果您尚未完成，請先完成下節中的步驟進行設定：

   1. [安裝並設定 Volcano](#tutorial-volcano-install)

   1. [為 Amazon EMR on EKS 設定 Spark Operator](spark-operator-setup.md)

   1. [安裝 Spark Operator](spark-operator-gs.md#spark-operator-install)

      當您執行 `helm install spark-operator-demo` 命令時，請包含下列引數：

      ```
      --set batchScheduler.enable=true 
      --set webhook.enable=true
      ```

1. 建立已設定 `batchScheduler` 的 `SparkApplication` 定義檔案 `spark-pi.yaml`。

   ```
   apiVersion: "sparkoperator.k8s.io/v1beta2"
   kind: SparkApplication
   metadata:
     name: spark-pi
     namespace: spark-operator
   spec:
     type: Scala
     mode: cluster
     image: "895885662937.dkr.ecr.us-west-2.amazonaws.com/spark/emr-6.10.0:latest"
     imagePullPolicy: Always
     mainClass: org.apache.spark.examples.SparkPi
     mainApplicationFile: "local:///usr/lib/spark/examples/jars/spark-examples.jar"
     sparkVersion: "3.3.1"
     batchScheduler: "volcano"   #Note: You must specify the batch scheduler name as 'volcano'
     restartPolicy:
       type: Never
     volumes:
       - name: "test-volume"
         hostPath:
           path: "/tmp"
           type: Directory
     driver:
       cores: 1
       coreLimit: "1200m"
       memory: "512m"
       labels:
         version: 3.3.1
       serviceAccount: emr-containers-sa-spark
       volumeMounts:
         - name: "test-volume"
           mountPath: "/tmp"
     executor:
       cores: 1
       instances: 1
       memory: "512m"
       labels:
         version: 3.3.1
       volumeMounts:
         - name: "test-volume"
           mountPath: "/tmp"
   ```

1. 使用下列命令提交 Spark 應用程式。這也會建立 `SparkApplication` 物件，名為 `spark-pi`：

   ```
   kubectl apply -f spark-pi.yaml
   ```

1. 使用下列命令檢查 `SparkApplication` 物件的事件：

   ```
   kubectl describe pods spark-pi-driver --namespace spark-operator
   ```

   第一個 Pod 事件會顯示 Volcano 已排程 Pod：

   ```
   Type    Reason     Age   From                Message
   ----    ------     ----  ----                -------
   Normal  Scheduled  23s   volcano             Successfully assigned default/spark-pi-driver to integration-worker2
   ```

## 使用 Volcano 排程器和 `spark-submit` 來執行 Spark 應用程式
<a name="tutorial-volcano-sparksubmit"></a>

1. 首先，請先完成 [為 Amazon EMR on EKS 設定 spark-submit](spark-submit-setup.md) 一節中的步驟。必須在 Volcano 支援下建立自己的 `spark-submit` 分發。如需詳細資訊，請參閱 Apache Spark 文件**中的[使用 Volcano 作為 Spark on Kubernetes 的自訂排程器](https://spark.apache.org/docs/latest/running-on-kubernetes.html#build)的**建置**一節。

1. 設定以下環境變數的值：

   ```
   export SPARK_HOME=spark-home
   export MASTER_URL=k8s://Amazon-EKS-cluster-endpoint
   ```

1. 使用下列命令提交 Spark 應用程式：

   ```
   $SPARK_HOME/bin/spark-submit \
    --class org.apache.spark.examples.SparkPi \
    --master $MASTER_URL \
    --conf spark.kubernetes.container.image=895885662937.dkr.ecr.us-west-2.amazonaws.com/spark/emr-6.10.0:latest \
    --conf spark.kubernetes.authenticate.driver.serviceAccountName=spark \
    --deploy-mode cluster \
    --conf spark.kubernetes.namespace=spark-operator \
    --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 \
    local:///usr/lib/spark/examples/jars/spark-examples.jar 20
   ```

1. 使用下列命令檢查 `SparkApplication` 物件的事件：

   ```
   kubectl describe pod spark-pi --namespace spark-operator
   ```

   第一個 Pod 事件會顯示 Volcano 已排程 Pod：

   ```
   Type    Reason     Age   From                Message
   ----    ------     ----  ----                -------
   Normal  Scheduled  23s   volcano             Successfully assigned default/spark-pi-driver to integration-worker2
   ```