本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
使用 Pod 模板
從亞馬遜 EMR 5.33.0 或 6.3.0 開始,EKS 上的亞馬遜 EMR 支持 Spark 的容器模板功能。容器是一組或多個容器,其中包含共享存儲和網絡資源,以及如何運行容器的規範。容器模板是確定如何運行每個容器的規範。您可以使用容器模板文件來定義 Spark 配置不支持的驅動程序或執行程序容器容器的配置。如需 Spark 的容器模板功能的詳細資訊,請參Pod 模板
容器模板功能僅適用於驅動程序和執行程序窗格。您無法使用容器模板配置作業控制器窗格。
常用案例
您可以定義如何在共享 EKS 上使用具有 Amazon EMR 的容器模板在共享 EKS 羣集上運行 Spark 作業,從而節省成本並提高資源利用率和性能。
-
為了降低成本,您可以安排 Spark 驅動程序任務在 Amazon EC2 上按需運行I安排在 Amazon EC2 競價上運行的 Spark 執行器任務時的情況I立場。
-
為了提高資源利用率,您可以支持多個團隊在同一個 EKS 羣集上運行其工作負載。每個團隊都將獲得一個指定的 Amazon EC2 節點組來運行其工作負載。您可以使用容器模板將相應的容差應用於其工作負載。
-
要改進監控,您可以運行單獨的日誌記錄容器,將日誌轉發到現有的監視應用程序。
例如,以下容器模板文件演示了一種常見的使用方案。
apiVersion: v1 kind: Pod spec: volumes: - name: source-data-volume emptyDir: {} - name: metrics-files-volume emptyDir: {} nodeSelector: eks.amazonaws.com/nodegroup: emr-containers-nodegroup containers: - name: spark-kubernetes-driver # This will be interpreted as driver Spark main container env: - name: RANDOM value: "random" volumeMounts: - name: shared-volume mountPath: /var/data - name: metrics-files-volume mountPath: /var/metrics/data - name: custom-side-car-container # Sidecar container image: <side_car_container_image> env: - name: RANDOM_SIDECAR value: random volumeMounts: - name: metrics-files-volume mountPath: /var/metrics/data command: - /bin/sh - '-c' - <command-to-upload-metrics-files> initContainers: - name: spark-init-container-driver # Init container image: <spark-pre-step-image> volumeMounts: - name: source-data-volume # Use EMR predefined volumes mountPath: /var/data command: - /bin/sh - '-c' - <command-to-download-dependency-jars>
容器模板完成下列任務:
-
新增一個新的初始化容器
,這是在 Spark 主容器啟動之前執行的。init 容器共享EmptyDir體積 呼叫 source-data-volume
與火花主容器。您可以讓 init 容器運行初始化步驟,例如下載依賴關係或生成輸入數據。然後 Spark 主容器會消耗數據。 -
新增另一個附屬容器
,它與 Spark 主容器一起執行。這兩個容器正在共享另一個 EmptyDir
卷調用metrics-files-volume
。您的 Spark 作業可以生成指標,例如 Prometheus 指標。然後,Spark 作業可以將指標放入文件中,並讓 side car 容器將文件上傳到您自己的 BI 系統,以便將來進行分析。 -
將新的環境變量添加到 Spark 主容器。您可以讓您的作業使用環境變量。
-
定義節點選擇器
,以便該容器僅安排在 emr-containers-nodegroup
節點組。這有助於跨工作和團隊隔離計算資源。
在 EKS 上使用 Amazon EMR 啟用容器模板
要使用 EKS 上的 Amazon EMR 啟用容器模板功能,請配置 Spark 屬性spark.kubernetes.driver.podTemplateFile
和spark.kubernetes.executor.podTemplateFile
以指向 Amazon S3 中的容器模板檔案。然後,Spark 下載容器模板文件並使用它來構建驅動程序和執行器窗格。
Spark 使用作業執行角色加載容器模板,因此作業執行角色必須具有訪問 Amazon S3 才能加載容器模板的權限。如需詳細資訊,請參閱 建立任務執行角色。
您可以使用SparkSubmitParameters
以指定容器模板的 Amazon S3 路徑,如以下作業運行 JSON 文件所示。
{ "name": "myjob", "virtualClusterId": "123456", "executionRoleArn": "iam_role_name_for_job_execution", "releaseLabel": "
release_label
", "jobDriver": { "sparkSubmitJobDriver": { "entryPoint": "entryPoint_location", "entryPointArguments": ["argument1
", "argument2
", ...], "sparkSubmitParameters": "--class <main_class> \ --conf spark.kubernetes.driver.podTemplateFile=s3://path_to_driver_pod_template
\ --conf spark.kubernetes.executor.podTemplateFile=s3://path_to_executor_pod_template
\ --conf spark.executor.instances=2 \ --conf spark.executor.memory=2G \ --conf spark.executor.cores=2 \ --conf spark.driver.cores=1" } } }
或者,您也可以使用configurationOverrides
以指定容器模板的 Amazon S3 路徑,如以下作業運行 JSON 文件所示。
{ "name": "myjob", "virtualClusterId": "123456", "executionRoleArn": "iam_role_name_for_job_execution", "releaseLabel": "
release_label
", "jobDriver": { "sparkSubmitJobDriver": { "entryPoint": "entryPoint_location", "entryPointArguments": ["argument1
", "argument2
", ...], "sparkSubmitParameters": "--class <main_class> \ --conf spark.executor.instances=2 \ --conf spark.executor.memory=2G \ --conf spark.executor.cores=2 \ --conf spark.driver.cores=1" } }, "configurationOverrides": { "applicationConfiguration": [ { "classification": "spark-defaults", "properties": { "spark.driver.memory":"2G", "spark.kubernetes.driver.podTemplateFile":"s3://path_to_driver_pod_template
", "spark.kubernetes.executor.podTemplateFile":"s3://path_to_executor_pod_template
" } } ] } }
-
將容器模板功能與 EKS 上的 Amazon EMR 配合使用時,您需要遵循安全指南,例如隔離不受信任的應用程序代碼。如需詳細資訊,請參閱 安全最佳實務。
-
您不能更改 Spark 主容器名稱,使用
spark.kubernetes.driver.podTemplateContainerName
和spark.kubernetes.executor.podTemplateContainerName
,因為這些名稱被硬編碼為spark-kubernetes-driver
和spark-kubernetes-executors
。如果要自定義 Spark 主容器,則必須使用這些硬編碼名稱在容器模板中指定容器。
Pod 模板字段
在 EKS 上使用 Amazon EMR 配置容器模板時,請考慮以下字段限制。
-
EKS 上的 Amazon EMR 僅允許在容器模板中使用以下字段,以實現正確的作業安排。
以下是允許的容器級別字段:
-
apiVersion
-
kind
-
metadata
-
spec.activeDeadlineSeconds
-
spec.affinity
-
spec.containers
-
spec.enableServiceLinks
-
spec.ephemeralContainers
-
spec.hostAliases
-
spec.hostname
-
spec.imagePullSecrets
-
spec.initContainers
-
spec.nodeName
-
spec.nodeSelector
-
spec.overhead
-
spec.preemptionPolicy
-
spec.priority
-
spec.priorityClassName
-
spec.readinessGates
-
spec.restartPolicy
-
spec.runtimeClassName
-
spec.schedulerName
-
spec.subdomain
-
spec.terminationGracePeriodSeconds
-
spec.tolerations
-
spec.topologySpreadConstraints
-
spec.volumes
以下是允許的 Spark 主容器級別字段:
-
env
-
envFrom
-
name
-
lifecycle
-
livenessProbe
-
readinessProbe
-
resources
-
startupProbe
-
stdin
-
stdinOnce
-
terminationMessagePath
-
terminationMessagePolicy
-
tty
-
volumeDevices
-
volumeMounts
-
workingDir
當您在容器模板中使用任何不允許的字段時,Spark 會拋出異常,並且作業失敗。以下示例顯示了由於不允許的字段而在 Spark 控制器日誌中出現的錯誤消息。
Executor pod template validation failed. Field container.command in Spark main container not allowed but specified.
-
-
EKS 上的 Amazon EMR 在容器模板中預定義了以下參數。在容器模板中指定的字段不得與這些字段重疊。
以下是預定義的卷名稱:
-
emr-container-communicate
-
config-volume
-
emr-container-application-log-dir
-
emr-container-event-log-dir
-
temp-data-dir
-
mnt-dir
-
home-dir
-
emr-container-s3
以下是僅適用於 Spark 主容器的預定義卷裝載:
-
名稱:
emr-container-communicate
;MountPath:/var/log/fluentd
-
名稱:
emr-container-application-log-dir
;MountPath:/var/log/spark/user
-
名稱:
emr-container-event-log-dir
;MountPath:/var/log/spark/apps
-
名稱:
mnt-dir
;MountPath:/mnt
-
名稱:
temp-data-dir
;MountPath:/tmp
-
名稱:
home-dir
;MountPath:/home/hadoop
以下是僅適用於 Spark 主容器的預定義環境變量:
-
SPARK_CONTAINER_ID
-
K8S_SPARK_LOG_URL_STDERR
-
K8S_SPARK_LOG_URL_STDOUT
-
SIDECAR_SIGNAL_FILE
注意 您仍然可以使用這些預定義的卷並將其安裝到附加的側車容器中。例如,您可以使用
emr-container-application-log-dir
並將其安裝到容器模板中定義的自己的側車容器中。如果您指定的字段與容器模板中的任何預定義字段發生衝突,Spark 將拋出異常,並且作業將失敗。以下示例顯示了由於與預定義字段衝突而在 Spark 應用程序日誌中出現的錯誤消息。
Defined volume mount path on main container must not overlap with reserved mount paths: [<reserved-paths>]
-
附屬注意事項
亞馬遜 EMR 控制由亞馬遜 EMR 在 EKS 上配置的容器的生命週期。側車容器應遵循 Spark 主容器的相同生命週期。如果您將其他側車容器注入到容器中,我們建議您與 Amazon EMR 定義的容器生命週期管理集成,以便在 Spark 主容器退出時,邊車容器可以自行停止。
為了降低成本,我們建議您實施一個過程,以防止帶有側車容器的驅動程序窗格在作業完成後繼續運行。執行程序完成後,Spark 驅動程序會刪除執行程序窗格。但是,當驅動程序完成後,額外的側車容器將繼續運行。在 EKS 上的 Amazon EMR 清理驅動程序容器之前,通常在驅動程序 Spark 主容器完成後不到一分鐘後,該容器將計費。為了降低成本,您可以將附加的側車容器與 Amazon EMR on EKS 為驅動程序和執行程序容器定義的生命週期管理機制集成,如以下部分所述。
驅動程序中的火花主容器和執行器窗格發送heartbeat
到一個文件/var/log/fluentd/main-container-terminated
每兩秒鐘一次 通過添加預定義的 Amazon EMRemr-container-communicate
卷掛載到您的 sidecar 容器中,您可以定義一個 Sidecar 容器的子進程,以定期跟蹤此文件的上次修改時間。如果子進程發現 Spark 主容器停止heartbeat
持續時間更長。
以下示例演示了跟蹤檢測信號文件並停止自身的子進程。Replace您的卷安裝
與安裝預定義卷的路徑一起使用。該腳本捆綁在旁邊集裝箱使用的圖像中。在容器模板文件中,您可以使用以下命令指定側車容器sub_process_script.sh
和main_command
。
MOUNT_PATH="
your_volume_mount
" FILE_TO_WATCH="$MOUNT_PATH/main-container-terminated" INITIAL_HEARTBEAT_TIMEOUT_THRESHOLD=60 HEARTBEAT_TIMEOUT_THRESHOLD=15 SLEEP_DURATION=10 function terminate_main_process() { # Stop main process } # Waiting for the first heartbeat sent by Spark main container echo "Waiting for file $FILE_TO_WATCH to appear..." start_wait=$(date +%s) while ! [[ -f "$FILE_TO_WATCH" ]]; do elapsed_wait=$(expr $(date +%s) - $start_wait) if [ "$elapsed_wait" -gt "$INITIAL_HEARTBEAT_TIMEOUT_THRESHOLD" ]; then echo "File $FILE_TO_WATCH not found after $INITIAL_HEARTBEAT_TIMEOUT_THRESHOLD seconds; aborting" terminate_main_process exit 1 fi sleep $SLEEP_DURATION; done; echo "Found file $FILE_TO_WATCH; watching for heartbeats..." while [[ -f "$FILE_TO_WATCH" ]]; do LAST_HEARTBEAT=$(stat -c %Y $FILE_TO_WATCH) ELAPSED_TIME_SINCE_AFTER_HEARTBEAT=$(expr $(date +%s) - $LAST_HEARTBEAT) if [ "$ELAPSED_TIME_SINCE_AFTER_HEARTBEAT" -gt "$HEARTBEAT_TIMEOUT_THRESHOLD" ]; then echo "Last heartbeat to file $FILE_TO_WATCH was more than $HEARTBEAT_TIMEOUT_THRESHOLD seconds ago at $LAST_HEARTBEAT; terminating" terminate_main_process exit 0 fi sleep $SLEEP_DURATION; done; echo "Outside of loop, main-container-terminated file no longer exists" # The file will be deleted once the fluentd container is terminated echo "The file $FILE_TO_WATCH doesn't exist any more;" terminate_main_process exit 0