Amazon EMR on EKS で Apache Spark のカスタムスケジューラとして YuniKorn を使用する方法 - Amazon EMR

Amazon EMR on EKS で Apache Spark のカスタムスケジューラとして YuniKorn を使用する方法

Amazon EMR on EKS では、Spark オペレータまたは spark-submit を使用して、Kubernetes カスタムスケジューラで Spark ジョブを実行できます。このチュートリアルでは、カスタムキューとギャングスケジューリングで YuniKorn スケジューラを使用して、Spark ジョブを実行する方法について説明します。

概要

Apache YuniKorn では、アプリ対応のスケジューリングで Spark スケジューリングを管理して、リソースのクォータと優先順位をきめ細かく制御できます。ギャングスケジューリングを備えており、アプリに最小限必要なリソースリクエストを満たすことができるときにのみ、アプリをスケジュールします。詳細については、Apache YuniKorn ドキュメントサイトの「What is gang scheduling」を参照してください。

YuniKorn 用にクラスターを作成してセットアップする

次の手順を使用して、Amazon EKS クラスターをデプロイします。AWS リージョン (region) とアベイラビリティーゾーン (availabilityZones) は変更してもかまいません。

  1. 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. クラスターを作成します。

    eksctl create cluster -f eks-cluster.yaml
  3. Spark ジョブの実行先となる名前空間 spark-job を作成します。

    kubectl create namespace spark-job
  4. 次に、Kubernetes ロールとロールバインディングを作成します。これは、Spark ジョブ実行が使用するサービスアカウントに必須の操作です。

    1. 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. 次のコマンドで Kubernetes ロールとロールバインディング定義を適用します。

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

YuniKorn をインストールしてセットアップする

  1. 次の kubectl コマンドを使用して、Yunikorn スケジューラのデプロイ先となる名前空間 yunikorn を作成します。

    kubectl create namespace yunikorn
  2. このスケジューラをインストールするには、次の Helm コマンドを実行します。

    helm repo add yunikorn https://apache.github.io/yunikorn-release
    helm repo update
    helm install yunikorn yunikorn/yunikorn --namespace yunikorn

Spark オペレータを指定して YuniKorn スケジューラで Spark アプリケーションを実行する

  1. 次のセクションのステップをまだ完了していない場合は完了してセットアップします。

    1. YuniKorn 用にクラスターを作成してセットアップする

    2. YuniKorn をインストールしてセットアップする

    3. Amazon EMR on EKS での Spark 演算子のセットアップ

    4. Spark 演算子をインストールする

      helm install spark-operator-demo コマンドを実行するときは、次の引数を含めます。

      --set batchScheduler.enable=true --set webhook.enable=true
  2. SparkApplication ジョブ定義ファイル spark-pi.yaml を作成します。

    YuniKorn をジョブのスケジューラとして使用するには、アプリケーション定義に特定の注釈とラベルを追加する必要があります。注釈とラベルでは、使用するジョブのキューとスケジューリング戦略を指定します。

    次の例では、注釈 schedulingPolicyParameters はアプリケーションにギャングスケジューリングをセットアップします。次に、タスクグループ (タスクの「ギャング」) を作成して、ジョブ実行を開始するポッドをスケジュールする前に最小限使用できなければならないキャパシティを指定します。最後に、「YuniKorn 用にクラスターを作成してセットアップする」セクションの定義に従って "app": "spark" ラベルを指定して、ノードグループを使用するようにタスクグループ定義を指定します。

    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. 次のコマンドで Spark アプリケーションを送信します。その結果、spark-pi という名前の SparkApplication オブジェクトも作成されます。

    kubectl apply -f spark-pi.yaml
  4. 次のコマンドで SparkApplication オブジェクトのイベントがないか確認します。

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

    最初のポッドイベントは、YuniKorn がポッドをスケジュールしたことを示しています。

    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

spark-submit を指定して YuniKorn スケジューラで Spark アプリケーションを実行します。

  1. まず、「Amazon EMR on EKS での spark-submit のセットアップ」セクションのステップを完了します。

  2. 次の環境変数の値を設定します。

    export SPARK_HOME=spark-home export MASTER_URL=k8s://Amazon-EKS-cluster-endpoint
  3. 次のコマンドで Spark アプリケーションを送信します。

    次の例では、注釈 schedulingPolicyParameters はアプリケーションにギャングスケジューリングをセットアップします。次に、タスクグループ (タスクの「ギャング」) を作成して、ジョブ実行を開始するポッドをスケジュールする前に最小限使用できなければならないキャパシティを指定します。最後に、「YuniKorn 用にクラスターを作成してセットアップする」セクションの定義に従って "app": "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-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. 次のコマンドで SparkApplication オブジェクトのイベントがないか確認します。

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

    最初のポッドイベントは、YuniKorn がポッドをスケジュールしたことを示しています。

    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