

Les traductions sont fournies par des outils de traduction automatique. En cas de conflit entre le contenu d'une traduction et celui de la version originale en anglais, la version anglaise prévaudra.

# Utilisation en YuniKorn tant que planificateur personnalisé pour Apache Spark sur Amazon EMR sur EKS
<a name="tutorial-yunikorn"></a>

Avec Amazon EMR on EKS, vous avez la possibilité d'utiliser l'opérateur  Spark ou la commande spark-submit pour lancer des tâches Spark en utilisant des planificateurs personnalisés Kubernetes. Ce didacticiel explique comment exécuter des tâches Spark à l'aide d'un YuniKorn planificateur sur une file d'attente personnalisée et comment planifier par groupes.

## Présentation de
<a name="tutorial-yunikorn-overview"></a>

[Apache YuniKorn](https://yunikorn.apache.org/) peut vous aider à gérer la planification Spark grâce à une planification adaptée aux applications afin que vous puissiez contrôler avec précision les quotas et les priorités des ressources. Avec la planification en groupe, YuniKorn planifie une application uniquement lorsque la demande de ressources minimale pour l'application peut être satisfaite. Pour plus d'informations, consultez la section [Qu'est-ce que la planification par groupes](https://yunikorn.apache.org/docs/user_guide/gang_scheduling/) sur le site de YuniKorn documentation d'Apache. 

## Créez votre cluster et préparez-vous pour YuniKorn
<a name="tutorial-yunikorn-setup"></a>

Suivez les étapes ci-dessous pour déployer un cluster Amazon EKS. Vous pouvez modifier les zones Région AWS (`region`) et les zones de disponibilité (`availabilityZones`).

1. Définissez le cluster Amazon EKS :

   ```
   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. Créez le cluster :

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

1. Créez l'espace de noms `spark-job` dans lequel vous exécuterez la tâche Spark :

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

1. Créez ensuite un rôle Kubernetes et une liaison de rôle. Cela est requis pour le compte de service utilisé par l'exécution de la tâche  Spark.

   1. Définissez le compte de service, le rôle et la liaison de rôle pour les tâches Spark.

      ```
      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. Appliquez la définition du rôle Kubernetes et de la liaison de rôle à l'aide de la commande suivante :

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

## Installation et configuration YuniKorn
<a name="tutorial-yunikorn-install"></a>

1. Utilisez la commande kubectl suivante pour créer un espace de noms `yunikorn` afin de déployer le planificateur YuniKorn :

   ```
   kubectl create namespace yunikorn
   ```

1. Pour installer le planificateur, exécutez les commandes Helm suivantes :

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

   ```
   helm repo update
   ```

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

## Exécuter une application Spark avec un YuniKorn planificateur avec l'opérateur Spark
<a name="tutorial-yunikorn-sparkoperator"></a>

1. Si vous ne l'avez pas encore fait, suivez les étapes indiquées dans les sections ci-dessous pour vous préparer :

   1. [Créez votre cluster et préparez-vous pour YuniKorn](#tutorial-yunikorn-setup)

   1. [Installation et configuration YuniKorn](#tutorial-yunikorn-install)

   1. [Configuration de l'opérateur Spark pour Amazon EMR on EKS](spark-operator-setup.md)

   1. [Installation de l'opérateur Spark](spark-operator-gs.md#spark-operator-install)

      Incluez les arguments suivants lorsque vous exécutez la commande `helm install spark-operator-demo` :

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

1. Créez un fichier de définition `SparkApplication` `spark-pi.yaml`.

   Pour l'utiliser YuniKorn comme planificateur pour vos tâches, vous devez ajouter certaines annotations et étiquettes à la définition de votre application. Les annotations et les étiquettes indiquent la file d'attente pour votre tâche et la stratégie de planification que vous souhaitez utiliser.

   Dans l'exemple ci-dessous, l'annotation `schedulingPolicyParameters` configure la planification groupée pour l'application. L'exemple crée ensuite des **groupes de tâches** pour indiquer la capacité minimale qui doit être disponible avant de programmer les pods pour commencer l'exécution de la tâche. Enfin, il indique dans la définition du groupe de tâches qu'il faut utiliser des groupes de nœuds avec l'étiquette `"app": "spark"`, comme défini dans la section [Créez votre cluster et préparez-vous pour YuniKorn](#tutorial-yunikorn-setup).

   ```
   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. Soumettez l'application Spark à l'aide de la commande suivante. Cela crée également un objet `SparkApplication` appelé `spark-pi` :

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

1. Vérifiez les événements de l'objet `SparkApplication` à l'aide de la commande suivante : 

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

   Le premier événement dédié aux pods indiquera qui YuniKorn a programmé les pods :

   ```
   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
   ```

## Exécutez une application Spark avec un YuniKorn planificateur avec `spark-submit`
<a name="tutorial-yunikorn-sparksubmit"></a>

1. Effectuez d'abord les étapes décrites dans la section [Configuration de spark-submit pour Amazon EMR on EKS](spark-submit-setup.md).

1. Définissez les valeurs des variables d'environnement suivantes :

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

1. Soumettez l'application Spark à l'aide de la commande suivante :

   Dans l'exemple ci-dessous, l'annotation `schedulingPolicyParameters` configure la planification groupée pour l'application. L'exemple crée ensuite des **groupes de tâches** pour indiquer la capacité minimale qui doit être disponible avant de programmer les pods pour commencer l'exécution de la tâche. Enfin, il indique dans la définition du groupe de tâches qu'il faut utiliser des groupes de nœuds avec l'étiquette `"app": "spark"`, comme défini dans la section [Créez votre cluster et préparez-vous pour YuniKorn](#tutorial-yunikorn-setup).

   ```
   $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. Vérifiez les événements de l'objet `SparkApplication` à l'aide de la commande suivante : 

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

   Le premier événement dédié aux pods indiquera qui YuniKorn a programmé les pods :

   ```
   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
   ```