Usar contenedores personalizados con Dataproc sin servidores para Spark

Dataproc sin servidores para Spark ejecuta cargas de trabajo en contenedores de Docker. El contenedor proporciona el entorno de ejecución para los procesos del controlador y del ejecutor de la carga de trabajo. De forma predeterminada, Dataproc sin servidores usa una imagen de contenedor que incluye los paquetes predeterminados Spark, Java, Python y R asociados a una versión de lanzamiento del entorno de ejecución. La API de lotes de Dataproc sin servidores para usar una imagen de contenedor personalizada en lugar de la imagen predeterminada. Por lo general, una imagen de contenedor personalizada agrega dependencias de Spark o Java de la carga de trabajo de Spark que no proporciona la imagen de contenedor predeterminada. Importante: No incluyas Spark en tu imagen de contenedor personalizada; Dataproc Serverless para Spark la activará en el contenedor durante el tiempo de ejecución.

Envía una carga de trabajo por lotes de Spark con una imagen de contenedor personalizada

gcloud

Usa el comando gcloud dataproc batch Submit spark con la marca --container-image para especificar tu imagen de contenedor personalizada cuando envías una carga de trabajo por lotes de Spark.

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

Notas:

  • Imagen personalizada: Especifica la imagen de contenedor personalizada con el siguiente formato de nombre de imagen de Container Registry: {hostname}/{project-id}/{image}:{tag}, por ejemplo, "gcr.io/my-project-id/my-image:1.0.1" Nota: Debes alojar la imagen de contenedor personalizada en Container Registry. Dataproc Serverless no puede recuperar contenedores de otros registros.
  • --jars: Especifica la ruta de acceso a una carga de trabajo de un usuario incluida en la imagen de contenedor personalizada o ubicada en Cloud Storage, por ejemplo, "/opt/spark/jars/spark-examples.jar" o "gs://my-bucket/spark/jars/spark-examples.jar".
  • Otras opciones de comandos de lotes: puedes agregar otras marcas de comandos de lotes opcionales, por ejemplo, para usar un servidor de historial de Spark. Consulta gcloud dataproc batches submit para conocer las marcas de comandos compatibles.
  • Argumentos de carga de trabajo: puedes agregar cualquier argumento de carga de trabajo si agregas "--" al final del comando, seguido de los argumentos de la carga de trabajo.

LÍNEA DE CMD Y REST

La imagen de contenedor personalizada se proporciona a través del campo RuntimeConfig.containerImage como parte de una solicitud a la API de batches.create.

En el siguiente ejemplo, se muestra cómo usar un contenedor personalizado para enviar una carga de trabajo por lotes con la API batches.create de Dataproc sin servidores de Spark.

Antes de usar cualquiera de los datos de solicitud a continuación, realiza los siguientes reemplazos:

  • project-id: Es el ID del proyecto de Google Cloud.
  • region: region
  • custom-container-image: Especifica la imagen de contenedor personalizada con el siguiente formato de nombre de imagen de Container Registry: {hostname}/{project-id}/{image}:{tag}, por ejemplo, "gcr.io/my-project-id/my-image:1.0.1" Nota: Debes alojar tu contenedor personalizado en Container Registry (Dataproc sin servidores no puede recuperar contenedores de otros registros).
  • jar-uri: Especifica la ruta de acceso a un jar de carga de trabajo incluido en la imagen de contenedor personalizada o ubicado en Cloud Storage, por ejemplo: &opt/spark/jars/spark-examples.jar" o &gs/spark/jars/spark-examples.jar.
  • class: el nombre completamente calificado de una clase en el archivo jar, como "org.apache.spark.examples.SparkPi"
  • Otras opciones: Puedes usar otros campos de recursos de cargas de trabajo por lotes, por ejemplo, el campo sparkBatch.args para pasar argumentos a tu carga de trabajo (consulta la documentación de recursos de Batch para obtener más información). Para usar un servidor de historial de Spark, consulta Configura un servidor de historial persistente.

Método HTTP y URL:

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

Cuerpo JSON de la solicitud:

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

Para enviar tu solicitud, expande una de estas opciones:

Deberías recibir una respuesta JSON similar a la que se muestra a continuación:

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

Compilar una imagen de contenedor personalizada

Las imágenes de contenedores personalizadas de Spark sin servidores de Spark son imágenes de Docker. Puedes usar las herramientas para compilar imágenes de Docker a fin de compilar imágenes de contenedor personalizadas. Sin embargo, hay condiciones que las imágenes deben cumplir a fin de ser compatibles con Dataproc sin servidores para Spark. En las siguientes secciones, se explican estas condiciones.

Sistema operativo

Puedes elegir cualquier imagen del sistema operativo como tu imagen de contenedor personalizada. Recomendación: Se prefieren las imágenes predeterminadas de Debian 11 (por ejemplo, debian:11-slim), ya que recibieron pruebas para evitar problemas de compatibilidad.

Utilidades

Debes incluir los siguientes paquetes de utilidades, que son necesarios para ejecutar Spark, en tu imagen de contenedor personalizada:

  • procps
  • tini

Usuario del contenedor

Dataproc Serverless para Spark ejecuta contenedores como el usuario spark de Linux con un UID de 1099 y un GID de 1099. Las directivas USER establecidas en Dockerfiles de imagen de contenedor personalizadas se ignoran en el entorno de ejecución. Usar el UID y el GID para los permisos del sistema de archivos Por ejemplo, si agregas un archivo jar en /opt/spark/jars/my-lib.jar en la imagen como una dependencia de carga de trabajo, debes otorgar permiso al usuario spark para leer el archivo.

Spark

No incluyas Spark en tu imagen de contenedor personalizada. En el entorno de ejecución, Dataproc Serverless para Spark activa los objetos binarios y la configuración de Spark del host en el contenedor: los objetos binarios se activan en el directorio /usr/lib/spark y las configuraciones se activan en el directorio /etc/spark/conf. Dataproc Serverless anula Spark en el directorio durante el tiempo de ejecución.

Java Runtime Environment

No incluyas tu propio entorno de ejecución de Java (JRE) en tu imagen de contenedor personalizada. En el tiempo de ejecución, Dataproc Serverless para Spark activa OpenJDK11 desde el host en el contenedor. Si incluyes un JRE en tu imagen de contenedor personalizada, se ignorará.

Paquetes Java

Puedes incluir archivos jar como dependencias de carga de trabajo de Spark en tu imagen de contenedor personalizada y puedes configurar la variable de entorno SPARK_EXTRA_CLASSPATH para incluir los archivos jar. Dataproc sin servidores para Spark agregará el valor de la variable env en la ruta de clase de los procesos de JVM de Spark. Recomendación: Coloca los archivos jar en el directorio /opt/spark/jars y configura SPARK_EXTRA_CLASSPATH como /opt/spark/jars/*.

Puedes incluir el jar de la carga de trabajo en tu imagen de contenedor personalizada y, luego, hacer referencia a ella con una ruta local cuando envíes la carga de trabajo, por ejemplo file:///opt/spark/jars/my-spark-job.jar (consulta Envía una carga de trabajo por lotes de Spark mediante una imagen de contenedor personalizada para ver un ejemplo).

Paquetes de Python

De forma predeterminada, Dataproc Serverless para Spark activa Conda del host al directorio /opt/dataproc/conda en el contenedor durante el tiempo de ejecución. PYSPARK_PYTHON se configura en /opt/dataproc/conda/bin/python. Su directorio base, /opt/dataproc/conda/bin, se incluye en PATH.

Puedes incluir tu entorno de Python con paquetes en un directorio diferente en tu imagen de contenedor personalizada, por ejemplo, en /opt/conda, y establecer la variable de entorno PYSPARK_PYTHON en /opt/conda/bin/python.

Tu imagen de contenedor personalizada puede incluir otros módulos de Python que no forman parte del entorno de Python, por ejemplo, secuencias de comandos de Python con funciones de utilidad. Configura la variable de entorno PYTHONPATH para incluir los directorios donde se encuentran los módulos.

Entorno de R

Puedes personalizar el entorno de R en tu imagen de contenedor personalizada con una de las siguientes opciones: - Usa Conda para administrar y, luego, instalar paquetes de R desde el canal conda-forge. - Agrega un repositorio de R para tu imagen de contenedor del SO Linux. Luego, instala paquetes de R mediante el administrador de paquetes del SO Linux (consulta el Índice de paquete de software de R).

Cuando usas cualquiera de las opciones, debes configurar la variable de entorno R_HOME para que apunte a tu entorno personalizado de R. Excepción: Si usas Conda para administrar tu entorno de R y personalizar tu entorno de Python, no necesitas configurar la variable de entorno R_HOME, ya que se configura automáticamente en función de la variable de entorno PYSPARK_PYTHON.

Ejemplo de compilación de imagen de contenedor personalizada

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

# (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

# (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

Comandos de compilación

Ejecuta en el directorio de Dockerfile.

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