为 Dataflow 构建自定义容器映像

本文档介绍如何为 Dataflow 作业创建自定义容器映像。

要求

Dataflow 的自定义容器映像必须满足以下要求:

  • 已安装 Apache Beam SDK 和必要的依赖项。 我们建议从默认的 Apache Beam SDK 映像开始。如需了解详情,请参阅本文档中的选择基础映像
  • /opt/apache/beam/boot 脚本必须作为容器启动期间的最后一步运行。此脚本会初始化工作器环境并启动 SDK 工作器进程。此脚本是 Apache Beam SDK 映像中的默认 ENTRYPOINT。但是,如果您使用其他基础映像,或者替换了默认 ENTRYPOINT,则必须显式运行此脚本。如需了解详情,请参阅本文档中的修改容器入口点
  • 您的容器映像必须支持 Dataflow 作业的工作器虚拟机架构。如果您打算使用 ARM 虚拟机上的自定义容器,我们建议您构建多架构映像。如需了解详情,请参阅构建多架构容器映像

准备工作

  1. 验证安装的 Apache Beam SDK 版本是否支持 Runner v2 和您的语言版本。 如需了解详情,请参阅安装 Apache Beam SDK

  2. 如需在本地测试容器映像,您必须安装 Docker。如需了解详情,请参阅获取 Docker

  3. 创建 Artifact Registry 代码库指定 Docker 映像格式。您必须至少具有代码库的 Artifact Registry Writer 访问权限

    如需创建新的代码库,请运行 gcloud artifacts repositories create 命令

    gcloud artifacts repositories create REPOSITORY \
      --repository-format=docker \
      --location=REGION \
      --async
    

    替换以下内容:

    • REPOSITORY:代码库的名称。代码库名称对于项目中的每个位置都必须是唯一的。
    • REGION:要在其中部署 Dataflow 作业的区域。选择靠近您运行命令的位置的 Dataflow 区域。该值必须是有效的区域名称。如需详细了解区域和位置,请参阅 Dataflow 位置

    本示例使用 --async 标志。该命令会立即返回,而不等待操作完成。

  4. 如需配置 Docker 以对 Artifact Registry 的请求进行身份验证,请运行 gcloud auth configure-docker 命令

    gcloud auth configure-docker REGION-docker.pkg.dev
    

    该命令将更新您的 Docker 配置。现在,您可以在 Google Cloud 项目中与 Artifact Registry 连接以推送映像。

选择基础映像

我们建议从使用 Apache Beam SDK 映像作为基础容器映像开始。这些映像作为 Apache Beam 版本的一部分发布到 Docker Hub

使用 Apache Beam 基础映像

如需使用 Apache Beam SDK 映像作为基础映像,请在 FROM 指令中指定容器映像,然后添加您自己的自定义项。

Java

此示例将 Java 8 与 Apache Beam SDK 2.61.0 版搭配使用。

FROM apache/beam_java8_sdk:2.61.0

# Make your customizations here, for example:
ENV FOO=/bar
COPY path/to/myfile ./

自定义容器的运行时版本必须与您用于启动流水线的运行时一致。例如,如果您要从本地 Java 11 环境启动流水线,FROM 行必须指定 Java 11 环境:apache/beam_java11_sdk:...

Python

此示例将 Python 3.10 与 Apache Beam SDK 2.61.0 版搭配使用。

FROM apache/beam_python3.10_sdk:2.61.0

# Make your customizations here, for example:
ENV FOO=/bar
COPY path/to/myfile ./

自定义容器的运行时版本必须与您用于启动流水线的运行时一致。例如,如果您要从本地 Python 3.10 环境启动流水线,FROM 行必须指定 Python 3.10 环境:apache/beam_python3.10_sdk:...

Go

此示例将 Go 与 Apache Beam SDK 2.61.0 版搭配使用。

FROM apache/beam_go_sdk:2.61.0

# Make your customizations here, for example:
ENV FOO=/bar
COPY path/to/myfile ./

使用自定义基础映像

如果要使用其他基础映像,或者需要修改默认 Apache Beam 映像的某些方面(例如操作系统版本或补丁),请使用多阶段构建流程。从默认的 Apache Beam 基础映像中复制必要的工件。

设置 ENTRYPOINT 以运行 /opt/apache/beam/boot 脚本,该脚本将初始化工作器环境并启动 SDK 工作器进程。如果未设置此入口点,Dataflow 工作器将无法正确启动。

以下示例展示了从 Apache Beam SDK 复制文件的 Dockerfile:

Java

FROM openjdk:8

# Copy files from official SDK image, including script/dependencies.
COPY --from=apache/beam_java8_sdk:2.61.0 /opt/apache/beam /opt/apache/beam

# Set the entrypoint to Apache Beam SDK launcher.
ENTRYPOINT ["/opt/apache/beam/boot"]

Python

FROM python:3.10-slim

# Install SDK.
RUN pip install --no-cache-dir apache-beam[gcp]==2.61.0

# Verify that the image does not have conflicting dependencies.
RUN pip check

# Copy files from official SDK image, including script/dependencies.
COPY --from=apache/beam_python3.10_sdk:2.61.0 /opt/apache/beam /opt/apache/beam

# Set the entrypoint to Apache Beam SDK launcher.
ENTRYPOINT ["/opt/apache/beam/boot"]

此示例假定现有基础映像上安装了必要的依赖项(在本例中为 Python 3.10 和 pip)。在映像中安装 Apache Beam SDK 可确保映像具有必要的 SDK 依赖项,并缩短工作器启动时间。

重要提示RUNCOPY 指令中指定的 SDK 版本必须与用于启动流水线的版本一致。

Go

FROM golang:latest

# Copy files from official SDK image, including script/dependencies.
COPY --from=apache/beam_go_sdk:2.61.0 /opt/apache/beam /opt/apache/beam

# Set the entrypoint to Apache Beam SDK launcher.
ENTRYPOINT ["/opt/apache/beam/boot"]

修改容器入口点

如果容器在容器启动期间运行自定义脚本,则该脚本必须以 /opt/apache/beam/boot 结束。Dataflow 在容器启动期间传递的参数必须传递给默认启动脚本。以下示例展示了调用默认启动脚本的自定义启动脚本:

#!/bin/bash

echo "This is my custom script"
# ...

# Pass command arguments to the default boot script.
/opt/apache/beam/boot "$@"

在 Dockerfile 中,设置 ENTRYPOINT 以调用脚本:

Java

FROM apache/beam_java8_sdk:2.61.0

COPY script.sh path/to/my/script.sh
ENTRYPOINT [ "path/to/my/script.sh" ]

Python

FROM apache/beam_python3.10_sdk:2.61.0

COPY script.sh path/to/my/script.sh
ENTRYPOINT [ "path/to/my/script.sh" ]

Go

FROM apache/beam_go_sdk:2.61.0

COPY script.sh path/to/my/script.sh
ENTRYPOINT [ "path/to/my/script.sh" ]

构建并推送映像

您可以使用 Cloud Build 或 Docker 构建容器映像并将其推送到 Artifact Registry 代码库。

Cloud Build

如需构建文件并将其推送到 Artifact Registry 代码库,请运行 gcloud builds submit 命令

  gcloud builds submit --tag REGION-docker.pkg.dev/PROJECT_ID/REPOSITORY/dataflow/FILE_NAME:TAG .

Docker

docker build . --tag REGION-docker.pkg.dev/PROJECT_ID/REPOSITORY/dataflow/FILE_NAME:TAG
docker push REGION-docker.pkg.dev/PROJECT_ID/REPOSITORY/dataflow/FILE_NAME:TAG

替换以下内容:

  • REGION:要在其中部署 Dataflow 作业的区域REGION 变量的值必须是有效的区域名称。
  • PROJECT_ID:项目名称或用户名。
  • REPOSITORY:映像代码库名称。
  • FILE_NAME:您的 Dockerfile 的名称。
  • TAG:映像标记。 始终指定有版本控制的容器 SHA 或标记。请勿使用 :latest 标记或可变标记。

预安装 Python 依赖项

本部分适用于 Python 流水线。

启动 Python Dataflow 作业时,您可以在运行时使用 --requirements_file--extra_packages 选项指定其他依赖项。如需了解详情,请参阅管理 Python 流水线依赖项。每个 Dataflow 工作器容器中会安装额外的依赖项。当作业首次启动以及在自动扩缩期间,依赖项安装通常会导致 CPU 使用率高,并且所有新启动的 Dataflow 工作器的预热期较长。

为避免重复的依赖项安装,您可以预构建自定义 Python SDK 容器映像,并预安装依赖项。您可以在构建时使用 Dockerfile 执行此步骤,或者在提交作业时执行此步骤。

工作器在启动容器时会创建新的虚拟 Python 环境。因此,请将依赖项安装到默认(全局)Python 环境中,而不是创建虚拟环境。如果您在容器映像中激活虚拟环境,则在作业启动时可能不会激活此环境。如需了解详情,请参阅常见问题

使用 Dockerfile 进行预安装

如需向 Python 自定义容器直接添加额外的依赖项,请使用以下命令:

FROM apache/beam_python3.10_sdk:2.61.0

COPY requirements.txt .

# Pre-install Python dependencies. For reproducibile builds,
# supply all of the dependencies and their versions in a requirements.txt file.
RUN pip install -r requirements.txt

# You can also install individual dependencies.
RUN pip install lxml
# Pre-install other dependencies.
RUN apt-get update \
  && apt-get dist-upgrade \
  && apt-get install -y --no-install-recommends ffmpeg

使用 --sdk_container_image--sdk_location 流水线选项提交您的作业。--sdk_location 选项会阻止 SDK 在作业启动时下载。系统会直接从容器映像检索 SDK。

以下示例运行 wordcount 示例流水线

python -m apache_beam.examples.wordcount \
  --input=INPUT_FILE \
  --output=OUTPUT_FILE \
  --project=PROJECT_ID \
  --region=REGION \
  --temp_location=TEMP_LOCATION \
  --runner=DataflowRunner \
  --experiments=use_runner_v2 \
  --sdk_container_image=IMAGE_URI
  --sdk_location=container

替换以下内容:

  • INPUT_FILE:流水线的输入文件
  • OUTPUT_FILE:要写入输出的路径
  • PROJECT_ID:Google Cloud 项目 ID
  • REGION:要在其中部署 Dataflow 作业的区域
  • TEMP_LOCATION:供 Dataflow 存储临时作业文件的 Cloud Storage 路径
  • IMAGE_URI:自定义容器映像 URI

提交作业时预构建容器映像

通过预构建容器映像,您可以在作业启动之前预安装流水线依赖项。您无需构建自定义容器映像。

如需在提交作业时预构建具有其他 Python 依赖项的容器,请使用以下流水线选项:

  • --prebuild_sdk_container_engine=[cloud_build | local_docker]。设置此标志后,Apache Beam 会生成自定义容器并安装通过 --requirements_file--extra_packages 选项指定的所有依赖项。此标志支持以下值:

    • cloud_build。使用 Cloud Build 构建容器。您必须在项目中启用 Cloud Build API。
    • local_docker。使用本地 Docker 安装来构建容器。
  • --docker_registry_push_url=IMAGE_PATH。将 IMAGE_PATH 替换为 Artifact Registry 文件夹。

  • --sdk_location=container。此选项可防止工作器在作业启动时下载 SDK。系统会改为直接从容器映像检索 SDK。

以下示例使用 Cloud Build 预构建映像:

python -m apache_beam.examples.wordcount \
  --input=INPUT_FILE \
  --output=OUTPUT_FILE \
  --project=PROJECT_ID \
  --region=REGION \
  --temp_location=TEMP_LOCATION \
  --runner=DataflowRunner \
  --disk_size_gb=DISK_SIZE_GB \
  --experiments=use_runner_v2 \
  --requirements_file=./requirements.txt \
  --prebuild_sdk_container_engine=cloud_build \
  --docker_registry_push_url=IMAGE_PATH \
  --sdk_location=container

此预构建功能需要使用 Python 版 Apache Beam SDK 2.25.0 或更高版本。

SDK 容器映像预构建工作流使用通过 --sdk_container_image 流水线选项传递的映像作为基础映像。如果未设置此选项,则系统默认会将 Apache Beam 映像用作基础映像。

您可以在具有相同依赖项和 SDK 版本的另一项作业中重复使用预先构建的 Python SDK 容器映像。如需重复使用该映像,请使用 --sdk_container_image 流水线选项将预构建的容器映像网址传递给其他作业。移除依赖项选项 --requirements_file--extra_packages--setup_file

如果您不打算重复使用该映像,请在作业完成后将其删除。您可以使用 gcloud CLI 或在 Google Cloud 控制台中的 Artifact Registry 页面删除映像。

如果映像存储在 Artifact Registry 中,请使用 artifacts docker images delete 命令:

   gcloud artifacts docker images delete IMAGE --delete-tags

常见问题

  • 如果您的作业具有来自私有 PyPi 镜像的额外 Python 依赖项,并且无法由远程 Cloud Build 作业拉取,请尝试使用本地 Docker 选项,或尝试使用 Dockerfile 构建容器。

  • 如果 Cloud Build 作业失败并显示 docker exit code 137,则说明构建作业内存不足,可能是由于安装的依赖项的大小所致。通过传递 --cloud_build_machine_type=machine_type 使用更大的 Cloud Build 工作器机器类型,其中 machine_type 是以下选项之一:

    • n1-highcpu-8
    • n1-highcpu-32
    • e2-highcpu-8
    • e2-highcpu-32

    默认情况下,Cloud Build 使用机器类型 e2-medium

  • 在 Apache Beam 2.44.0 及更高版本中,工作器在启动自定义容器时会创建虚拟环境。如果容器创建自己的虚拟环境来安装依赖项,则这些依赖项会被舍弃。此行为可能会导致错误,例如:

    ModuleNotFoundError: No module named '<dependency name>'

    为避免此问题,请将依赖项安装到默认(全局)Python 环境中。如需解决此问题,请在容器映像中设置以下环境变量,以在 Beam 2.48.0 及更高版本中停用此行为:

    ENV RUN_PYTHON_SDK_IN_DEFAULT_ENVIRONMENT=1

后续步骤