

Die vorliegende Übersetzung wurde maschinell erstellt. Im Falle eines Konflikts oder eines Widerspruchs zwischen dieser übersetzten Fassung und der englischen Fassung (einschließlich infolge von Verzögerungen bei der Übersetzung) ist die englische Fassung maßgeblich.

# Verwendung YuniKorn als benutzerdefinierter Scheduler für Apache Spark auf Amazon EMR auf EKS
<a name="tutorial-yunikorn"></a>

Mit Amazon EMR in EKS können Sie Spark-Operator oder Spark-Submit verwenden, um Spark-Aufträge mit benutzerdefinierten Kubernetes-Schedulern auszuführen. Dieses Tutorial behandelt die Ausführung von Spark-Jobs mit einem YuniKorn Scheduler in einer benutzerdefinierten Warteschlange und die Gruppenplanung.

## -Übersicht
<a name="tutorial-yunikorn-overview"></a>

[Apache](https://yunikorn.apache.org/) unterstützt YuniKorn Sie bei der Verwaltung der Spark-Zeitplanung mit anwendungsorientierter Planung, sodass Sie die Ressourcenkontingente und Prioritäten genau steuern können. Bei der Gruppenplanung wird eine YuniKorn App nur dann geplant, wenn die minimale Ressourcenanforderung für die App erfüllt werden kann. Weitere Informationen finden Sie auf der YuniKorn Dokumentationsseite von Apache unter [Was ist Gruppenplanung](https://yunikorn.apache.org/docs/user_guide/gang_scheduling/). 

## Erstellen Sie Ihren Cluster und bereiten Sie sich darauf vor YuniKorn
<a name="tutorial-yunikorn-setup"></a>

Führen Sie die folgenden Schritte aus, um einen Amazon-EKS-Cluster bereitzustellen. Sie können die AWS-Region (`region`) und Availability Zones (`availabilityZones`) ändern.

1. Definieren Sie den Amazon-EKS-Cluster:

   ```
   cat <<EOF >eks-cluster.yaml
   ---
   apiVersion: eksctl.io/v1alpha5
   kind: ClusterConfig
   
   metadata:
     name: emr-eks-cluster
     region: eu-west-1
   
   vpc:
     clusterEndpoints:
       publicAccess: true
       privateAccess: true
   
   iam:
     withOIDC: true
     
   nodeGroups:
     - name: spark-jobs
       labels: { app: spark }
       instanceType: m5.xlarge
       desiredCapacity: 2
       minSize: 2
       maxSize: 3
       availabilityZones: ["eu-west-1a"]
   EOF
   ```

1. Erstellen Sie den Cluster:

   ```
   eksctl create cluster -f eks-cluster.yaml
   ```

1. Erstellen Sie den Namespace `spark-job`, in dem Sie den Spark-Auftrag ausführen werden:

   ```
   kubectl create namespace spark-job
   ```

1. Erstellen Sie als Nächstes eine Kubernetes-Rolle und eine Rollenbindung. Dies ist für das Servicekonto erforderlich, das der Spark-Auftraglauf verwendet.

   1. Definieren Sie das Servicekonto, die Rolle und die Rollenbindung für Spark-Aufträge.

      ```
      cat <<EOF >emr-job-execution-rbac.yaml
      ---
      apiVersion: v1
      kind: ServiceAccount
      metadata:
        name: spark-sa
        namespace: spark-job
      automountServiceAccountToken: false
      ---
      apiVersion: rbac.authorization.k8s.io/v1
      kind: Role
      metadata:
        name: spark-role
        namespace: spark-job
      rules:
        - apiGroups: ["", "batch","extensions"]
          resources: ["configmaps","serviceaccounts","events","pods","pods/exec","pods/log","pods/portforward","secrets","services","persistentvolumeclaims"]
          verbs: ["create","delete","get","list","patch","update","watch"]
      ---
      apiVersion: rbac.authorization.k8s.io/v1
      kind: RoleBinding
      metadata:
        name: spark-sa-rb
        namespace: spark-job
      roleRef:
        apiGroup: rbac.authorization.k8s.io
        kind: Role
        name: spark-role
      subjects:
        - kind: ServiceAccount
          name: spark-sa
          namespace: spark-job
      EOF
      ```

   1. Wenden Sie die Kubernetes-Rollen- und Rollenbindungsdefinition mit dem folgenden Befehl an:

      ```
      kubectl apply -f emr-job-execution-rbac.yaml
      ```

## Installation und Einrichtung YuniKorn
<a name="tutorial-yunikorn-install"></a>

1. Verwenden Sie den folgenden kubectl-Befehl, um einen `yunikorn`-Namespace für die Bereitstellung des Yunikorn-Planers zu erstellen:

   ```
   kubectl create namespace yunikorn
   ```

1. Um den Planer zu installieren, führen Sie die folgenden Helm-Befehle aus:

   ```
   helm repo add yunikorn https://apache.github.io/yunikorn-release
   ```

   ```
   helm repo update
   ```

   ```
   helm install yunikorn yunikorn/yunikorn --namespace yunikorn
   ```

## Führen Sie eine Spark-Anwendung mit YuniKorn Scheduler mit dem Spark-Operator aus
<a name="tutorial-yunikorn-sparkoperator"></a>

1. Sofern noch nicht geschehen, stellen Sie sicher, dass Sie folgende Voraussetzungen erfüllen:

   1. [Erstellen Sie Ihren Cluster und bereiten Sie sich darauf vor YuniKorn](#tutorial-yunikorn-setup)

   1. [Installation und Einrichtung YuniKorn](#tutorial-yunikorn-install)

   1. [Einrichten des Spark-Operators für Amazon EMR in EKS](spark-operator-setup.md)

   1. [Den Spark-Operator installieren](spark-operator-gs.md#spark-operator-install)

      Geben Sie bei der Ausführung des `helm install spark-operator-demo`-Befehls die folgenden Argumente an:

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

1. Erstellen Sie eine `SparkApplication`-Definitionsdatei `spark-pi.yaml`.

   Um ihn YuniKorn als Scheduler für Ihre Jobs zu verwenden, müssen Sie Ihrer Anwendungsdefinition bestimmte Anmerkungen und Labels hinzufügen. Die Anmerkungen und Beschriftungen spezifizieren die Warteschlange für Ihren Auftrag und die Planungsstrategie, die Sie verwenden möchten.

   Im folgenden Beispiel `schedulingPolicyParameters` richtet die Anmerkung die Gruppenplanung für die Anwendung ein. Anschließend werden im Beispiel **Aufgabengruppen** oder „Gruppen“ von Aufgaben erstellt, um die Mindestkapazität anzugeben, die verfügbar sein muss, bevor die Pods für den Start der Auftragsausführung geplant werden. Und schließlich gibt es in der Aufgabengruppendefinition an, dass Knotengruppen mit der `"app": "spark"`-Bezeichnung verwendet werden sollen, wie im [Erstellen Sie Ihren Cluster und bereiten Sie sich darauf vor YuniKorn](#tutorial-yunikorn-setup)-Abschnitt definiert.

   ```
   apiVersion: "sparkoperator.k8s.io/v1beta2"
   kind: SparkApplication
   metadata:
     name: spark-pi
     namespace: spark-job
   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"
     restartPolicy:
       type: Never
     volumes:
       - name: "test-volume"
         hostPath:
           path: "/tmp"
           type: Directory
     driver:
       cores: 1
       coreLimit: "1200m"
       memory: "512m"
       labels:
         version: 3.3.1
       annotations:
         yunikorn.apache.org/schedulingPolicyParameters: "placeholderTimeoutSeconds=30 gangSchedulingStyle=Hard"
         yunikorn.apache.org/task-group-name: "spark-driver"
         yunikorn.apache.org/task-groups: |-
           [{
               "name": "spark-driver",
               "minMember": 1,
               "minResource": {
                 "cpu": "1200m",
                 "memory": "1Gi"
               },
               "nodeSelector": {
                 "app": "spark"
               }
             },
             {
               "name": "spark-executor",
               "minMember": 1,
               "minResource": {
                 "cpu": "1200m",
                 "memory": "1Gi"
               },
               "nodeSelector": {
                 "app": "spark"
               }
           }]
       serviceAccount: spark-sa
       volumeMounts:
         - name: "test-volume"
           mountPath: "/tmp"
     executor:
       cores: 1
       instances: 1
       memory: "512m"
       labels:
         version: 3.3.1
       annotations:
         yunikorn.apache.org/task-group-name: "spark-executor"
       volumeMounts:
         - name: "test-volume"
           mountPath: "/tmp"
   ```

1. Senden Sie die Spark-Anwendung mit dem folgenden Befehl. Dadurch wird auch ein `SparkApplication`-Objekt mit dem Namen `spark-pi` erstellt:

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

1. Überprüfen Sie die Ereignisse für das `SparkApplication`-Objekt mit dem folgenden Befehl: 

   ```
   kubectl describe sparkapplication spark-pi --namespace spark-job
   ```

   Beim ersten Pod-Ereignis wird angezeigt, dass die Pods geplant YuniKorn wurden:

   ```
   Type    Reason            Age   From                          Message
   ----    ------            ----  ----                          -------
   Normal Scheduling        3m12s yunikorn   spark-operator/org-apache-spark-examples-sparkpi-2a777a88b98b8a95-driver is queued and waiting for allocation
   Normal GangScheduling    3m12s yunikorn   Pod belongs to the taskGroup spark-driver, it will be scheduled as a gang member
   Normal Scheduled         3m10s yunikorn   Successfully assigned spark
   Normal PodBindSuccessful 3m10s yunikorn   Pod spark-operator/
   Normal TaskCompleted     2m3s  yunikorn   Task spark-operator/
   Normal Pulling           3m10s kubelet    Pulling
   ```

## Führen Sie eine Spark-Anwendung mit YuniKorn Scheduler aus mit `spark-submit`
<a name="tutorial-yunikorn-sparksubmit"></a>

1. Führen Sie zunächst die Schritte in diesem [Einrichten von spark-submit für Amazon EMR in EKS](spark-submit-setup.md)-Abschnitt durch.

1. Legen Sie die Werte der folgenden Umgebungsvariablen fest:

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

1. Senden Sie die Spark-Anwendung mit dem folgenden Befehl:

   Im folgenden Beispiel `schedulingPolicyParameters` richtet die Anmerkung die Gruppenplanung für die Anwendung ein. Anschließend werden im Beispiel **Aufgabengruppen** oder „Gruppen“ von Aufgaben erstellt, um die Mindestkapazität anzugeben, die verfügbar sein muss, bevor die Pods für den Start der Auftragsausführung geplant werden. Und schließlich gibt es in der Aufgabengruppendefinition an, dass Knotengruppen mit der `"app": "spark"`-Bezeichnung verwendet werden sollen, wie im [Erstellen Sie Ihren Cluster und bereiten Sie sich darauf vor YuniKorn](#tutorial-yunikorn-setup)-Abschnitt definiert.

   ```
   $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-sa \
    --deploy-mode cluster \
    --conf spark.kubernetes.namespace=spark-job \
    --conf spark.kubernetes.scheduler.name=yunikorn \
    --conf spark.kubernetes.driver.annotation.yunikorn.apache.org/schedulingPolicyParameters="placeholderTimeoutSeconds=30 gangSchedulingStyle=Hard" \
    --conf spark.kubernetes.driver.annotation.yunikorn.apache.org/task-group-name="spark-driver" \
    --conf spark.kubernetes.executor.annotation.yunikorn.apache.org/task-group-name="spark-executor" \
    --conf spark.kubernetes.driver.annotation.yunikorn.apache.org/task-groups='[{
               "name": "spark-driver",
               "minMember": 1,
               "minResource": {
                 "cpu": "1200m",
                 "memory": "1Gi"
               },
               "nodeSelector": {
                 "app": "spark"
               }
             },
             {
               "name": "spark-executor",
               "minMember": 1,
               "minResource": {
                 "cpu": "1200m",
                 "memory": "1Gi"
               },
               "nodeSelector": {
                 "app": "spark"
               }
           }]' \
    local:///usr/lib/spark/examples/jars/spark-examples.jar 20
   ```

1. Überprüfen Sie die Ereignisse für das `SparkApplication`-Objekt mit dem folgenden Befehl: 

   ```
   kubectl describe pod spark-driver-pod --namespace spark-job
   ```

   Beim ersten Pod-Event wird angezeigt, YuniKorn dass die Pods geplant wurden:

   ```
   Type    Reason           Age   From                          Message
   ----    ------           ----  ----                          -------
   Normal Scheduling        3m12s yunikorn   spark-operator/org-apache-spark-examples-sparkpi-2a777a88b98b8a95-driver is queued and waiting for allocation
   Normal GangScheduling    3m12s yunikorn   Pod belongs to the taskGroup spark-driver, it will be scheduled as a gang member
   Normal Scheduled         3m10s yunikorn   Successfully assigned spark
   Normal PodBindSuccessful 3m10s yunikorn   Pod spark-operator/
   Normal TaskCompleted     2m3s  yunikorn   Task spark-operator/
   Normal Pulling           3m10s kubelet    Pulling
   ```