Benutzerdefinierte Container-Images für Dataflow erstellen

In diesem Dokument wird beschrieben, wie Sie ein benutzerdefiniertes Container-Image für Dataflow-Jobs erstellen.

Voraussetzungen

Ein benutzerdefiniertes Container-Image für Dataflow muss die folgenden Anforderungen erfüllen:

  • Das Apache Beam SDK und die erforderlichen Abhängigkeiten sind installiert Wir empfehlen, mit einem Standard-Image des Apache Beam SDK zu beginnen. Weitere Informationen finden Sie in diesem Dokument unter Basis-Image auswählen.
  • Das Skript /opt/apache/beam/boot muss beim Start des Containers als letzter Schritt ausgeführt werden. Dieses Skript initialisiert die Worker-Umgebung und startet den SDK-Worker-Prozess. Dieses Skript ist der Standard-ENTRYPOINT in den Apache Beam SDK-Images. Wenn Sie jedoch ein anderes Basis-Image verwenden oder den Standardwert ENTRYPOINT überschreiben, müssen Sie das Skript explizit ausführen. Weitere Informationen finden Sie in diesem Dokument unter Container-Einstiegspunkt ändern.
  • Ihr Container-Image muss die Architektur der Worker-VMs für Ihren Dataflow-Job unterstützen. Wenn Sie den benutzerdefinierten Container auf ARM-VMs verwenden möchten, empfehlen wir, ein Image mit mehreren Architekturen zu erstellen. Weitere Informationen finden Sie unter Container-Image mit mehreren Architekturen erstellen.

Vorbereitung

  1. Prüfen Sie, ob die installierte Version des Apache Beam SDK Runner v2 und Ihre Sprachversion unterstützt. Weitere Informationen finden Sie unter Apache Beam SDK installieren.

  2. Wenn Sie Ihr Container-Image lokal testen möchten, muss Docker installiert sein. Weitere Informationen finden Sie unter Docker herunterladen.

  3. Artifact Registry-Repository erstellen Geben Sie das Docker-Image-Format an. Sie müssen für das Repository mindestens Zugriff als Artifact Registry-Autor haben.

    Führen Sie den gcloud artifacts repositories create-Befehl aus, um ein neues Repository zu erstellen:

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

    Ersetzen Sie dabei Folgendes:

    • REPOSITORY ist ein Name für Ihr Repository. Repository-Namen müssen für jeden Repository-Speicherort in einem Projekt einmalig sein.
    • REGION ist die Region, in der der Dataflow-Job bereitgestellt wird. Wählen Sie eine Dataflow-Region in der Nähe des Standorts, an dem die Befehle ausgeführt werden. Der Wert muss ein gültiger Regionsname sein. Weitere Informationen zu Regionen und Standorten finden Sie unter Dataflow-Standorte.

    In diesem Beispiel wird das Flag --async verwendet. Der Befehl wird sofort zurückgegeben, ohne auf den Abschluss des Vorgangs zu warten.

  4. Führen Sie den Befehl gcloud auth configure-docker aus, um Docker für die Authentifizierung von Anfragen für Artifact Registry zu konfigurieren:

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

    Mit dem Befehl wird die Docker-Konfiguration aktualisiert. Sie können jetzt eine Verbindung zu Artifact Registry in Ihrem Google Cloud-Projekt herstellen, um Images per Push zu übertragen.

Basis-Image auswählen

Wir empfehlen, mit einem Apache Beam SDK-Image als Basis-Container-Image zu beginnen. Standard-Images werden im Rahmen von Apache Beam-Releases in DockerHub veröffentlicht.

Apache Beam-Basis-Image verwenden

Wenn Sie ein Apache Beam SDK-Image als Basis-Image verwenden möchten, geben Sie das Container-Image in der Anweisung FROM an und fügen Sie dann eigene Anpassungen hinzu.

Java

In diesem Beispiel wird Java 8 mit der Apache Beam SDK-Version 2.61.0 verwendet.

FROM apache/beam_java8_sdk:2.61.0

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

Die Laufzeitversion des benutzerdefinierten Containers muss mit der Laufzeit übereinstimmen, die Sie zum Starten der Pipeline verwenden. Wenn Sie beispielsweise die Pipeline aus einer lokalen Java 11-Umgebung starten, muss in der Zeile FROM eine Java 11-Umgebung angegeben sein: apache/beam_java11_sdk:....

Python

In diesem Beispiel wird Python 3.10 mit der Apache Beam SDK-Version 2.61.0 verwendet.

FROM apache/beam_python3.10_sdk:2.61.0

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

Die Laufzeitversion des benutzerdefinierten Containers muss mit der Laufzeit übereinstimmen, die Sie zum Starten der Pipeline verwenden. Wenn Sie beispielsweise die Pipeline aus einer lokalen Python 3.10-Umgebung starten, muss in der Zeile FROM eine Python 3.10-Umgebung angegeben sein: apache/beam_python3.10_sdk:....

Go

In diesem Beispiel wird Go mit der Apache Beam SDK-Version 2.61.0 verwendet.

FROM apache/beam_go_sdk:2.61.0

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

Benutzerdefiniertes Basis-Image verwenden

Wenn Sie ein anderes Basis-Image verwenden oder Aspekte der Standard-Apache Beam-Images (z. B. Betriebssystemversion oder Patches) ändern möchten, verwenden Sie einen mehrstufigen Build-Prozess. Kopieren Sie die erforderlichen Artefakte aus einem Apache Beam-Standard-Image.

Legen Sie ENTRYPOINT so fest, dass das Skript /opt/apache/beam/boot ausgeführt wird, das die Worker-Umgebung initialisiert und den SDK-Worker-Prozess startet. Wenn Sie diesen Einstiegspunkt nicht festlegen, werden die Dataflow-Worker nicht ordnungsgemäß gestartet.

Das folgende Beispiel zeigt ein Dockerfile, das Dateien aus dem Apache Beam SDK kopiert:

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

In diesem Beispiel wird davon ausgegangen, dass die erforderlichen Abhängigkeiten (in diesem Fall Python 3.10 und pip) auf dem vorhandenen Basis-Image installiert wurden. Durch die Installation des Apache Beam SDK in dem Image wird sichergestellt, dass das Image die erforderlichen SDK-Abhängigkeiten hat und die Startzeit des Workers verkürzt wird.

Wichtig: Die in den Anleitungen RUN und COPY angegebene SDK-Version muss der Version entsprechen, die zum Starten der Pipeline verwendet wird.

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

Containereinstiegspunkt ändern

Wenn Ihr Container beim Containerstart ein benutzerdefiniertes Skript ausführt, muss das Skript mit der Ausführung von /opt/apache/beam/boot enden. Argumente, die von Dataflow beim Start des Containers übergeben werden, müssen an das Standardstartskript übergeben werden. Das folgende Beispiel zeigt ein benutzerdefiniertes Startskript, das das Standard-Bootskript aufruft:

#!/bin/bash

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

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

Legen Sie im Dockerfile ENTRYPOINT für den Aufruf des Skripts fest:

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

Erstellen Sie das Image und übertragen Sie es per Push

Sie können Cloud Build oder Docker verwenden, um Ihr Container-Image zu erstellen und in ein Artifact Registry-Repository zu übertragen.

Cloud Build

Führen Sie den Befehl gcloud builds submit aus, um die Datei zu erstellen und in Ihr Artifact Registry-Repository zu übertragen:

  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

Ersetzen Sie dabei Folgendes:

  • REGION ist die Region, in der Sie Ihren Dataflow-Job bereitstellen möchten. Der Wert der Variablen REGION muss ein gültiger Regionsname sein.
  • PROJECT_ID: der Projekt- oder Nutzername.
  • REPOSITORY: der Name des Image-Repository.
  • FILE_NAME ist der Name des Dockerfile.
  • TAG: das Image-Tag. Geben Sie immer ein versioniertes Container-SHA oder -Tag an. Verwende weder das Tag :latest noch ein änderbares Tag.

Python-Abhängigkeiten vorinstallieren

Dieser Abschnitt gilt für Python-Pipelines.

Wenn Sie einen Python Dataflow-Job starten, können Sie zusätzliche Abhängigkeiten mit der Option --requirements_file oder --extra_packages zur Laufzeit angeben. Weitere Informationen finden Sie unter Python-Pipelineabhängigkeiten verwalten. In jedem Dataflow-Worker-Container werden zusätzliche Abhängigkeiten installiert. Wenn der Job zum ersten Mal gestartet und während des Autoscalings ausgeführt wird, führt die Abhängigkeitsinstallation häufig zu einer hohen CPU-Auslastung und einer langen Aufwärmzeit für alle neu gestarteten Dataflow-Worker.

Um sich wiederholende Abhängigkeitsinstallationen zu vermeiden, können Sie das benutzerdefinierte Python SDK-Container-Image mit den vorinstallierten Abhängigkeiten vorfertigen. Sie können diesen Schritt bei der Erstellung mit einem Dockerfile oder zur Laufzeit ausführen, wenn Sie den Job senden.

Worker erstellen beim Starten des Containers eine neue virtuelle Python-Umgebung. Installieren Sie aus diesem Grund Abhängigkeiten in der standardmäßigen (globalen) Python-Umgebung, anstatt eine virtuelle Umgebung zu erstellen. Wenn Sie eine virtuelle Umgebung in Ihrem Container-Image aktivieren, wird diese Umgebung beim Start des Jobs möglicherweise nicht aktiviert. Weitere Informationen finden Sie unter Häufige Probleme.

Mit einem Dockerfile vorinstallieren

Verwenden Sie die folgenden Befehle, um dem benutzerdefinierten Python-Container zusätzliche Abhängigkeiten direkt hinzuzufügen:

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

Senden Sie Ihren Job mit den Pipeline-Optionen --sdk_container_image und --sdk_location. Die Option --sdk_location verhindert, dass das SDK beim Starten des Jobs heruntergeladen wird. Das SDK wird direkt aus dem Container-Image abgerufen.

Im folgenden Beispiel wird die wordcount-Beispielpipeline ausgeführt:

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

Ersetzen Sie dabei Folgendes:

  • INPUT_FILE ist eine Eingabedatei für die Pipeline.
  • OUTPUT_FILE ist ein Pfad, in den die Ausgabe geschrieben wird.
  • PROJECT_ID: die Google Cloud-Projekt-ID
  • REGION ist die Region, in der Ihr Dataflow-Job bereitgestellt werden soll.
  • TEMP_LOCATION ist ein Cloud Storage-Pfad, den Dataflow für das Staging temporärer Jobdateien verwendet.
  • IMAGE_URI: der URI des benutzerdefinierten Container-Images.

Container-Image beim Senden des Jobs vorfertigen

Durch das Vorfertigen eines Container-Images können Sie die Pipelineabhängigkeiten vor dem Jobstart vorinstallieren. Sie müssen kein benutzerdefiniertes Container-Image erstellen.

Verwenden Sie die folgenden Pipelineoptionen, um beim Senden eines Jobs einen Container mit zusätzlichen Python-Abhängigkeiten vorab zu erstellen:

  • --prebuild_sdk_container_engine=[cloud_build | local_docker] Wenn dieses Flag festgelegt ist, generiert Apache Beam einen benutzerdefinierten Container und installiert alle Abhängigkeiten, die durch die Optionen --requirements_file und --extra_packages angegeben werden. Dieses Flag unterstützt die folgenden Werte:

    • cloud_build. Verwenden Sie Cloud Build, um den Container zu erstellen. Die Cloud Build API muss in Ihrem Projekt aktiviert sein.
    • local_docker. Verwenden Sie Ihre lokale Docker-Installation, um den Container zu erstellen.
  • --docker_registry_push_url=IMAGE_PATH. Ersetzen Sie IMAGE_PATH durch einen Artifact Registry-Ordner.

  • --sdk_location=container. Diese Option verhindert, dass die Worker das SDK beim Starten des Jobs herunterladen. Stattdessen wird das SDK direkt aus dem Container-Image abgerufen.

Im folgenden Beispiel wird Cloud Build verwendet, um das Image vorab zu erstellen:

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

Für die Voraberstellung ist das Apache Beam SDK for Python ab Version 2.25.0 erforderlich.

Im Workflow zum Vorfertigen von SDK-Container-Images wird das Image verwendet, das mit der Pipeline-Option --sdk_container_image als Basis-Image übergeben wurde. Wenn die Option nicht festgelegt ist, wird standardmäßig ein Apache Beam-Image als Basis-Image verwendet.

Sie können ein vorgefertigtes Python SDK-Container-Image in einem anderen Job mit denselben Abhängigkeiten und derselben SDK-Version wiederverwenden. Übergeben Sie die URL des vorgefertigten Container-Image mithilfe der Pipeline-Option --sdk_container_image an den anderen Job, um das Image wiederzuverwenden. Entfernen Sie die Abhängigkeitsoptionen --requirements_file, --extra_packages und --setup_file.

Wenn Sie das Image nicht wiederverwenden möchten, löschen Sie es nach Abschluss des Jobs. Sie können das Image mit der gcloud CLI oder auf den Artifact Registry-Seiten in der Google Cloud Console löschen.

Wenn das Image in Artifact Registry gespeichert ist, verwenden Sie den Befehl artifacts docker images delete:

   gcloud artifacts docker images delete IMAGE --delete-tags

Allgemeine Probleme

  • Wenn der Job zusätzliche Python-Abhängigkeiten aus einem privaten PyPi-Spiegel hat und nicht von einem Remote-Cloud Build-Job abgerufen werden kann, verwenden Sie die lokale Docker-Option oder versuchen Sie, den Container mit einem Dockerfile zu erstellen.

  • Wenn der Cloud Build-Job mit docker exit code 137 fehlschlägt, hat der Build-Job nicht genügend Arbeitsspeicher, möglicherweise aufgrund der Größe der installierten Abhängigkeiten. Verwenden Sie einen größeren Cloud Build-Worker-Maschinentyp. Übergeben Sie dazu --cloud_build_machine_type=machine_type, wobei machine_type eine der folgenden Optionen ist:

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

    Cloud Build verwendet standardmäßig den Maschinentyp e2-medium.

  • In Apache Beam 2.44.0 und höher erstellen Worker beim Starten eines benutzerdefinierten Containers eine virtuelle Umgebung. Wenn der Container seine eigene virtuelle Umgebung zum Installieren von Abhängigkeiten erstellt, werden diese Abhängigkeiten verworfen. Dieses Verhalten kann zu Fehlern wie den folgenden führen:

    ModuleNotFoundError: No module named '<dependency name>'

    Zur Vermeidung dieses Problems installieren Sie Abhängigkeiten in der standardmäßigen (globalen) Python-Umgebung. Zur Umgehung dieses Problems deaktivieren Sie dieses Verhalten in Beam 2.48.0 und höher. Legen Sie dazu die folgende Umgebungsvariable in Ihrem Container-Image fest:

    ENV RUN_PYTHON_SDK_IN_DEFAULT_ENVIRONMENT=1

Wie geht es weiter?