Usar contêineres personalizados com o Dataproc Serverless para Spark

O Dataproc Serverless for Spark executa cargas de trabalho nos contêineres do Docker. O contêiner fornece o ambiente de execução para os processos de driver e executor dos cargas de trabalho. Por padrão, o Dataproc sem servidor para o Spark usa uma imagem de contêiner que inclui os pacotes Spark, Java, Python e R associados a uma versão de lançamento de ambiente de execução. A API sem servidor do servidor em lote do Dataproc permite usar uma imagem de contêiner personalizada em vez da imagem padrão. Normalmente, uma imagem de contêiner personalizada adiciona dependências Java ou Python da carga de trabalho do Spark não fornecidas pela imagem de contêiner padrão. Importante: não inclua o Spark na imagem do contêiner personalizado. O Dataproc sem servidor para o Spark monta o Spark no contêiner no ambiente de execução.

Enviar uma carga de trabalho em lote do Spark usando uma imagem de contêiner personalizada

gcloud

Use o comando gcloud dataproc lotes send spark com a sinalização --container-image para especificar a imagem do contêiner personalizada ao enviar uma carga de trabalho em lote do 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

Observações:

  • Imagem personalizada: especifique a imagem do contêiner personalizada usando o seguinte formato de nomenclatura de imagem do Container Registry: {hostname}/{project-id}/{image}:{tag}. Por exemplo: "gcr.io/my-project-id/my-image:1.0.1". Observação: você precisa hospedar sua imagem de contêiner personalizada no Container Registry. O Dataproc sem servidor não pode buscar contêineres de outros registros.
  • --jars: especifique um caminho para uma carga de trabalho do usuário incluída na imagem do contêiner personalizada ou no Cloud Storage, por exemplo, "/opt/spark/jars/spark-examples.jar" ou "gs://my-bucket/spark/jars/spark-examples.jar".
  • Outras opções de comando em lotes: é possível adicionar outras sinalizações de comando opcionais de lotes, por exemplo, para usar um servidor de histórico do Spark. Consulte gcloud dataproc batches submit para ver as sinalizações de comando compatíveis.
  • argumentos de carga de trabalho É possível adicionar argumentos de carga de trabalho adicionando ""--" ao final do comando, seguido pelos argumentos da carga de trabalho.

REST e linha de comando

A imagem de contêiner personalizada é fornecida pelo campo RuntimeConfig.containerImage como parte de uma solicitação de API batches.create.

Veja no exemplo a seguir como usar um contêiner personalizado para enviar uma carga de trabalho em lote usando a API Dataproc batches.create sem servidor para o Dataproc.

Antes de usar qualquer um dos dados da solicitação, faça as seguintes substituições:

  • project-id: ID do projeto do Google Cloud
  • region: region
  • custom-container-image: especifique a imagem do contêiner personalizada usando o seguinte formato de nomenclatura de imagem do Container Registry: {hostname}/{project-id}/{image}:{tag}, por exemplo, "gcr.io/my-project-id/my-image:1.0.1". Observação: é preciso hospedar seu contêiner personalizado no Container Registry. O Dataproc sem servidor não pode buscar contêineres de outros registros.
  • jar-uri: especifique um caminho para um jar de carga de trabalho incluído na imagem do contêiner personalizada ou localizado no Cloud Storage, por exemplo, "quoquo;/opt/spark/jars/spark-examples.jar" ou "gs:///spark/jars/spark-examples.jar"
  • class: o nome totalmente qualificado de uma classe no arquivo jar, como "org.apache.spark.examples.SparkPi".
  • Outras opções: é possível usar outros campos de recursos de carga de trabalho em lote, por exemplo, o campo sparkBatch.args para transmitir argumentos para a carga de trabalho. Consulte a documentação do recurso Batch para mais informações. Para usar um servidor de histórico do Spark, consulte Como configurar um servidor de histórico permanente.

Método HTTP e URL:

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

Corpo JSON da solicitação:

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

Para enviar a solicitação, expanda uma destas opções:

Você receberá uma resposta JSON semelhante a esta:

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

Criar uma imagem de contêiner personalizada

As imagens de contêiner personalizadas do Dataproc sem servidor para o Spark são imagens do Docker. É possível usar as ferramentas para criar imagens do Docker a fim de criar imagens de contêiner personalizadas, mas há condições que as imagens precisam atender para serem compatíveis com o Dataproc Serverless for Spark. As seções a seguir explicam essas condições.

Sistema operacional

Você pode escolher qualquer imagem do sistema operacional como a imagem personalizada do contêiner. Recomendação: as imagens padrão do Debian 11 são preferenciais (por exemplo, debian:11-slim), porque receberam testes para evitar problemas de compatibilidade.

Utilitários

Você precisa incluir os seguintes pacotes de utilitários, necessários para executar o Spark na imagem de contêiner personalizada:

  • procps
  • tini

Usuário de contêiner

O Dataproc Serverless for Spark executa contêineres como o usuário spark do Linux com um UID 1099 e um GID 1099. As diretivas USER definidas em Dockerfiles de imagens de contêiner personalizadas são ignoradas no ambiente de execução. Usar o UID e o GID para permissões de sistema de arquivos Por exemplo, se você adicionar um arquivo jar em /opt/spark/jars/my-lib.jar à imagem como uma dependência de carga de trabalho, precisará conceder ao usuário spark permissão de leitura no arquivo.

Spark

Não inclua o Spark na imagem do contêiner personalizado. No ambiente de execução, o Dataproc sem servidor para o Spark monta os binários e as configurações do Spark do host no contêiner: os binários são montados no diretório /usr/lib/spark e os ajustes são montados no diretório /etc/spark/conf. Os arquivos atuais nesses diretórios são modificados pelo Dataproc sem servidor para o Spark no momento da execução.

Java Runtime Environment

Não inclua seu próprio Java Runtime Environment (JRE) na imagem do contêiner personalizado. No ambiente de execução, o Dataproc sem servidor para o Spark monta OpenJDK11 do host no contêiner. Se você incluir um JRE na sua imagem personalizada de contêiner, ele será ignorado.

Pacotes Java

É possível incluir arquivos jar como dependências de carga de trabalho do Spark na imagem do contêiner personalizado e definir a variável de ambiente SPARK_EXTRA_CLASSPATH para incluir os jars. O Dataproc sem servidor para o Spark adicionará o valor da variável env no caminho de classe dos processos da JVM do Spark. Recomendação: coloque jars no diretório /opt/spark/jars e defina SPARK_EXTRA_CLASSPATH como /opt/spark/jars/*.

É possível incluir o jar da carga de trabalho na imagem de contêiner personalizada e referenciá-la com um caminho local ao enviá-la, por exemplo, file:///opt/spark/jars/my-spark-job.jar. Consulte Enviar uma carga de trabalho em lote do Spark usando uma imagem de contêiner personalizada.

Pacotes do Python

Por padrão, o Dataproc Serverless for Spark monta o Conda do host para o diretório /opt/dataproc/conda no contêiner no momento da execução. PYSPARK_PYTHON está definido como /opt/dataproc/conda/bin/python. O diretório base, /opt/dataproc/conda/bin, está incluído em PATH.

É possível incluir o ambiente Python com pacotes em um diretório diferente na imagem do contêiner personalizado, por exemplo, em /opt/conda e definir a variável de ambiente PYSPARK_PYTHON como /opt/conda/bin/python.

A imagem do contêiner personalizada pode incluir outros módulos Python que não fazem parte do ambiente Python, por exemplo, scripts Python com funções utilitárias. Defina a variável de ambiente PYTHONPATH para incluir os diretórios em que os módulos estão localizados.

Ambiente R

Você pode personalizar o ambiente R na imagem do contêiner personalizado usando uma das seguintes opções: - Usar o Conda para gerenciar e instalar pacotes R do canal conda-forge - Adicionar um repositório R para a imagem de contêiner Linux e instalar pacotes R por meio do gerenciador de pacotes Linux (consulte o Índice de pacotes R Software)

Ao usar uma dessas opções, defina a variável de ambiente R_HOME para apontar para o ambiente R personalizado. Exceção: se você estiver usando o Conda para gerenciar o ambiente R e personalizar o ambiente Python, não será necessário definir a variável de ambiente R_HOME. Ela é definida automaticamente com base na variável de ambiente PYSPARK_PYTHON.

Exemplo de build de imagem de contêiner personalizado

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 versão

Execute no diretório do 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}"