Benutzerdefinierte Container mit Dataproc Serverless für Spark verwenden

Dataproc Serverless for Spark führt Arbeitslasten in Docker-Containern aus. Der Container stellt die Laufzeitumgebung für die Treiber- und Executor-Prozesse der Arbeitslast bereit. Standardmäßig verwendet Dataproc Serverless for Spark ein Container-Image, das die Spark-, Java-, Python- und R-Standardpakete enthält, die einer Laufzeitversion zugeordnet sind. Mit der Dataproc Serverless API für Spark-Batches können Sie anstelle des Standard-Images ein benutzerdefiniertes Container-Image verwenden. In der Regel fügt ein benutzerdefiniertes Container-Image Java- oder Python-Abhängigkeiten für Spark-Arbeitslasten hinzu, die nicht vom Standard-Container-Image bereitgestellt werden. Wichtig: Nehmen Sie Spark nicht in Ihr benutzerdefiniertes Container-Image auf. Dataproc Serverless for Spark stellt Spark zur Laufzeit im Container bereit.

Spark-Batcharbeitslast mit einem benutzerdefinierten Container-Image senden

gcloud

Geben Sie beim Senden einer Spark-Batcharbeitslast mit dem Befehl gcloud dataprocbatchessubmit spark mit dem Flag --container-image Ihr benutzerdefiniertes Container-Image an.

gcloud dataproc batches submit spark \
    --container-image=custom-image, for example, "gcr.io/my-project-id/my-image:1.0.1" \
    --region=region \
    --jars=path to user workload jar located in Cloud Storage or included in the custom container \
    --class=The fully qualified name of a class in the jar file, such as org.apache.spark.examples.SparkPi \
    -- add any workload arguments here

Hinweise:

  • Custom-Image: Geben Sie das benutzerdefinierte Container-Image im folgenden Format für Container Registry-Image-Namen an: {hostname}/{project-id}/{image}:{tag}. Beispiel: "gcr.io/my-project-id/my-image:1.0.1". Hinweis: Sie müssen das benutzerdefinierte Container-Image in Container Registry oder Artifact Registry hosten. Dataproc Serverless kann keine Container aus anderen Registrys abrufen.
  • --jars: Geben Sie einen Pfad zu einer Nutzerarbeitslast an, die in Ihrem benutzerdefinierten Container-Image enthalten ist oder sich in Cloud Storage befindet, z. B. file:///opt/spark/jars/spark-examples.jar oder gs://my-bucket/spark/jars/spark-examples.jar.
  • Andere Batch-Befehlsoptionen: Sie können weitere optionale Batch-Befehls-Flags hinzufügen, um beispielsweise einen Persistent History Server (PHS) zu verwenden. Hinweis: Der PHS muss sich in der Region befinden, in der Sie Batcharbeitslasten ausführen.
  • Arbeitslastargumente Sie können beliebige Arbeitslastargumente hinzufügen. Dazu fügen Sie am Ende des Befehls "--" gefolgt von den Arbeitslastargumenten hinzu.

REST

Das benutzerdefinierte Container-Image wird über das Feld RuntimeConfig.containerImage als Teil der API-Anfrage batches.create bereitgestellt.

Im folgenden Beispiel wird gezeigt, wie Sie einen benutzerdefinierten Container verwenden, um eine Batcharbeitslast mithilfe der API batches.create von Dataproc Serverless for Spark zu senden.

Bevor Sie die Anfragedaten verwenden, ersetzen Sie die folgenden Werte:

  • project-id: ID des Google Cloud-Projekts.
  • region: Region
  • custom-container-image: Geben Sie das benutzerdefinierte Container-Image im folgenden Namensformat für Container Registry-Images an: {hostname}/{project-id}/{image}:{tag}. Beispiel: „gcr.io/my-project-id/my-image:1.0.1“. Hinweis: Der benutzerdefinierte Container muss in Container Registry oder Artifact Registry gehostet werden. Dataproc Serverless kann keine Container aus anderen Registrys abrufen.
  • jar-uri: Geben Sie einen Pfad zu einer Arbeitslast-JAR-Datei an, die in Ihrem benutzerdefinierten Container-Image enthalten ist oder sich in Cloud Storage befindet, z. B. „/opt/spark/jars/spark-examples.jar“ oder „gs:///spark/jars/spark-examples.jar“.
  • class: Der voll qualifizierte Name einer Klasse in der JAR-Datei, z. B. „org.apache.spark.examples.SparkPi“.
  • Weitere Optionen: Sie können andere Batch-Ressourcenfelder für Arbeitslasten verwenden, beispielsweise das Feld sparkBatch.args, um Argumente an die Arbeitslast zu übergeben. Weitere Informationen finden Sie in der Ressourcendokumentation Batch. Informationen zur Verwendung eines Persistent History Servers (PHS) finden Sie unter Nichtflüchtigen Verlaufsserver einrichten. Hinweis: Der PHS muss sich in der Region befinden, in der Sie Batcharbeitslasten ausführen.

HTTP-Methode und URL:

POST https://dataproc.googleapis.com/v1/projects/project-id/locations/region/batches

JSON-Text der Anfrage:

{
  "runtimeConfig":{
    "containerImage":"custom-container-image
  },
  "sparkBatch":{
    "jarFileUris":[
      "jar-uri"
    ],
    "mainClass":"class"
  }
}

Wenn Sie die Anfrage senden möchten, maximieren Sie eine der folgenden Optionen:

Sie sollten in etwa folgende JSON-Antwort erhalten:

{
"name":"projects/project-id/locations/region/batches/batch-id",
  "uuid":",uuid",
  "createTime":"2021-07-22T17:03:46.393957Z",
  "runtimeConfig":{
    "containerImage":"gcr.io/my-project/my-image:1.0.1"
  },
  "sparkBatch":{
    "mainClass":"org.apache.spark.examples.SparkPi",
    "jarFileUris":[
      "/opt/spark/jars/spark-examples.jar"
    ]
  },
  "runtimeInfo":{
    "outputUri":"gs://dataproc-.../driveroutput"
  },
  "state":"SUCCEEDED",
  "stateTime":"2021-07-22T17:06:30.301789Z",
  "creator":"account-email-address",
  "runtimeConfig":{
    "properties":{
      "spark:spark.executor.instances":"2",
      "spark:spark.driver.cores":"2",
      "spark:spark.executor.cores":"2",
      "spark:spark.app.name":"projects/project-id/locations/region/batches/batch-id"
    }
  },
  "environmentConfig":{
    "peripheralsConfig":{
      "sparkHistoryServerConfig":{
      }
    }
  },
  "operation":"projects/project-id/regions/region/operation-id"
}

Benutzerdefiniertes Container-Image erstellen

Dataproc Serverless für benutzerdefinierte Spark-Container-Images sind Docker-Images. Sie können die Tools zum Erstellen von Docker-Images verwenden, um benutzerdefinierte Container-Images zu erstellen. Die Images müssen jedoch bestimmte Bedingungen erfüllen, um mit Dataproc Serverless for Spark kompatibel zu sein. In den folgenden Abschnitten werden diese Bedingungen erläutert.

Betriebssystem

Sie können ein beliebiges Betriebssystem-Image als Basis-Image für Ihr benutzerdefiniertes Container-Image auswählen. Empfehlung: Die Debian 11-Standard-Images werden bevorzugt (z. B. debian:11-slim), da sie getestet wurden, um Kompatibilitätsprobleme zu vermeiden.

Dienstprogramme

Sie müssen die folgenden Dienstprogrammpakete, die zum Ausführen von Spark erforderlich sind, in Ihr benutzerdefiniertes Container-Image aufnehmen:

  • procps
  • tini

Zum Ausführen von XGBoost aus Spark (Java oder Scala) müssen Sie libgomp1 einfügen

Containernutzer

Dataproc Serverless for Spark führt Container als Linux-Nutzer spark mit einer 1099-UID und einer 1099-GID aus. USER-Anweisungen, die in benutzerdefinierten Container-Image-Dockerfiles festgelegt sind, werden zur Laufzeit ignoriert. Verwenden Sie die UID und die GID für Dateisystemberechtigungen. Wenn Sie beispielsweise eine JAR-Datei unter /opt/spark/jars/my-lib.jar im Image als Arbeitslastabhängigkeit hinzufügen, müssen Sie dem spark-Nutzer eine Leseberechtigung für die Datei erteilen.

Image-Streaming

Dataproc Serverless für Spark startet normalerweise eine Arbeitslast, die ein benutzerdefiniertes Container-Image erfordert, indem das gesamte Image auf das Laufwerk heruntergeladen wird. Dies kann insbesondere bei Kunden mit großen Images zu einer Verzögerung bei der Initialisierung führen.

Sie können stattdessen auch das Image-Streaming verwenden. Dabei handelt es sich um eine Methode, um Bilddaten nach Bedarf abzurufen. Dadurch kann die Arbeitslast gestartet werden, ohne auf den Download des gesamten Images warten zu müssen, was möglicherweise die Initialisierungszeit verbessert. Um das Image-Streaming zu aktivieren, müssen Sie die Container File System API aktivieren. Außerdem müssen Sie Ihre Container-Images in Artifact Registry speichern und das Artifact Registry-Repository muss sich in derselben Region wie Ihre Dataproc-Arbeitslast oder an einem multiregionalen Standort befinden, der der Region entspricht, in der die Arbeitslast ausgeführt wird. Wenn Dataproc das Image nicht unterstützt oder der Image-Streaming-Dienst nicht verfügbar ist, lädt die Streaming-Implementierung das gesamte Image herunter. Folgendes wird für das Bildstreaming nicht unterstützt:

In diesen Fällen ruft Dataproc das gesamte Image ab, bevor die Arbeitslast gestartet wird.

Spark

Fügen Sie Spark nicht in Ihr benutzerdefiniertes Container-Image ein. Zur Laufzeit stellt Dataproc Serverless for Spark Spark-Binärdateien und -Konfigurationen vom Host im Container bereit: Binärdateien werden im Verzeichnis /usr/lib/spark und Konfigurationen im Verzeichnis /etc/spark/conf bereitgestellt. Vorhandene Dateien in diesen Verzeichnissen werden zur Laufzeit von Dataproc Serverless für Spark überschrieben.

Java-Laufzeitumgebung

Fügen Sie nicht Ihre eigene Java-Laufzeitumgebung (JRE) in Ihr benutzerdefiniertes Container-Image ein. Zur Laufzeit stellt Dataproc Serverless for Spark OpenJDK vom Host im Container bereit. Wenn Sie eine JRE in Ihr benutzerdefiniertes Container-Image aufnehmen, wird sie ignoriert.

Java-Pakete

Sie können JAR-Dateien als Spark-Arbeitslastabhängigkeiten in Ihr benutzerdefiniertes Container-Image aufnehmen und die Umgebungsvariable SPARK_EXTRA_CLASSPATH so festlegen, dass die JAR-Dateien eingeschlossen werden. Dataproc Serverless for Spark fügt den Wert der Umgebungsvariablen in den Klassenpfad von Spark-JVM-Prozessen ein. Empfehlung: Speichern Sie JAR-Dateien in das Verzeichnis /opt/spark/jars und setzen Sie SPARK_EXTRA_CLASSPATH auf /opt/spark/jars/*.

Sie können die Arbeitslast-JAR-Datei in Ihr benutzerdefiniertes Container-Image einfügen und dann beim Senden der Arbeitslast mit einem lokalen Pfad darauf verweisen, z. B. file:///opt/spark/jars/my-spark-job.jar. Ein Beispiel finden Sie unter Spark-Batcharbeitslast mit einem benutzerdefinierten Container-Image senden.

Python-Pakete

Standardmäßig stellt Dataproc Serverless for Spark zur Laufzeit Conda vom Host im Verzeichnis /opt/dataproc/conda im Container bereit. PYSPARK_PYTHON ist auf /opt/dataproc/conda/bin/python gesetzt. Das Basisverzeichnis /opt/dataproc/conda/bin ist in PATH enthalten.

Sie können Ihre Python-Umgebung mit Paketen in einem anderen Verzeichnis in Ihrem benutzerdefinierten Container-Image aufnehmen, z. B. in /opt/conda, und die Umgebungsvariable PYSPARK_PYTHON auf /opt/conda/bin/python festlegen.

Das benutzerdefinierte Container-Image kann andere Python-Module enthalten, die nicht Teil der Python-Umgebung sind, z. B. Python-Skripts mit Dienstprogrammfunktionen. Legen Sie die Umgebungsvariable PYTHONPATH so fest, dass die Verzeichnisse eingeschlossen werden, in denen sich die Module befinden.

R-Umgebung

Sie können die R-Umgebung in Ihrem benutzerdefinierten Container-Image mit einer der folgenden Optionen anpassen:

  • Verwenden Sie Conda, um R-Pakete aus dem Kanal conda-forge zu verwalten und zu installieren.
  • Fügen Sie ein R-Repository für das Linux-Betriebssystem des Container-Images hinzu und installieren Sie R-Pakete mit dem Linux OS-Paketmanager (siehe R-Software-Paketindex).

Wenn Sie eine der beiden Optionen verwenden, müssen Sie die Umgebungsvariable R_HOME so festlegen, dass sie auf Ihre benutzerdefinierte R-Umgebung verweist. Ausnahme: Wenn Sie mit Conda sowohl Ihre R-Umgebung verwalten als auch Ihre Python-Umgebung anpassen, müssen Sie die Umgebungsvariable R_HOME nicht festlegen. Sie wird automatisch auf Grundlage der Umgebungsvariable PYSPARK_PYTHON festgelegt.

Beispiel für einen benutzerdefinierten Container-Image-Build

Dieser Abschnitt enthält ein Build-Beispiel für ein benutzerdefiniertes Container-Image, das mit einem Beispiel-Dockerfile beginnt.

Dockerfile

# Debian 11 is recommended.
FROM debian:11-slim

# Suppress interactive prompts
ENV DEBIAN_FRONTEND=noninteractive

# (Required) Install utilities required by Spark scripts.
RUN apt update && apt install -y procps tini libjemalloc2

# (Optiona) Install utilities required by XGBoost for Spark.
RUN apt install -y procps libgomp1

# Enable jemalloc2 as default memory allocator
ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2

# (Optional) Add extra jars.
ENV SPARK_EXTRA_JARS_DIR=/opt/spark/jars/
ENV SPARK_EXTRA_CLASSPATH='/opt/spark/jars/*'
RUN mkdir -p "${SPARK_EXTRA_JARS_DIR}"
COPY spark-bigquery-with-dependencies_2.12-0.22.2.jar "${SPARK_EXTRA_JARS_DIR}"

# (Optional) Install and configure Miniconda3.
ENV CONDA_HOME=/opt/miniconda3
ENV PYSPARK_PYTHON=${CONDA_HOME}/bin/python
ENV PATH=${CONDA_HOME}/bin:${PATH}
COPY Miniconda3-py39_4.10.3-Linux-x86_64.sh .
RUN bash Miniconda3-py39_4.10.3-Linux-x86_64.sh -b -p /opt/miniconda3 \
  && ${CONDA_HOME}/bin/conda config --system --set always_yes True \
  && ${CONDA_HOME}/bin/conda config --system --set auto_update_conda False \
  && ${CONDA_HOME}/bin/conda config --system --prepend channels conda-forge \
  && ${CONDA_HOME}/bin/conda config --system --set channel_priority strict
# Packages ipython and ipykernel are required if using custom conda and want to
# use this container for running notebooks.
RUN ${CONDA_HOME}/bin/conda install ipython ipykernel

# (Optional) Install Conda packages.
#
# The following packages are installed in the default image, it is strongly
# recommended to include all of them.
#
# Use mamba to install packages quickly.
RUN ${CONDA_HOME}/bin/conda install mamba -n base -c conda-forge \
    && ${CONDA_HOME}/bin/mamba install \
      conda \
      cython \
      fastavro \
      fastparquet \
      gcsfs \
      google-cloud-bigquery-storage \
      google-cloud-bigquery[pandas] \
      google-cloud-bigtable \
      google-cloud-container \
      google-cloud-datacatalog \
      google-cloud-dataproc \
      google-cloud-datastore \
      google-cloud-language \
      google-cloud-logging \
      google-cloud-monitoring \
      google-cloud-pubsub \
      google-cloud-redis \
      google-cloud-spanner \
      google-cloud-speech \
      google-cloud-storage \
      google-cloud-texttospeech \
      google-cloud-translate \
      google-cloud-vision \
      koalas \
      matplotlib \
      nltk \
      numba \
      numpy \
      openblas \
      orc \
      pandas \
      pyarrow \
      pysal \
      pytables \
      python \
      regex \
      requests \
      rtree \
      scikit-image \
      scikit-learn \
      scipy \
      seaborn \
      sqlalchemy \
      sympy \
      virtualenv

# (Optional) Add extra Python modules.
ENV PYTHONPATH=/opt/python/packages
RUN mkdir -p "${PYTHONPATH}"
COPY test_util.py "${PYTHONPATH}"

# (Optional) Install R and R libraries.
RUN apt update \
  && apt install -y gnupg \
  && apt-key adv --no-tty \
      --keyserver "hkp://keyserver.ubuntu.com:80" \
      --recv-keys E19F5F87128899B192B1A2C2AD5F960A256A04AF \
  && echo "deb http://cloud.r-project.org/bin/linux/debian bullseye-cran40/" \
      >/etc/apt/sources.list.d/cran-r.list \
  && apt update \
  && apt install -y \
      libopenblas-base \
      libssl-dev \
      r-base \
      r-base-dev \
      r-recommended \
      r-cran-blob

ENV R_HOME=/usr/lib/R

# (Required) Create the 'spark' group/user.
# The GID and UID must be 1099. Home directory is required.
RUN groupadd -g 1099 spark
RUN useradd -u 1099 -g 1099 -d /home/spark -m spark
USER spark

Build-Befehle

Führen Sie die Datei im Dockerfile-Verzeichnis aus.

IMAGE=gcr.io/my-project/my-image:1.0.1

# Download the BigQuery connector.
gsutil cp \
  gs://spark-lib/bigquery/spark-bigquery-with-dependencies_2.12-0.22.2.jar .

# Download the Miniconda3 installer.
wget https://repo.anaconda.com/miniconda/Miniconda3-py39_4.10.3-Linux-x86_64.sh

# Python module example
cat >test_util.py <<EOF
def hello(name):
  print("hello {}".format(name))

def read_lines(path):
  with open(path) as f:
    return f.readlines()
EOF

# Build and push the image.
docker build -t "${IMAGE}" .
docker push "${IMAGE}"