使用 Docker on YARN 自定义 Spark 作业运行时环境

借助 Dataproc 的 Docker on YARN 功能,您可以创建和使用 Docker 映像来自定义 Spark 作业运行时环境。该映像可以包含对 Java、Python 和 R 依赖项以及作业 jar 的自定义内容。

限制

以下设备不支持使用此功能:

  • 低于 2.0.49 的 Dataproc 映像版本(1.5 映像中不提供)
  • MapReduce 作业(仅适用于 Spark 作业)
  • Spark 客户端模式(仅在 Spark 集群模式下受支持)
  • Kerberos 集群:如果您在启用 Kerberos 的情况下使用 Docker on YARN 创建集群,集群创建将会失败。
  • JDK、Hadoop 和 Spark 的自定义:系统会使用主机 JDK、Hadoop 和 Spark,而不是您的自定义内容。

创建 Docker 映像

自定义 Spark 环境的第一步是构建 Docker 映像

Dockerfile

您可以将以下 Dockerfile 用作示例,根据需要进行更改和添加。

FROM debian:10-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 *.jar "${SPARK_EXTRA_JARS_DIR}"

# Optional: Install and configure Miniconda3.
ENV CONDA_HOME=/opt/miniconda3
ENV PYSPARK_PYTHON=${CONDA_HOME}/bin/python
ENV PYSPARK_DRIVER_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}"

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

构建并推送映像

以下是用于构建和推送示例 Docker 映像的命令,您可以根据自己的自定义进行更改。

# Increase the version number when there is a change to avoid referencing
# a cached older image. Avoid reusing the version number, including the default
# `latest` version.
IMAGE=gcr.io/my-project/my-image:1.0.1

# Download the BigQuery connector.
gcloud storage 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}"

创建 Dataproc 集群

创建用于自定义 Spark 环境的 Docker 映像后,创建一个 Dataproc 集群,该集群将在运行 Spark 作业时使用您的 Docker 映像。

gcloud

gcloud dataproc clusters create CLUSTER_NAME \
    --region=REGION \
    --image-version=DP_IMAGE \
    --optional-components=DOCKER \
    --properties=dataproc:yarn.docker.enable=true,dataproc:yarn.docker.image=DOCKER_IMAGE \
    other flags

替换以下内容:

  • CLUSTER_NAME:集群名称。
  • REGION:集群区域。
  • DP_IMAGE:Dataproc 映像版本必须为 2.0.49 或更高版本(--image-version=2.0 将使用高于 2.0.49 的合格次要版本)。
  • --optional-components=DOCKER:在集群上启用 Docker 组件
  • --properties 标志:
    • dataproc:yarn.docker.enable=true:启用 Dataproc Docker on YARN 功能所需的属性。
    • dataproc:yarn.docker.image:可选属性,您可以添加该属性以使用以下 Container Registry 映像命名格式指定 DOCKER_IMAGE{hostname}/{project-id}/{image}:{tag}

      示例:

      dataproc:yarn.docker.image=gcr.io/project-id/image:1.0.1
      

      要求:您必须在 Container RegistryArtifact Registry 上托管 Docker 映像。(Dataproc 无法从其他注册表中提取容器)。

      建议:在创建集群时添加此属性,以缓存 Docker 映像,并避免日后在提交使用该映像的作业时出现 YARN 超时。

dataproc:yarn.docker.enable 设置为 true 后,Dataproc 会更新 Hadoop 和 Spark 配置,以便在集群中启用 Docker on YARN 功能。例如,spark.submit.deployMode 设置为 clusterspark.yarn.appMasterEnv.YARN_CONTAINER_RUNTIME_DOCKER_MOUNTSspark.executorEnv.YARN_CONTAINER_RUNTIME_DOCKER_MOUNTS 设置为将主机中的目录装载到容器中。

将 Spark 作业提交到集群

创建 Dataproc 集群后,将 Spark 作业提交到使用您的 Docker 映像的集群。本部分的示例会将 PySpark 作业提交到集群。

设置作业属性:

# Set the Docker image URI.
IMAGE=(e.g., gcr.io/my-project/my-image:1.0.1)

# Required: Use `#` as the delimiter for properties to avoid conflicts.
JOB_PROPERTIES='^#^'

# Required: Set Spark properties with the Docker image.
JOB_PROPERTIES="${JOB_PROPERTIES}#spark.yarn.appMasterEnv.YARN_CONTAINER_RUNTIME_DOCKER_IMAGE=${IMAGE}"
JOB_PROPERTIES="${JOB_PROPERTIES}#spark.executorEnv.YARN_CONTAINER_RUNTIME_DOCKER_IMAGE=${IMAGE}"

# Optional: Add custom jars to Spark classpath. Don't set these properties if
# there are no customizations.
JOB_PROPERTIES="${JOB_PROPERTIES}#spark.driver.extraClassPath=/opt/spark/jars/*"
JOB_PROPERTIES="${JOB_PROPERTIES}#spark.executor.extraClassPath=/opt/spark/jars/*"

# Optional: Set custom PySpark Python path only if there are customizations.
JOB_PROPERTIES="${JOB_PROPERTIES}#spark.pyspark.python=/opt/miniconda3/bin/python"
JOB_PROPERTIES="${JOB_PROPERTIES}#spark.pyspark.driver.python=/opt/miniconda3/bin/python"

# Optional: Set custom Python module path only if there are customizations.
# Since the `PYTHONPATH` environment variable defined in the Dockerfile is
# overridden by Spark, it must be set as a job property.
JOB_PROPERTIES="${JOB_PROPERTIES}#spark.yarn.appMasterEnv.PYTHONPATH=/opt/python/packages"
JOB_PROPERTIES="${JOB_PROPERTIES}#spark.executorEnv.PYTHONPATH=/opt/python/packages"

注意:

gcloud

将作业提交到集群。

gcloud dataproc jobs submit pyspark PYFILE \
    --cluster=CLUSTER_NAME \
    --region=REGION \
    --properties=${JOB_PROPERTIES}

替换以下内容:

  • PYFILE:PySpark 作业文件的文件路径。该路径可以是本地文件路径,也可以是 Cloud Storage 中文件的 URI (gs://BUCKET_NAME/PySpark filename)。
  • CLUSTER_NAME:集群名称。
  • REGION:集群区域。