Adrienne Vermorel
Déployer dbt Core sur une Google Cloud Function
Dans un article précédent, j’ai parlé des différences entre dbt Core et dbt Cloud, et comment dbt Core ne propose pas de moyen pour planifier et orchestrer les transformations de données. Donc, si dbt Cloud n’est pas votre choix pour orchestrer les données, vous devrez trouver un autre outil pour le faire.
La méthode que je préfère est d’utiliser les Google Cloud Functions car j’utilise généralement BigQuery pour mon data warehouse, qui se trouve également sur Google Cloud Platform (GCP).
D’autres options pourraient être de déployer via une machine virtuelle (mais cela serait probablement excessif pour un processus qui prend souvent seulement quelques minutes) ou via un container (mais cela nécessite des connaissances plus avancées en code et en gestion d’infrastructure).
Ci-dessous vous trouverez un guide pour déployer dbt Core sur une Google Cloud Function.
Pré-requis
- Vous devez avoir un repository pour projet dbt Core
- Vous devez avoir accès à un projet GCP : je configure généralement l’orchestration dans le projet qui héberge déjà mes transformations de données
Modifier le repo dbt Core
Premièrement, restructurez le repository en mettant tous les dossiers et fichiers dbt actuels dans un sous-répertoire. Je l’ai appelé “dbt_transform” mais vous pouvez le nommer comme vous voulez.
|-- dbt_transform |-- analyses |-- models |-- seeds |-- snapshots |-- tests |-- dbt_project.yml |-- packages.yml |-- profiles.ymlNotez que j’ai un fichier profiles.yml dans mon dossier dbt_transform. Dans ce fichier profiles.yml, utilisez la méthode oauth :
dbt_project_name: outputs: dev: dataset: dbt job_execution_timeout_seconds: 3500 job_retries: 1 location: EU method: oauth priority: interactive project: gcp_project_name threads: 4 type: bigquery target: devAjouter les fichiers main.py et requirements.txt
À la racine du répertoire, créez un fichier main.py :
import osimport subprocessimport logging
# Configure logginglogging.basicConfig(level=logging.INFO)
def run_dbt(request): try: # Set your dbt profiles directory (assuming it's in /workspace) os.environ['DBT_PROFILES_DIR'] = '/workspace/dbt_transform' # Log the current working directory and list files dbt_project_dir = '/workspace/dbt_transform' os.chdir(dbt_project_dir) # Log the current working directory and list files logging.info(f"Current working directory: {os.getcwd()}") logging.info(f"Files in the current directory: {os.listdir('.')}") # Install dbt packages logging.info("Installing dbt packages...") subprocess.run(['dbt', 'deps'], check=True, capture_output=True, text=True) # Run dbt command (e.g., dbt run) result = subprocess.run( ['dbt', 'build'], capture_output=True, text=True ) # Return dbt output return result.stdout except subprocess.CalledProcessError as e: # If a command fails, log its output and error logging.error( f"Command '{e.cmd}' returned non-zero exit status {e.returncode}.") logging.error(f"stdout: {e.stdout}") logging.error(f"stderr: {e.stderr}") return f"Error running dbt: {e.stderr}" except Exception as e: logging.error(f"Error running dbt: {str(e)}") return f"Error running dbt: {str(e)}"Ensuite, ajoutez le requirements.txt pour gérer les dépendances :
dbt-coredbt-bigqueryMaintenant votre repository ressemble à ceci :
|-- dbt_transform |-- analyses |-- models |-- seeds |-- snapshots |-- tests |-- dbt_project.yml |-- packages.yml |-- profiles.yml|-- main.py|-- requirements.txtConfigurer le compte de service pour dbt
Vous devrez configurer un compte de service pour dbt avec les rôles suivants :
- BigQuery Data Viewer et BigQuery Job User sur les projets/datasets qui hébergent les sources de votre projet dbt
- BigQuery Data Editor et BigQuery User sur le projet où vos transformations de données ont lieu
- Cloud Function Invoker sur le projet où votre Cloud Function va tourner
Pour créer ce compte de service, exécutez le script Cloud Shell ci-dessous.
Configurez les variables suivantes : TRANSFORM_PROJECT_ID, FUNCTION_PROJECT_ID et SOURCE_PROJECT_IDS.
# Variables à configurerTRANSFORM_PROJECT_ID="transform-project-id"FUNCTION_PROJECT_ID="function-project-id"SOURCE_PROJECT_IDS=("source-project-id-1" "source-project-id-2" "source-project-id-N")SERVICE_ACCOUNT_NAME="dbt-transform-sa"SERVICE_ACCOUNT_DISPLAY_NAME="dbt Transformation Service Account"
# Créer le compte de service dans le projet de transformations de donnéesgcloud iam service-accounts create "$SERVICE_ACCOUNT_NAME" \ --description="Service account for dbt data transformations" \ --display-name="$SERVICE_ACCOUNT_DISPLAY_NAME" \ --project="$TRANSFORM_PROJECT_ID"
# Formater l'email du compte de serviceSERVICE_ACCOUNT_EMAIL="${SERVICE_ACCOUNT_NAME}@${TRANSFORM_PROJECT_ID}.iam.gserviceaccount.com"echo "Service account $SERVICE_ACCOUNT_EMAIL created."
# Boucler sur les IDs de projets sources pour assigner les rôlesfor PROJECT_ID in "${SOURCE_PROJECT_IDS[@]}"do gcloud projects add-iam-policy-binding "$PROJECT_ID" \ --member="serviceAccount:$SERVICE_ACCOUNT_EMAIL" \ --role="roles/bigquery.dataViewer" gcloud projects add-iam-policy-binding "$PROJECT_ID" \ --member="serviceAccount:$SERVICE_ACCOUNT_EMAIL" \ --role="roles/bigquery.jobUser" echo "Roles assigned in the source project $PROJECT_ID."done
# Assigner les rôles dans le projet de transformationgcloud projects add-iam-policy-binding "$TRANSFORM_PROJECT_ID" \ --member="serviceAccount:$SERVICE_ACCOUNT_EMAIL" \ --role="roles/bigquery.dataEditor"gcloud projects add-iam-policy-binding "$TRANSFORM_PROJECT_ID" \ --member="serviceAccount:$SERVICE_ACCOUNT_EMAIL" \ --role="roles/bigquery.user"echo "Roles assigned in the transformation project."
# Assigner le rôle Cloud Function Invoker dans le projet où la Cloud Function va tournergcloud projects add-iam-policy-binding "$FUNCTION_PROJECT_ID" \ --member="serviceAccount:$SERVICE_ACCOUNT_EMAIL" \ --role="roles/cloudfunctions.invoker"echo "Cloud Function Invoker role assigned."
echo "Setup complete."Déployer la Cloud Function
Pour déployer la Cloud Function, vous devrez avoir le CLI gcloud installé.
Une fois installé, assurez-vous d’être connecté avec le bon compte utilisateur Google en exécutant le script suivant dans votre terminal local.
gcloud auth loginMaintenant, assurez-vous d’être à la racine de votre projet et déployez la Cloud Function en exécutant le script ci-dessous.
Mettez à jour l’adresse de votre compte de service et la région que vous voulez utiliser.
Voici une liste des régions disponibles ; choisissez une région où les fonctions 2ème génération sont disponibles.
gcloud functions deploy dbt_run \--region=europe-west1 \--service-account=dbt-transform-sa@projectid.iam.gserviceaccount.com \--gen2 \--runtime=python310 \--entry-point=run_dbt \--trigger-http \--timeout=3500 \--memory=1GMaintenant que la Cloud Function est déployée, vous pouvez planifier son exécution.
Configurer Cloud Scheduler
Configurez le Cloud Scheduler en exécutant le script ci-dessous dans Google Cloud Shell.
Configurez FUNCTION_URL, SCHEDULER_JOB_NAME, PROJECT_ID, LOCATION et SERVICE_ACCOUNT_EMAIL, TIME_ZONE et CRON_SCHEDULE avec les bonnes valeurs.
Vous pouvez trouver une liste des fuseaux horaires au format tz et un outil pour créer des schedules CRON en ligne.
# VariablesFUNCTION_URL="YOUR_CLOUD_FUNCTION_TRIGGER_URL"SCHEDULER_JOB_NAME="daily-dbt-run-job"PROJECT_ID="YOUR_PROJECT_ID"LOCATION="YOUR_LOCATION_ID"SERVICE_ACCOUNT_EMAIL="YOUR_SERVICE_ACCOUNT_EMAIL"TIME_ZONE="YOUR_TIME_ZONE"CRON_SCHEDULE="0 7 * * *" # Changez ceci selon le planning désiré (quotidien à 7h par défaut)
# Étape 1: S'assurer que le compte de service a le rôle "Service Account Token Creator"gcloud iam service-accounts add-iam-policy-binding $SERVICE_ACCOUNT_EMAIL \ --member="serviceAccount:$SERVICE_ACCOUNT_EMAIL" \ --role="roles/iam.serviceAccountTokenCreator" \ --project=$PROJECT_IDecho "Added Service Account Token Creator role to $SERVICE_ACCOUNT_EMAIL."
# Étape 2: Créer le job Cloud Schedulergcloud scheduler jobs create http $SCHEDULER_JOB_NAME \ --location=$LOCATION \ --schedule="$CRON_SCHEDULE" \ --http-method=GET \ --uri=$FUNCTION_URL \ --oidc-service-account-email=$SERVICE_ACCOUNT_EMAIL \ --oidc-token-audience=$FUNCTION_URL \ --time-zone="$TIME_ZONE" \ --project=$PROJECT_IDecho "Cloud Scheduler job created: $SCHEDULER_JOB_NAME"Félicitations, vous avez terminé d’orchestrer dbt Core avec une Cloud Function.