本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
使用 Pod 範本
從 Amazon EMR 版本 5.33.0 或 6.3.0 開始,Amazon EMR 上EKS支持星火的網繭模板功能。Pod 是一個或多個容器群組,其中包含共用儲存和網路資源,以及如何執行容器的規範。Pod 範本是決定如何執行每個 Pod 的規範。可以使用 Pod 範本檔案來定義 Spark 組態不支援的驅動程式或執行程式 Pod 組態。如需有關 Spark 的 Pod 範本功能的詳細資訊,請參閱 Pod 範本
注意
Pod 範本功能僅適用於驅動程式和執行程式 Pod。您無法使用網繭範本設定工作提交者網繭。
常用案例
您可以在 Amazon EMR 上使用 pod 範本,定義如何在共用EKS叢集上執行 Spark 任務,EKS並節省成本並改善資源使用率和效能。
-
為了降低成本,您可以安排 Spark 驅動程式任務在 Amazon EC2 隨需執行個體上執行,同時排程 Spark 執行程式任務在 Amazon S EC2 pot 執行個體上執行。
-
若要提高資源使用率,您可以支援多個團隊在同一EKS叢集上執行其工作負載。每個團隊都會獲得一個指定的 Amazon EC2 節點群組,以便在其上執行工作負載。可以使用 Pod 範本,將對應的容差套用至其工作負載。
-
若要改善監控,可以執行單獨的日誌容器,將日誌轉寄至現有的監控應用程式。
例如,下列 Pod 範本檔案示範常見的使用案例。
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>
Pod 範本會完成下列任務:
-
新增一個在 Spark 主容器啟動之前執行的初始化容器
。初始化容器共享 source-data-volume
與 Spark 主容器調用的EmptyDir卷。可以讓初始化容器執行初始化步驟,例如下載相依性或產生輸入資料。然後,Spark 主容器會消耗資料。 -
新增與 Spark 主容器一起執行的另一個附屬容器
。這兩個容器正在共用另一個稱為的 metrics-files-volume
的EmptyDir
磁碟區。您的 Spark 作業可以產生指標,例如 Prometheus 指標。然後,Spark 作業可以將指標放入檔案中,並讓附屬容器將檔案上傳到您自己的 BI 系統,以供將來分析。 -
將新環境變數新增至 Spark 主容器。可以讓作業消耗環境變數。
-
定義節點選取器
,以便僅在 emr-containers-nodegroup
節點群組上排程 Pod。這有助於隔離作業和團隊的運算資源。
使用 Amazon EMR 啟用網繭範本 EKS
若要在 Amazon EMR 上啟用網繭範本功能EKS,請設定 Spark 屬性,spark.kubernetes.driver.podTemplateFile
並指spark.kubernetes.executor.podTemplateFile
向 Amazon S3 中的網繭範本檔案。然後,Spark 會下載 Pod 範本檔案,並使用它來建構驅動程式和執行程式 Pod。
注意
Spark 使用作業執行角色來載入 Pod 範本,因此作業執行角色必須有權存取 Amazon S3 以載入 Pod 範本。如需詳細資訊,請參閱建立作業執行角色。
您可以使用指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
" } } ] } }
注意
-
EMR在 Amazon 上使用網繭範本功能時,您需要遵循安全準則EKS,例如隔離不受信任的應用程式程式碼。如需詳細資訊,請參閱Amazon EMR on EKS 安全最佳實務。
-
無法使用
spark.kubernetes.driver.podTemplateContainerName
和spark.kubernetes.executor.podTemplateContainerName
來變更 Spark 主容器名稱 ,因為這些名稱硬編碼為spark-kubernetes-driver
和spark-kubernetes-executors
。如果想要自訂 Spark 主容器,則必須使用這些硬編碼名稱在 Pod 範本中指定容器。
Pod 範本欄位
EMR在使用 Amazon 設定網繭範本時,請考慮下列欄位限制EKS。
-
Amazon EMR on 僅EKS允許網繭範本中的下列欄位以啟用適當的任務排程。
以下是允許的 Pod 層級欄位:
-
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.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
當您在 Pod 範本中使用任何不允許的欄位時,Spark 會擲出例外狀況,且作業失敗。下列範例會顯示 Spark 控制器日誌中的錯誤訊息,因為存在不允許的欄位。
Executor pod template validation failed. Field container.command in Spark main container not allowed but specified.
-
-
Amazon EMR on 會在網繭範本中EKS預先定義下列參數。在 Pod 範本中指定的欄位不得與這些欄位重疊。
以下是預先定義的磁碟區名稱:
-
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
並將其掛接到 Pod 範本中定義的您自己的附屬容器。如果您指定的欄位與 Pod 範本中的任何預定義欄位衝突,Spark 會擲出例外狀況,而作業會失敗。下列範例會顯示 Spark 應用程式日誌中的錯誤訊息,因為與預定義的欄位衝突。
Defined volume mount path on main container must not overlap with reserved mount paths: [<reserved-paths>]
-
附屬容器的考量
Amazon EMR 控制 Amazon EMR 在上佈建的網繭的生命週期EKS。附屬容器應遵循 Spark 主容器的相同生命週期。如果您將額外的附加容器插入網繭,建議您與 Amazon EMR 定義的網繭生命週期管理整合,以便 Spark 主容器結束時,並行容器可以自行停止。
為了降低成本,建議您實施一個程序,以防止具有附屬容器的驅動程式 Pod 在作業完成後繼續執行。當執行程式完成時,Spark 驅動程式會刪除執行程式 Pod。但是,當驅動程式完成時,其他附屬容器會繼續執行。網繭一直計費,直到 Amazon EKS 清理驅動程式網繭為止,通常EMR在驅動程式 Spark 主容器完成後不到一分鐘。為了降低成本,您可以將其他附加的附屬容器與 Amazon 針對驅動程式和執行程式網EMR繭EKS定義的生命週期管理機制整合,如下節所述。
驅動程式和執行程式 Pod 中的 Spark 主容器每兩秒向檔案 /var/log/fluentd/main-container-terminated
傳送一次 heartbeat
。透過將 Amazon EMR 預先定義的emr-container-communicate
磁碟區掛載新增至附屬容器,您可以定義附屬容器的子流程,以定期追蹤此檔案的上次修改時間。然後,如果子流程發現 Spark 主容器長時間停止 heartbeat
,則子流程會自行停止。
下列範例示範追蹤活動訊號檔案並自行停止的子流程。Replace (取代) your_volume_mount
使用掛載預定義卷的路徑。指令碼綁定在附屬容器使用的映像內。在 Pod 範本檔案中,可以使用下列命令 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