Node Placement

AWS EKS 集群可以跨 VPC 中的多个可用区。Spark 应用程序的driver和executor pod 分布在多个可用区中会产生跨AZ的数据传输成本。为了最小化或消除跨AZ的数据传输成本,可以配置应用程序仅在单个可用区内的节点上运行。此外,根据使用情况,可能需要在特定的实例类型上运行 Spark 应用程序。

单AZ部署

我们将提交一个Spark作业,只在单AZ的节点上运行。

每个node都有label标签,标志它在哪个AZ运行:

image-20240620215347274

提交作业,只在单AZ运行。在下面的命令中替换AZ的值:

aws emr-containers start-job-run \
--virtual-cluster-id ${EMR_EKS_CLUSTER_ID} \
--name spark-pi-single-az \
--execution-role-arn ${EMR_EKS_EXECUTION_ARN} \
--release-label emr-6.2.0-latest \
--job-driver '{
    "sparkSubmitJobDriver": {
        "entryPoint": "s3://aws-data-analytics-workshops/emr-eks-workshop/scripts/pi.py",
        "sparkSubmitParameters": "--conf spark.kubernetes.node.selector.topology.kubernetes.io/zone='<可用区>' --conf spark.executor.instances=1 --conf spark.executor.memory=2G --conf spark.executor.cores=2 --conf spark.driver.cores=1"
        }
    }' \
--configuration-overrides '{
    "applicationConfiguration": [
      {
        "classification": "spark-defaults", 
        "properties": {
          "spark.driver.memory":"2G"
         }
      }
    ], 
    "monitoringConfiguration": {
      "cloudWatchMonitoringConfiguration": {
        "logGroupName": "/emr-containers/jobs", 
        "logStreamNamePrefix": "emr-eks-workshop"
      }, 
      "s3MonitoringConfiguration": {
        "logUri": "'"$S3_BUCKET"'/logs/"
      }
    }
}'

image-20240620215534433

当作业启动时,driver pod和executor pod只会被调度到带有标签topology.kubernetes.io/zone: <az-name>的EKS工作节点上。这确保了Spark作业在单AZ内运行。

结果确认

pod运行在30结尾的IP上:

image-20240620220355140

查看这个IP,发现它确实属于us-west-2d:

image-20240620220438328

参考:

https://spark.apache.org/docs/latest/running-on-kubernetes.html#pod-spec

https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/

AZ是EKS分配给每个EKS工作节点的内置标签。上述配置将确保executor pod和driver pod被调度到带有标签topology.kubernetes.io/zone: <az-name>的EKS工作节点上。

用户定义的标签也可以分配给EKS工作节点并用作节点选择器。

其他常见用例是使用节点标签来强制作业在on-demand/spot实例或特定机型上运行。

使用特定实例类型

我们将提交一个Spark作业,只在单AZ的节点上运行,并使用特定的实例类型。

image-20240620220612702

提交作业,在下面的命令中替换可用区实例类型的值:

aws emr-containers start-job-run \
--virtual-cluster-id ${EMR_EKS_CLUSTER_ID} \
--name spark-pi-single-az-instance-type \
--execution-role-arn ${EMR_EKS_EXECUTION_ARN} \
--release-label emr-6.2.0-latest \
--job-driver '{
    "sparkSubmitJobDriver": {
        "entryPoint": "s3://aws-data-analytics-workshops/emr-eks-workshop/scripts/pi.py",
        "sparkSubmitParameters": "--conf spark.executor.instances=2 --conf spark.executor.memory=2G --conf spark.executor.cores=2 --conf spark.driver.cores=1"
        }
    }' \
--configuration-overrides '{
    "applicationConfiguration": [
      {
        "classification": "spark-defaults", 
        "properties": {
          "spark.driver.memory":"2G",
          "spark.kubernetes.node.selector.topology.kubernetes.io/zone":"<可用区>",
          "spark.kubernetes.node.selector.node.kubernetes.io/instance-type":"<实例类型>"
         }
      }
    ], 
    "monitoringConfiguration": {
      "cloudWatchMonitoringConfiguration": {
        "logGroupName": "/emr-containers/jobs", 
        "logStreamNamePrefix": "emr-eks-workshop"
      }, 
      "s3MonitoringConfiguration": {
        "logUri": "'"$S3_BUCKET"'/logs/"
      }
    }
}'

当作业启动时,driver pod和executor pod只会被调度到带有标签topology.kubernetes.io/zone: <可用区>和标签node.kubernetes.io/instance-type: <实例类型>的EKS工作节点上。这确保了Spark作业在单一可用区和特定实例类型上运行:

image-20240620220804125

由于我们的集群中全部都是c5.xlarge机型,所以上面任务的pod永远不会被调度:

image-20240620220927574

这个侧面印证了instance-type这个selector生效了,如果改成c5.xlarge则任务会正常运行

另外,可以传递多个键值对给spark.kubernetes.node.selector.[labelKey]来添加筛选条件,以选择EKS工作节点。