Uso dei modelli di pod - Amazon EMR

Uso dei modelli di pod

A partire da Amazon EMR versioni 5.33.0 o 6.3.0, Amazon EMR su EKS supporta la funzione dei modelli di pod di Spark. Un pod è un gruppo di uno o più container, con risorse di rete e archiviazione condivise e una specifica per l'esecuzione dei container. I modelli di pod sono specifiche che determinano la modalità di esecuzione di ciascun pod. È possibile utilizzare i file dei modelli di pod per definire le configurazioni dei pod driver o executor non supportate dalle configurazioni Spark. Per ulteriori informazioni sulla funzione dei modelli di pod di Spark, consulta Modelli di pod.

Nota

La funzione dei modelli di pod funziona solo con i pod driver ed executor. Non è possibile configurare i pod del controller di processo utilizzando il modello di pod.

Scenari comuni

È possibile definire come eseguire i processi Spark in cluster EKS condivisi utilizzando i modelli di pod con Amazon EMR su EKS e, al contempo, risparmiare sui costi e migliorare l'utilizzo e le prestazioni delle risorse.

  • Per ridurre i costi, puoi pianificare l'esecuzione delle attività dei driver Spark su istanze On Demand Amazon EC2 mentre pianifichi le attività dell'executor Spark per l'esecuzione su istanze Spot Amazon EC2.

  • Per incrementare l'utilizzo delle risorse, è possibile supportare più team che eseguono i propri carichi di lavoro nello stesso cluster EKS. Ogni team riceverà un gruppo di nodi Amazon EC2 designato su cui eseguire i propri carichi di lavoro. È possibile utilizzare i modelli di pod per applicare una tolleranza corrispondente al carico di lavoro.

  • Per migliorare il monitoraggio, è possibile eseguire un container di log separato per inoltrare i log all'applicazione di monitoraggio esistente.

Ad esempio, il file del modello pod riportato di seguito illustra uno scenario di utilizzo comune.

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>

Il modello di pod completa le attività seguenti:

  • Aggiungi un nuovo container init da eseguire prima dell'avvio del container principale Spark. Il container init condivide il volume EmptyDir chiamato source-data-volume con il container principale Spark. È possibile fare in modo che il container init esegua i passaggi di inizializzazione, come il download di dipendenze o la generazione di dati di input. In seguito, il container principale Spark consuma i dati.

  • Aggiungi un altro container sidecar da eseguire insieme al container principale Spark. I due container stanno condividendo un altro volume EmptyDir chiamatometrics-files-volume. Il processo Spark può generare parametri quali i parametri Prometheus. In seguito il processo Spark può inserire i parametri in un file e fare in modo che il container sidecar carichi i file nel proprio sistema BI per analisi future.

  • Aggiungi una nuova variabile ambiente al container principale Spark. Puoi fare in modo che il processo utilizzi la variabile ambiente.

  • Definisci un selettore di nodi, in modo che il pod sia pianificato solo sul gruppo di nodi emr-containers-nodegroup. Ciò consente di isolare le risorse di calcolo tra i processi e i team.

Attivazione di modelli di pod con Amazon EMR su EKS

Per abilitare la funzione dei modelli di pod con Amazon EMR su EKS, configura le proprietà Spark spark.kubernetes.driver.podTemplateFile e spark.kubernetes.executor.podTemplateFile per puntare ai file dei modelli di pod in Amazon S3. Spark scarica quindi il file del modello di pod e lo utilizza per costruire pod driver ed executor.

Nota

Spark utilizza il ruolo di esecuzione del processo per caricare il modello di pod, pertanto il ruolo di esecuzione del processo deve disporre delle autorizzazioni per accedere ad Amazon S3 per caricare i modelli di pod. Per ulteriori informazioni, consulta . Creazione di un ruolo di esecuzione del processo.

È possibile utilizzare SparkSubmitParameters per specificare il percorso Amazon S3 al modello di pod, come dimostra il seguente file JSON dell'esecuzione di processo.

{ "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" } } }

In alternativa, è possibile utilizzare configurationOverrides per specificare il percorso Amazon S3 al modello di pod, come dimostra il seguente file JSON dell'esecuzione di processo.

{ "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" } } ] } }
Nota
  1. Quando si utilizza la funzione dei modelli di pod con Amazon EMR su EKS, è necessario seguire le linee guida di sicurezza, ad esempio isolando un eventuale codice dell'applicazione non attendibile. Per ulteriori informazioni, consulta . Best practice relative alla sicurezza.

  2. Non è possibile modificare i nomi dei container principali Spark utilizzando spark.kubernetes.driver.podTemplateContainerName e spark.kubernetes.executor.podTemplateContainerName, perché questi nomi sono codificati come spark-kubernetes-driver e spark-kubernetes-executors. Se si desidera personalizzare il container principale Spark, è necessario specificarlo in un modello di pod con questi nomi codificati.

Campi del modello di pod

Quando configuri un modello di pod con Amazon EMR su EKS, prendi in considerazione le seguenti restrizioni sul campo.

  • Amazon EMR su EKS accetta solo i seguenti campi in un modello di pod per consentire una corretta pianificazione dei processi.

    Seguono i campi a livello di pod consentiti:

    • 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

    Seguono i campi a livello di container principale Spark consentiti:

    • env

    • envFrom

    • name

    • lifecycle

    • livenessProbe

    • readinessProbe

    • resources

    • startupProbe

    • stdin

    • stdinOnce

    • terminationMessagePath

    • terminationMessagePolicy

    • tty

    • volumeDevices

    • volumeMounts

    • workingDir

    Quando si utilizzano campi non consentiti nel modello di pod, Spark genera un'eccezione e il processo ha esito negativo. L'esempio seguente mostra un messaggio di errore nel log del controller Spark a causa di campi non consentiti.

    Executor pod template validation failed. Field container.command in Spark main container not allowed but specified.
  • Amazon EMR su EKS predefinisce i seguenti parametri in un modello di pod. I campi specificati in un modello di pod non devono sovrapporsi a questi campi.

    Seguono i nomi predefiniti dei volumi:

    • 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

    Seguono i montaggi di volume predefiniti che si applicano solo al container principale Spark:

    • Nome: emr-container-communicate; Percorso montaggio: /var/log/fluentd

    • Nome: emr-container-application-log-dir; Percorso montaggio: /var/log/spark/user

    • Nome: emr-container-event-log-dir; Percorso montaggio: /var/log/spark/apps

    • Nome: mnt-dir; Percorso montaggio: /mnt

    • Nome: temp-data-dir; Percorso montaggio: /tmp

    • Nome: home-dir; Percorso montaggio: /home/hadoop

    Seguono le variabili ambiente predefinite che si applicano solo al container principale Spark:

    • SPARK_CONTAINER_ID

    • K8S_SPARK_LOG_URL_STDERR

    • K8S_SPARK_LOG_URL_STDOUT

    • SIDECAR_SIGNAL_FILE

    Nota

    È comunque possibile utilizzare questi volumi predefiniti e montarli nei container sidecar aggiuntivi. Ad esempio, è possibile utilizzare emr-container-application-log-dir e montarlo sul proprio container sidecar definito nel modello di pod.

    Se i campi specificati sono in conflitto con uno qualsiasi dei campi predefiniti nel modello di pod, Spark genera un'eccezione e il processo ha esito negativo. L'esempio seguente mostra un messaggio di errore nel log dell'applicazione Spark a causa di conflitti con i campi predefiniti.

    Defined volume mount path on main container must not overlap with reserved mount paths: [<reserved-paths>]

Considerazioni sui container sidecar

Amazon EMR controlla il ciclo di vita dei pod forniti da Amazon EMR su EKS. I container sidecar devono seguire lo stesso ciclo di vita del container principale Spark. Se inserisci ulteriori container sidecar nei tuoi pod, ti consigliamo di integrare la gestione del ciclo di vita dei pod definita da Amazon EMR in modo che il container sidecar possa bloccarsi quando il container principale Spark esce.

Per ridurre i costi, è consigliabile implementare un processo che impedisce ai pod driver con container sidecar di continuare a funzionare al termine del processo. Il driver Spark elimina i pod executor quando l'executor viene terminato. Tuttavia, al termine di un programma driver, i container sidecar aggiuntivi continuano a funzionare. Il pod viene fatturato fino a quando Amazon EMR su EKS non elimina il pod driver, generalmente meno di un minuto dopo il completamento del container principale del driver Spark. Per ridurre i costi, è possibile integrare i container sidecar aggiuntivi con il meccanismo di gestione del ciclo di vita definito da Amazon EMR su EKS sia per i pod driver che per i pod executor, come descritto nella sezione seguente.

Il container principale Spark nei pod driver ed executor invia heartbeat a un file /var/log/fluentd/main-container-terminated ogni due secondi. Aggiungendo il montaggio del volume emr-container-communicate predefinito di Amazon EMR sul container sidecar, è possibile definire un sottoprocesso del container sidecar per tenere traccia periodicamente dell'ora dell'ultima modifica di questo file. Il sottoprocesso si arresta se scopre che il container principale Spark arresta il heartbeat per una durata di tempo maggiore.

Nell'esempio seguente viene illustrato un sottoprocesso che tiene traccia del file heartbeat e si arresta. Sostituisci your_volume_mount con il percorso in cui desideri montare il volume predefinito. Lo script è raggruppato all'interno dell'immagine utilizzata dal container sidecar. In un file del modello di pod, è possibile specificare un container sidecar con i seguenti comandi sub_process_script.sh e 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