Utilisation de YuniKorn comme planificateur personnalisé pour Apache Spark sur Amazon EMR on EKS - Amazon EMR

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 de YuniKorn comme planificateur personnalisé pour Apache Spark sur Amazon EMR on EKS

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 avec un planificateur YuniKorn sur une file d'attente personnalisée et une planification groupée.

Présentation

Apache YuniKorn vous offre la possibilité de gérer la planification Spark en adaptant la planification aux applications, vous permettant ainsi de définir avec exactitude les quotas et les priorités en matière de ressources. Grâce à la planification groupée, YuniKorn ne programme une application que si la demande minimale de ressources pour celle-ci peut être satisfaite. Pour plus d'informations, consultez la rubrique Qu'est-ce que la planification groupée sur le site de documentation d'Apache YuniKorn.

Création de votre cluster et préparation pour YuniKorn

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

    eksctl create cluster -f eks-cluster.yaml
  3. Créez l'espace de noms spark-job dans lequel vous exécuterez la tâche Spark :

    kubectl create namespace spark-job
  4. 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
    2. 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 de YuniKorn

  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
  2. 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écution d'une application Spark avec le planificateur YuniKorn à l'aide de l'opérateur Spark

  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éation de votre cluster et préparation pour YuniKorn

    2. Installation et configuration de YuniKorn

    3. Configuration de l'opérateur Spark pour Amazon EMR sur EKS

    4. Installation de l'opérateur Spark

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

      --set batchScheduler.enable=true --set webhook.enable=true
  2. Créez un fichier de définition SparkApplication spark-pi.yaml.

    Pour 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éation de votre cluster et préparation pour YuniKorn.

    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"
  3. 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
  4. 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 du pod montrera que 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écution d'une application Spark avec le planificateur YuniKorn à l'aide de spark-submit

  1. Effectuez d'abord les étapes décrites dans la section Configuration de Spark-Submit pour Amazon sur EMR EKS.

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

    export SPARK_HOME=spark-home export MASTER_URL=k8s://Amazon-EKS-cluster-endpoint
  3. 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éation de votre cluster et préparation pour YuniKorn.

    $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
  4. 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 du pod montrera que 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