Utiliser des conteneurs personnalisés dans Dataflow

Cette page explique comment personnaliser l'environnement d'exécution du code utilisateur dans les pipelines Dataflow en fournissant une image de conteneur personnalisé. Les conteneurs personnalisés sont compatibles avec les pipelines utilisant Dataflow Runner v2.

Lorsque Dataflow lance des VM de nœud de calcul, il utilise des images de conteneurs Docker pour lancer des processus de SDK en conteneurs sur les nœuds de calcul. Vous pouvez spécifier une image de conteneur personnalisée au lieu d'utiliser l'une des images Apache Beam par défaut. Lorsque vous spécifiez une image de conteneur personnalisée, Dataflow lance des nœuds de calcul qui extraient l'image spécifiée. Voici quelques raisons pour lesquelles vous pouvez utiliser un conteneur personnalisé :

  • Préinstallation des dépendances de pipeline pour réduire le temps de démarrage des nœuds de calcul
  • Préinstallation des dépendances de pipeline qui ne sont pas disponibles dans les dépôts publics.
  • Prétraitement des fichiers volumineux pour réduire le temps de démarrage des nœuds de calcul.
  • Lancement d'un logiciel tiers en arrière-plan.
  • Personnalisation de l'environnement d'exécution.

Pour une présentation plus détaillée des conteneurs personnalisés, consultez le guide des conteneurs personnalisés Apache Beam.

Avant de commencer

Vérifiez que vous avez installé une version du SDK Apache Beam compatible avec l'exécuteur v2 et avec votre version de langage.

Vous pouvez ensuite utiliser la ou les options de pipeline suivantes pour activer les conteneurs personnalisés :

Java

Utilisez --experiments=use_runner_v2 pour activer l'exécuteur v2.

Utilisez le paramètre --sdkContainerImage afin de spécifier une image de conteneur client pour votre environnement d'exécution Java.

Python

Si vous utilisez le SDK 2.30.0 ou version ultérieure, utilisez l'option de pipeline --sdk_container_image.

Pour les anciennes versions du SDK, utilisez l'option de pipeline --worker_harness_container_image.

Pour en savoir plus, consultez le guide Installer le SDK Apache Beam.

Pour tester votre image de conteneur localement, vous devez avoir installé Docker. Pour en savoir plus, consultez la page Obtenir Docker.

Images de conteneurs du SDK par défaut

Nous vous recommandons de commencer par une image par défaut du SDK Apache Beam comme image de conteneur de base. Les images par défaut sont publiées dans les versions d'Apache Beam sur DockerHub.

Créer l'image de conteneur

Cette section fournit des exemples de différentes manières de créer une image de conteneur de SDK personnalisée.

Une image de conteneur de SDK personnalisée doit répondre aux exigences suivantes :

  • Le SDK Apache Beam et les dépendances nécessaires sont installés.
  • Le script ENTRYPOINT par défaut (/opt/apache/beam/boot sur les conteneurs par défaut) s'exécute à la dernière étape lors du démarrage du conteneur. Consultez la section Modifier le point d'entrée du conteneur pour plus d'informations.

Utiliser l'image de base Apache Beam

Pour créer une image de conteneur personnalisé, spécifiez l'image Apache Beam en tant qu'image parente et ajoutez vos propres personnalisations. Pour en savoir plus sur l'écriture de Dockerfiles, consultez la page Bonnes pratiques pour l'écriture de Dockerfiles.

  1. Créez un fichier Dockerfile en spécifiant l'image de base à l'aide de l'instruction FROM.

    Java

    Dans cet exemple, nous utilisons Java 8 avec le SDK Apache Beam version 2.34.0.

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

    La version d'exécution du conteneur personnalisé doit correspondre à l'environnement d'exécution que vous utiliserez pour démarrer le pipeline. Par exemple, si vous démarrez le pipeline à partir d'un environnement Java 11 local, la ligne FROM doit spécifier un environnement Java 11 : apache/beam_java11_sdk:....

    Python

    Dans cet exemple, nous utilisons Python 3.8 avec le SDK Apache Beam version 2.34.0.

    FROM apache/beam_python3.8_sdk:2.34.0
    
    # Make your customizations here, for example:
    ENV FOO=/bar
    COPY path/to/myfile ./
    

    La version d'exécution du conteneur personnalisé doit correspondre à l'environnement d'exécution que vous utiliserez pour démarrer le pipeline. Par exemple, si vous démarrez le pipeline à partir d'un environnement Python 3.8 local, la ligne FROM doit spécifier un environnement Python 3.8 : apache/beam_python3.8_sdk:....

  2. Créez l'image enfant et transférez-la vers Container Registry.

    Cloud Build

    export PROJECT=PROJECT
    export REPO=REPO
    export TAG=TAG
    export IMAGE_URI=gcr.io/$PROJECT/$REPO:$TAG
    gcloud builds submit . --tag $IMAGE_URI
    

    Docker

    export PROJECT=PROJECT
    export REPO=REPO
    export TAG=TAG
    export IMAGE_URI=gcr.io/$PROJECT/$REPO:$TAG
    docker build . --tag $IMAGE_URI
    docker push $IMAGE_URI
    

    Remplacez les éléments suivants :

    • PROJECT : nom du projet ou de l'utilisateur.
    • REPO : nom du dépôt de l'image.
    • TAG : tag de l'image, généralement latest.

Utiliser une image de base personnalisée ou des compilations en plusieurs étapes

Si vous disposez d'une image de base existante ou si vous devez modifier un aspect de base des images Apache Beam par défaut (version de système d'exploitation, correctifs, etc.), utilisez un processus de création en plusieurs étapes pour copier les artefacts nécessaires à partir d'une image de base Apache Beam par défaut et fournir votre image de conteneur personnalisé.

Voici un exemple de Dockerfile qui copie les fichiers du SDK Apache Beam :

Java

FROM openjdk:8

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

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

Python

FROM python:3.8-slim

# Install SDK.
RUN pip install --no-cache-dir apache-beam[gcp]==2.34.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.8_sdk:2.34.0 /opt/apache/beam /opt/apache/beam

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

Cet exemple suppose que les dépendances nécessaires (dans ce cas, Python 3.8 et pip) ont été installées sur l'image de base existante. L'installation du SDK Apache Beam dans l'image garantit que l'image dispose des dépendances de SDK nécessaires et réduit le temps de démarrage des nœuds de calcul. La version spécifiée dans l'instruction RUN doit correspondre à la version utilisée pour lancer le pipeline.

Modifier le point d'entrée du conteneur

Les conteneurs personnalisés doivent exécuter le script ENTRYPOINT par défaut /opt/apache/beam/boot, qui initialise l'environnement de calcul et lance le processus du SDK. Si vous ne définissez pas ce point d'entrée, votre nœud de calcul ne démarrera pas correctement.

Si vous devez exécuter votre propre script au démarrage du conteneur, vous devez vous assurer que votre image ENTRYPOINT démarre toujours correctement le processus du SDK de nœud de calcul, y compris en transmettant les arguments Dataflow à ce script.

Cela signifie que votre ENTRYPOINT personnalisé doit se terminer par l'exécution de /opt/apache/beam/boot, et que tous les arguments requis transmis par Dataflow au démarrage du conteneur sont correctement transmis au script de démarrage par défaut. Pour ce faire, créez un script personnalisé qui exécute /opt/apache/beam/boot :

#!/bin/bash

echo "This is my custom script"

# ...

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

Ensuite, remplacez la valeur par défaut de ENTRYPOINT. Exemple Dockerfile :

Java

FROM apache/beam_java8_sdk:2.34.0

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

Python

FROM apache/beam_python3.8_sdk:2.34.0

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

Exécuter une tâche avec des conteneurs personnalisés

Cette section traite de l'exécution de pipelines avec des conteneurs personnalisés, avec des exécuteurs locaux à des fins de test et sur Dataflow. Si vous avez déjà validé votre image de conteneur et votre pipeline, passez à la section Lancer la tâche Dataflow.

Avant de commencer

Lors de l'exécution de votre pipeline, veillez à lancer le pipeline à l'aide du SDK Apache Beam avec la même version et la même version de langage que le SDK de votre image de conteneur personnalisée. Cela évite les erreurs inattendues provenant de SDK ou de dépendances incompatibles.

Tester localement

Pour en savoir plus sur l'utilisation spécifique à Apache Beam, consultez le guide Apache Beam Exécuter des pipelines avec des images de conteneurs personnalisées.

Tests de base avec PortableRunner

Vérifiez que les images de conteneurs distantes peuvent être extraites et qu'elles peuvent au moins exécuter un pipeline simple à l'aide du PortableRunner Apache Beam.

Voici un exemple d'exécution de pipeline :

Java

mvn compile exec:java -Dexec.mainClass=com.example.package.MyClassWithMain \
    -Dexec.args="--runner=PortableRunner \
    --job_endpoint=embed \
    --environment_type=DOCKER \
    --environment_config=IMAGE_URI \
    --inputFile=INPUT_FILE \
    --output=OUTPUT_FILE"

Python

python path/to/my/pipeline.py \
  --runner=PortableRunner \
  --job_endpoint=embed \
  --environment_type=DOCKER \
  --environment_config=IMAGE_URI \
  --input=INPUT_FILE \
  --output=OUTPUT_FILE

Remplacez les éléments suivants :

  • IMAGE_URI : URI de l'image de conteneur personnalisée. Vous pouvez utiliser la variable d'interface système $IMAGE_URI créée à l'étape précédente si elle demeure dans le champ d'application.
  • INPUT_FILE : fichier d'entrée pouvant être lu sous forme de fichier texte. L'image de conteneur
    du SDK Harness doit pouvoir accéder à ce fichier. Il peut être soit préchargé sur l'image du conteneur, soit accessible en tant que fichier distant.
  • OUTPUT_FILE : chemin d'accès au fichier dans lequel écrire le résultat. Il peut s'agir d'un chemin distant ou d'un chemin d'accès local sur le conteneur.

Une fois le pipeline terminé, consultez les journaux de la console pour vérifier que le pipeline a bien été exécuté, et que l'image distante spécifiée par $IMAGE_URI a bien été utilisée.

Notez qu'après l'exécution, les fichiers enregistrés dans le conteneur ne se trouvent pas dans votre système de fichiers local et le conteneur s'est arrêté. Les fichiers peuvent être copiés à partir du système de fichiers de conteneur arrêté à l'aide de docker cp.

Vous pouvez également procéder comme suit :

  • Fournir des sorties à un système de fichiers distant tel que Cloud Storage. Notez que cela peut nécessiter la configuration manuelle de l'accès à des fins de test, y compris les fichiers d'identifiants ou les identifiants par défaut de l'application.
  • Ajouter une journalisation temporaire pour un débogage rapide.

Utiliser DirectRunner

Pour des tests locaux plus approfondis de l'image de conteneur et de votre pipeline, utilisez DirectRunner d'Apache Beam.

Vous pouvez vérifier votre pipeline séparément du conteneur en effectuant un test dans un environnement local correspondant à l'image du conteneur, ou en lançant le pipeline sur un conteneur en cours d'exécution.

Java

docker run -it --entrypoint "/bin/bash" $IMAGE_URI
...
# On docker container:
root@4f041a451ef3:/#  mvn compile exec:java -Dexec.mainClass=com.example.package.MyClassWithMain ...

Python

docker run -it --entrypoint "/bin/bash" $IMAGE_URI
...
# On docker container:
root@4f041a451ef3:/#  python path/to/my/pipeline.py ...

Cet exemple suppose que tous les fichiers de pipeline (y compris le pipeline lui-même) se trouvent sur le conteneur personnalisé lui-même, ont été installés à partir d'un système de fichiers local, ou sont distants et accessibles par Apache Beam et le conteneur. Par exemple, pour utiliser Maven (mvn) pour exécuter l'exemple Java ci-dessus, vous devez disposer de Maven et de ses dépendances en préproduction sur le conteneur. Pour en savoir plus, consultez la documentation de Docker sur le stockage et docker run.

Notez que l'objectif des tests DirectRunner est de tester votre pipeline dans l'environnement de conteneurs personnalisés, et non de tester l'exécution effective de votre conteneur avec son ENTRYPOINT par défaut. Modifiez le fichier ENTRYPOINT (par exemple, docker run --entrypoint ...) pour exécuter directement votre pipeline ou autoriser les commandes manuelles sur le conteneur.

Si vous souhaitez vous appuyer sur une configuration spécifique sur Compute Engine, vous pouvez exécuter ce conteneur directement sur une VM Compute Engine. Consultez la section GPU sur Compute Engine pour plus d'informations.

Lancer la tâche Dataflow

Lors du lancement du pipeline Apache Beam sur Dataflow, spécifiez le chemin d'accès à l'image de conteneur, comme indiqué ci-dessous :

Java

Utilisez le paramètre --sdkContainerImage afin de spécifier une image de conteneur client pour votre environnement d'exécution Java.

Utilisez --experiments=use_runner_v2 pour activer l'exécuteur v2.

Python

Si vous utilisez le SDK 2.30.0 ou version ultérieure, utilisez l'option de pipeline --sdk_container_image.

Pour les anciennes versions du SDK, utilisez l'option de pipeline --worker_harness_container_image.

Les conteneurs personnalisés ne sont compatibles qu'avec l'application Runner v2. Si vous lancez un pipeline Python par lots, définissez l'option --experiments=use_runner_v2. Si vous lancez un pipeline Python en streaming, la spécification du test n'est pas nécessaire, car les pipelines Python en streaming utilisent Runner v2 par défaut.

L'exemple suivant montre comment lancer l'exemple de traitement par lots wordcount avec un conteneur personnalisé.

Java

mvn compile exec:java -Dexec.mainClass=org.apache.beam.examples.WordCount \
   -Dexec.args="--runner=DataflowRunner \
                --inputFile=INPUT_FILE \
                --output=OUTPUT_FILE \
                --project=PROJECT_ID \
                --region=REGION \
                --gcpTempLocation=TEMP_LOCATION \
                --diskSizeGb=DISK_SIZE_GB \
                --experiments=use_runner_v2 \
                --sdkContainerImage=$IMAGE_URI"

Python

Utilisez le SDK Apache Beam pour Python version 2.30.0 ou ultérieure :

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 \
  --sdk_container_image=$IMAGE_URI

Remplacez les éléments suivants :

  • INPUT_FILE : chemin d'accès au fichier d'entrée Cloud Storage lu par Dataflow lors de l'exécution de l'exemple.
  • OUTPUT_FILE : chemin d'accès au fichier de sortie Cloud Storage écrit par l'exemple de pipeline. Le nombre de mots sera consigné ici.
  • PROJECT_ID : ID de votre projet Google Cloud.
  • REGION : point de terminaison régional pour le déploiement de votre tâche Dataflow.
  • TEMP_LOCATION : chemin d'accès à Cloud Storage dans lequel Dataflow prépare les fichiers de tâches temporaires créés lors de l'exécution du pipeline.
  • DISK_SIZE_GB (facultatif) : si votre conteneur est volumineux, envisagez d'augmenter la taille du disque de démarrage par défaut afin d'éviter de manquer d'espace disque.
  • $IMAGE_URI : URI de l'image de conteneur personnalisée. Vous pouvez utiliser la variable d'interface système $IMAGE_URI créée à l'étape précédente si elle demeure dans le champ d'application.

Dépannage

Cette section fournit des instructions permettant de résoudre des problèmes liés à l'utilisation de conteneurs personnalisés dans Cloud Dataflow. Les problèmes de démarrage de conteneurs ou de nœuds de calcul y sont plus particulièrement traités. Si vos nœuds de calcul peuvent démarrer et progresser, suivez les instructions générales de dépannage de pipeline.

Avant de contacter l'assistance, assurez-vous d'avoir résolu les problèmes liés à votre image de conteneur :

  • Suivez les étapes pour tester votre image de conteneur localement.
  • Recherchez les erreurs dans les journaux des tâches ou dans les journaux des nœuds de calcul, et comparez les erreurs détectées par rapport aux conseils sur les erreurs courantes.
  • Assurez-vous que la version du SDK Apache Beam et la version du langage que vous utilisez pour lancer le pipeline correspondent au SDK sur votre image de conteneur personnalisée.
  • Si vous utilisez Java, assurez-vous que la version majeure de Java que vous utilisez pour lancer le pipeline correspond à la version installée dans votre image de conteneur.
  • Si vous utilisez Python, assurez-vous que la version majeure et mineure de Python que vous utilisez pour lancer le pipeline correspond à la version installée dans votre image de conteneur, et que celle-ci ne présente pas de dépendances conflictuelles. Vous pouvez exécuter pip check pour confirmer.

Rechercher les journaux des nœuds de calcul liés aux conteneurs personnalisés

Les journaux des nœuds de calcul Dataflow des messages d'erreur liés au conteneur sont disponibles dans l'explorateur de journaux :

  1. Sélectionnez les noms de journaux. Les erreurs de démarrage des conteneurs personnalisés relèvent probablement de l'un des cas suivants :

    • dataflow.googleapis.com/docker
    • dataflow.googleapis.com/kubelet
    • dataflow.googleapis.com/worker-startup
  2. Sélectionnez la ressource Dataflow Step et spécifiez le job_id.

En particulier, si vous voyez des messages de journal Error Syncing pod..., suivez les conseils concernant les erreurs courantes. Vous pouvez interroger ces messages de journal dans les journaux des nœuds de calcul Dataflow à l'aide de l'explorateur de journaux avec la requête suivante :

resource.type="dataflow_step" AND jsonPayload.message:("$IMAGE_URI") AND severity="ERROR"

Problèmes courants

La tâche présente des erreurs ou a échoué, car l'image de conteneur ne peut pas être extraite

Les images de conteneurs personnalisées doivent être accessibles par les nœuds de calcul Dataflow. Si le nœud de calcul ne peut pas extraire l'image en raison d'URL non valides, d'identifiants mal configurés ou d'un accès réseau manquant, le nœud de calcul ne démarre pas.

Dans le cas des tâches par lot pour lesquelles aucun travail n'a démarré et plusieurs nœuds de calcul ne peuvent pas démarrer de manière séquentielle, Dataflow fait échouer la tâche. Sinon, Dataflow consigne les erreurs, mais n'effectue aucune autre action pour éviter de détruire l'état d'une tâche de longue durée.

Suivez les conseils sur les erreurs courantes pour en déterminer l'origine et résoudre ce problème.

Les nœuds de calcul ne démarrent pas ou leur travail ne progresse pas

Dans certains cas, si le conteneur du SDK ne démarre pas en raison d'une erreur, Dataflow ne peut pas déterminer si l'erreur est permanente ou fatale, et tente continuellement de redémarrer le nœud de calcul en cas d'échec.

Recherchez des erreurs spécifiques dans les journaux des nœuds de calcul et consultez les conseils sur les erreurs courantes.

Si aucune erreur évidente ne s'affiche, mais que vous voyez des journaux [topologymanager] RemoveContainer de niveau INFO dans dataflow.googleapis.com/kubelet, ces journaux indiquent que l'image de conteneur personnalisée se ferme prématurément et n'a pas démarré. le processus du SDK des nœuds de calcul de longue durée. Cela peut se produire si un ENTRYPOINT personnalisé ne démarre pas le script de démarrage par défaut /opt/apache/beam/boot ou n'a pas transmis d'arguments de manière appropriée à ce script. Consultez la section Modifier le point d'entrée personnalisé.