Verwenden von Pod-Vorlagen - Amazon EMR

Die vorliegende Übersetzung wurde maschinell erstellt. Im Falle eines Konflikts oder eines Widerspruchs zwischen dieser übersetzten Fassung und der englischen Fassung (einschließlich infolge von Verzögerungen bei der Übersetzung) ist die englische Fassung maßgeblich.

Verwenden von Pod-Vorlagen

Ab den Amazon-EMR-Versionen 5.33.0 oder 6.3.0 unterstützt Amazon EMR in EKS das Pod-Vorlagenfeature von Spark. Ein Pod ist eine Gruppe von einem oder mehreren Containern mit gemeinsam genutzten Speicher- und Netzwerkressourcen und einer Spezifikation für die Ausführung der Container. Pod-Vorlagen sind Spezifikationen, die bestimmen, wie jeder Pod ausgeführt wird. Sie können Pod-Vorlagendateien verwenden, um die Treiber- oder Executor-Pod-Konfigurationen zu definieren, die Spark-Konfigurationen nicht unterstützen. Weitere Informationen zum Pod-Vorlagenfeature von Spark finden Sie unter Pod-Vorlage.

Anmerkung

Das Pod-Vorlagenfeature funktioniert nur mit Treiber- und Executor-Pods. Sie können Auftrag-Controller-Pods nicht mithilfe der Pod-Vorlage konfigurieren.

Gängige Szenarien

Sie können definieren, wie Spark-Aufträge auf gemeinsam genutzten EKS-Clustern ausgeführt werden, indem Sie Pod-Vorlagen mit Amazon EMR in EKS verwenden. So können Sie Kosten sparen und die Ressourcennutzung und Leistung verbessern.

  • Um die Kosten zu senken, können Sie Spark-Treiberaufgaben so planen, dass sie auf On-Demand-Instances von Amazon EC2 ausgeführt werden, und gleichzeitig Spark-Executor-Aufgaben für die Ausführung auf Amazon-EC2-Spot Instances planen.

  • Um die Ressourcennutzung zu erhöhen, können Sie mehrere Teams dabei unterstützen, ihre Workloads auf demselben EKS-Cluster auszuführen. Jedes Team erhält eine bestimmte Amazon-EC2-Knotengruppe, auf der es seine Workloads ausführen kann. Sie können Pod-Vorlagen verwenden, um eine entsprechende Toleranz auf ihren Workload anzuwenden.

  • Um die Überwachung zu verbessern, können Sie einen separaten Protokollierungs-Container ausführen, um Protokolle an Ihre bestehende Überwachungsanwendung weiterzuleiten.

Die folgende Pod-Vorlagendatei veranschaulicht beispielsweise ein gängiges Nutzungsszenario.

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>

Die Pod-Vorlage führt die folgenden Aufgaben aus:

  • Fügen Sie einen neuen Init-Container hinzu, der ausgeführt wird, bevor der Spark-Hauptcontainer gestartet wird. Der Init-Container teilt sich das aufgerufene EmptyDir-Volume namens source-data-volume mit dem Spark-Hauptcontainer. Sie können Ihren Init-Container Initialisierungsschritte wie das Herunterladen von Abhängigkeiten oder das Generieren von Eingabedaten ausführen lassen. Dann verbraucht der Spark-Hauptcontainer die Daten.

  • Fügen Sie einen weiteren Sidecar-Container hinzu, der zusammen mit dem Spark-Hauptcontainer ausgeführt wird. Die beiden Container teilen sich ein weiteres EmptyDir-Volume namens metrics-files-volume. Ihr Spark-Auftrag kann Metriken wie Prometheus-Metriken generieren. Dann kann der Spark-Auftrag die Metriken in eine Datei schreiben und den Sidecar-Container die Dateien zur zukünfigen Analyse in Ihr eigenes BI-System hochladen lassen.

  • Fügen Sie dem Spark-Hauptcontainer eine neue Umgebungsvariable hinzu. Sie können festlegen, dass Ihr Auftrag die Umgebungsvariable verwendet.

  • Definieren Sie eine Knotenauswahl, sodass der Pod nur für die emr-containers-nodegroup-Knotengruppe geplant ist. Dies hilft dabei, Rechenressourcen für verschiedene Aufträge und Teams zu isolieren.

Aktivieren von Pod-Vorlagen mit Amazon EMR in EKS

Um das Pod-Vorlagenfeature mit Amazon EMR in EKS zu aktivieren, konfigurieren Sie die Spark-Eigenschaften spark.kubernetes.driver.podTemplateFile und spark.kubernetes.executor.podTemplateFile verweisen Sie auf die Pod-Vorlagendateien in Amazon S3. Spark lädt dann die Pod-Vorlagendatei herunter und verwendet sie, um Treiber- und Executor-Pods zu erstellen.

Anmerkung

Spark verwendet die Auftragausführungsrolle, um die Pod-Vorlage zu laden, sodass die Auftragausführungsrolle über Zugriffsberechtigungen für Amazon S3 verfügen muss, um die Pod-Vorlagen zu laden. Weitere Informationen finden Sie unter Erstellen einer Aufgabenausführungsrolle.

Sie können SparkSubmitParameters verwenden, um den Amazon-S3-Pfad zur Pod-Vorlage anzugeben, wie die folgende JSON-Datei mit der Auftragausführung zeigt.

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

Alternativ können Sie den configurationOverrides verwenden, um den Amazon-S3-Pfad zur Pod-Vorlage anzugeben, wie die folgende JSON-Datei mit der Auftragausführung zeigt.

{ "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" } } ] } }
Anmerkung
  1. Sie müssen die Sicherheitsrichtlinien befolgen, wenn Sie das Pod-Vorlagenfeature mit Amazon EMR in EKS verwenden, z. B. das Isolieren von nicht vertrauenswürdigem Anwendungscode. Weitere Informationen finden Sie unter Bewährte Methoden für Sicherheit in Amazon EMR in EKS.

  2. Sie können die Namen der Spark-Hauptcontainer nicht mit spark.kubernetes.driver.podTemplateContainerName und spark.kubernetes.executor.podTemplateContainerName ändern, da diese Namen als spark-kubernetes-driver und spark-kubernetes-executors fest codiert sind. Wenn Sie den Spark-Hauptcontainer anpassen möchten, müssen Sie den Container in einer Pod-Vorlage mit diesen hartcodierten Namen angeben.

Pod-Vorlagenfelder

Beachten Sie die folgenden Feldeinschränkungen, wenn Sie eine Pod-Vorlage mit Amazon EMR in EKS konfigurieren.

  • Amazon EMR in EKS erlaubt nur die folgenden Felder in einer Pod-Vorlage, um eine korrekte Aufgabenplanung zu ermöglichen.

    Dies sind die zulässigen Felder auf Pod-Ebene:

    • 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

    Dies sind die zulässigen Felder auf Spark-Hauptcontainerebene:

    • env

    • envFrom

    • name

    • lifecycle

    • livenessProbe

    • readinessProbe

    • resources

    • startupProbe

    • stdin

    • stdinOnce

    • terminationMessagePath

    • terminationMessagePolicy

    • tty

    • volumeDevices

    • volumeMounts

    • workingDir

    Wenn Sie unzulässige Felder in der Pod-Vorlage verwenden, löst Spark eine Ausnahme aus und der Auftrag schlägt fehl. Das folgende Beispiel zeigt eine Fehlermeldung im Spark-Controller-Protokoll, die auf unzulässige Felder zurückzuführen ist.

    Executor pod template validation failed. Field container.command in Spark main container not allowed but specified.
  • Amazon EMR in EKS definiert die folgenden Parameter in einer Pod-Vorlage vordefiniert. Die Felder, die Sie in einer Pod-Vorlage angeben, dürfen sich nicht mit diesen Feldern überschneiden.

    Dies sind die vordefinierten Volume-Namen:

    • 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

    Dies sind die vordefinierten Volume-Mounts, die nur für den Spark-Hauptcontainer gelten:

    • Name: emr-container-communicate; MountPath: /var/log/fluentd

    • Name: emr-container-application-log-dir; MountPath: /var/log/spark/user

    • Name: emr-container-event-log-dir; MountPath: /var/log/spark/apps

    • Name: mnt-dir; MountPath: /mnt

    • Name: temp-data-dir; MountPath: /tmp

    • Name: home-dir; MountPath: /home/hadoop

    Dies sind die vordefinierten Umgebungsvariablen, die nur für den Spark-Hauptcontainer gelten:

    • SPARK_CONTAINER_ID

    • K8S_SPARK_LOG_URL_STDERR

    • K8S_SPARK_LOG_URL_STDOUT

    • SIDECAR_SIGNAL_FILE

    Anmerkung

    Sie können diese vordefinierten Volumes weiterhin verwenden und sie in Ihre zusätzlichen Sidecar-Container einbinden. Sie können beispielsweise emr-container-application-log-dir verwenden und in Ihrem eigenen Sidecar-Container bereitstellen, der in der Pod-Vorlage definiert ist.

    Wenn die von Ihnen angegebenen Felder mit einem der vordefinierten Felder in der Pod-Vorlage in Konflikt stehen, löst Spark eine Ausnahme aus und der Auftrag schlägt fehl. Das folgende Beispiel zeigt eine Fehlermeldung im Spark-Anwendungsprotokoll aufgrund von Konflikten mit den vordefinierten Feldern.

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

Überlegungen zu Sidecarcontainern

Amazon EMR steuert den Lebenszyklus der Pods, die von Amazon EMR in EKS bereitgestellt werden. Die Sidecar-Container sollten dem gleichen Lebenszyklus folgen wie der Spark-Hauptcontainer. Wenn Sie zusätzliche Sidecar-Container in Ihre Pods einbauen, empfehlen wir Ihnen, das Pod-Lifecycle-Management, das Amazon EMR definiert, zu integrieren, sodass sich der Sidecar-Container selbst stoppen kann, wenn der Spark-Hauptcontainer verlassen wird.

Um die Kosten zu senken, empfehlen wir Ihnen, einen Prozess zu implementieren, der verhindert, dass Treiber-Pods mit Sidecar-Containern nach Abschluss Ihres Aufträge weiter ausgeführt werden. Der Spark-Treiber löscht Ausführer-Pods, wenn der Ausführer fertig ist. Wenn ein Treiberprogramm abgeschlossen ist, werden die zusätzlichen Sidecar-Container jedoch weiter ausgeführt. Der Pod wird in Rechnung gestellt, bis Amazon EMR in EKS den Treiber-Pod bereinigt hat, normalerweise weniger als eine Minute, nachdem der Treiber-Spark-Hauptcontainer abgeschlossen ist. Um die Kosten zu senken, können Sie Ihre zusätzlichen Sidecar-Container in den Lebenszyklus-Management-Mechanismus integrieren, den Amazon EMR in EKS sowohl für Treiber- als auch für Ausführer-Pods definiert, wie im folgenden Abschnitt beschrieben.

Der Spark-Hauptcontainer in den Treiber- und Ausführer-Pods sendet heartbeat alle zwei Sekunden an eine /var/log/fluentd/main-container-terminated-Datei. Indem Sie den vordefinierten emr-container-communicate-Amazon-EMR-Volume-Mount zu Ihrem Sidecar-Container hinzufügen, können Sie einen Unterprozess Ihres Sidecar-Containers definieren, der regelmäßig den Zeitpunkt der letzten Änderung für diese Datei verfolgt. Der Unterprozess stoppt sich dann selbst, wenn er feststellt, dass der Spark-Hauptcontainer den heartbeat für einen längeren Zeitraum stoppt.

Das folgende Beispiel zeigt einen Unterprozess, der die Heartbeat-Datei verfolgt und sich selbst stoppt. Ersetzen Sie your_volume_mount durch den Pfad, in dem Sie das vordefinierte Volume mounten. Das Skript ist in dem Image gebündelt, das vom Sidecar-Container verwendet wird. In einer Pod-Vorlagendatei können Sie einen Sidecar-Container mit den folgenden Befehlen sub_process_script.sh und main_command angeben.

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