Cet article est le 3ème d’une série de 3 articles sur l’automatisation des déploiements Databricks :
- Déploiement d’un Workspace Databricks dans Azure avec Terraform
- Paramétrage d’un workspace Databricks par Terraform
- Pipelines de déploiement d’un environnement Databricks (Infra, paramétrage, notebooks,…)
Nous avons vu dans les articles précédents comment créer un environnement Databricks en utilisant Terraform. Pour aller jusqu’au bout, nous allons maintenant voir comment intégrer tout ceci dans des pipelines de déploiement Azure Devops pour déployer l’infrastructure et des notebooks.
Retrouvez le code source complet ici
Découpage des pipelines de déploiements
Les pipelines de déploiements que nous allons faire, sont découpés en 3 :
- un pipeline de déploiement de l’infra Azure. Il s’agit de déployer ce que nous avons fait sur le 1er article
- un pipeline de déploiement de la configuration Databricks. Il s’agit de déployer ce que nous avons fait sur le 2ème article
- un pipeline de déploiement de Notebooks et de fichiers d’initialisation des clusters. C’est ce dernier pipeline que les data engineers utiliseront le plus pour déployer leurs développements
Déploiement Terraform
Que ce soit pour le pipeline de déploiement de l’infra Azure ou le pipeline de déploiement de la configuration Databricks, on utilise Terraform, ce qui nous permet d’utiliser la même méthode de déploiement et d’avoir un template yaml qui effectue les tâches suivantes :
- Affectation des variables Terraform
- Installation de Terraform
- Lancement de la commande « Terraform init »
- Lancement de la commande « Terraform apply »
Pour que l’affectation des variables se fasse, il y a quelques pré-requis :
- Ajouter un groupe de variables dans Azure Devops pour chaque environnement
- Créer un fichier « tfvars » dans les scripts Terraform qui référence les variables Azure Devops
- Référencer le groupe de variables dans le pipeline Yaml
Les groupes de variables sont automatiquement injectés lors de l’exécution d’un pipeline s’il est référencé dans le Yaml. Un groupe de variables par environnement est nécessaire et on peut prévoir un groupe de variables pour tout ce qui va être commun à tous les environnements.
Dans nos scripts Terraform, on crée un fichier « variables.auto.tfvars » qui référence les variables que l’on a mis dans nos groupes de variables Azure Devops :
Ici, par exemple, « __ResourceGroupName__ » sera remplacé par la valeur de la variable « ResourceGroupName ».
Et pour que ces variables soient injectées, il faut les référencer et utiliser une tâche de « Replace tokens » :
jobs: - job: DeployInfra displayName: 'Deploy Infra' variables: - group: 'Infra-Dev' - group: 'Infra-Common' steps: - task: replacetokens@5 inputs: rootDirectory: '$(Pipeline.Workspace)/${{ parameters.PipelineResourceName }}/${{ parameters.ArtifactName }}' targetFiles: 'variables.auto.tfvars' encoding: 'auto' tokenPattern: 'rm' writeBOM: false actionOnMissing: 'warn' keepToken: false actionOnNoFiles: 'continue' enableTransforms: false enableRecursion: false useLegacyPattern: false enableTelemetry: true
Là, on voit bien que l’on référence les groupes de variables « Infra-Dev » et « Infra-Common » et la tâche « Replace tokens » remplace toutes les valeurs dans le fichier variables.auto.tfvars.
On peut ensuite dérouler le process classique d’exécution des scripts Terraform :
- task: TerraformInstaller@0 displayName: 'Install Terraform 1.2.9' inputs: terraformVersion: 1.2.9 - task: TerraformTaskV2@2 displayName: 'Terraform : azurerm init' inputs: provider: 'azurerm' command: 'init' workingDirectory: '$(Pipeline.Workspace)/${{ parameters.PipelineResourceName }}/${{ parameters.ArtifactName }}' commandOptions: '-no-color' backendServiceArm: '${{ parameters.ServiceConnection }}' backendAzureRmResourceGroupName: '$(TerraformResourceGroupName)' backendAzureRmStorageAccountName: $(TerraformStorageAccountName) backendAzureRmContainerName: '$(TerraformContainerName)' backendAzureRmKey: '${{ parameters.TerraformKey }}' - task: TerraformTaskV2@2 displayName: 'Terraform : azurerm validate and apply' inputs: provider: 'azurerm' command: apply workingDirectory: '$(Pipeline.Workspace)/${{ parameters.PipelineResourceName }}/${{ parameters.ArtifactName }}' commandOptions: '-no-color --var-file=variables.auto.tfvars' environmentServiceNameAzureRM: '${{ parameters.ServiceConnection }}'
En « templatisant » tout ceci dans un fichier Yaml, on crée à la fois le 1er et le 2ème pipeline. Voici à quoi ressemble le déploiement de l’environnement de dev pour l’infra Azure :
stages: - stage: Dev displayName: Dev condition: or(eq(variables['Build.SourceBranch'],'refs/heads/develop'), startsWith(variables['Build.SourceBranch'],'refs/heads/feature'), startsWith(variables['Build.SourceBranch'],'refs/heads/fix')) variables: - group: 'Infra-Dev' - group: 'Infra-Common' jobs: - template: release-terraform-stage-template.yml parameters: ServiceConnection: 'CONNECTION-DEV' PoolName: 'POOL-DEV' PipelineResourceName: 'resourceBuild' EnvironmentName: Develop ArtifactName: infra-azure TerraformKey: infra-azure.tfstate
Déploiement des Notebooks et des scripts d’initialisation des clusters
Dans l’article précédent, nous avons vu comment déployer des pipelines et des jobs clusters. Ils exécutent des notebooks qui se trouvent sur l’espace « /Shared » du workspace. Ces notebooks doivent être déployés par la CI/CD. Pour cela, nous allons faire un pipeline qui lance les tâches suivantes :
- Récupération d’un token Azure AD pour se connecter à Databricks
- Récupération de l’URL du workspace Databricks
- Installation de Python. Nécessaire à l’installation de Databricks Connect
- Installation de Databricks Connect
- Déploiement des Notebooks
- Déploiement des scripts d’initialisation des clusters
Récupération d’un token Azure AD pour se connecter à Databricks
Pour l’exécution de commandes Databricks Connect, nous avons besoin d’un token d’authentification. Nous utiliserons l’identité du Service Connection Azure Devops dont nous supposons qui a les permissions (le créateur du Workspace Databricks a les droits admin. Donc si c’est ce même Service Connection qui a été utilisé pour créer le workspace, il n’y aura pas de problème de permissions). Nous utilisons une commande AZ CLI pour récupérer ce token et nous l’enregistrons dans une variable d’environnement que Databricks Connect utilisera :
- task: AzureCLI@2 displayName: 'Get SPN Acces token for Databricks' inputs: azureSubscription: '${{ parameters.ServiceConnection }}' scriptType: 'pscore' scriptLocation: 'inlineScript' inlineScript: | $accessToken=(az account get-access-token --resource 2ff814a6-3304-4ab8-85cb-cd0e6f879c1d | jq .accessToken --raw-output) Write-Host ("##vso[task.setvariable variable=AccessToken;]$accessToken") [System.Environment]::SetEnvironmentVariable('DATABRICKS_AAD_TOKEN', $accessToken, [System.EnvironmentVariableTarget]::Machine) failOnStandardError: true
Récupération de l’URL du workspace Databricks
Nous utilisons une commande AZ CLI pour récupérer l’URL du workspace à partir de son nom qui se trouve dans le groupe de variables :
- task: AzureCLI@2 displayName: 'Get Databricks Workspace URL' inputs: azureSubscription: '${{ parameters.ServiceConnection }}' scriptType: 'pscore' scriptLocation: 'inlineScript' inlineScript: | az extension add --name databricks $workspaceUrl=(az databricks workspace show --resource-group "$(ResourceGroupName)" --name "$(DatabricksWorkspaceName)" --query workspaceUrl --output tsv) Write-Host ("##vso[task.setvariable variable=WorkspaceUrl;]$workspaceUrl") failOnStandardError: true
Installation de Databricks Connect
Nous installons Databricks Connect et nous le configurons en créant un fichier databrickscfg qui contient les informations d’identification du workspace : l’url et l’access token précédemment récupérés.
- task: UsePythonVersion@0 inputs: versionSpec: '3.8' displayName: 'Use Python 3.8' - task: Bash@3 displayName: 'Install et configure Databricks connect' inputs: targetType: 'inline' script: | python -m pip install databricks-cli cat > ~/.databrickscfg <<EOF [DEFAULT] host = https://$(WorkspaceUrl)/ token = $(AccessToken) EOF
Déploiement des Notebooks
Maintenant que Databricks Connect est installé et configuré, nous pouvons l’utiliser pour déployer les notebooks.
D’abord nous supprimons le répertoire cible pour nettoyer tout éventuel ancien fichier indésirable puis nous copions les notebooks dans le répertoire « /shared/Notebooks » du workspace :
- task: Bash@3 displayName: 'Suppression du répertoire /Shared/Notebooks' inputs: targetType: 'inline' script: | FOLDER=/Shared/Notebooks databricks workspace ls $FOLDER > /dev/null RES=$? if [ $RES -eq 0 ]; then databricks workspace delete -r $FOLDER fi failOnStderr: true - task: Bash@3 displayName: 'Deploy Notebooks' inputs: targetType: 'inline' script: | databricks workspace import_dir -o '$(Pipeline.Workspace)/resourceBuild/notebooks' '/Shared/Notebooks' failOnStderr: true
Déploiement des scripts d’initialisation des clusters
De la même manière que les notebooks, nous déployons les scripts d’initialisation sauf que ceux-ci doivent se trouver dans le DBFS du workspace :
- task: Bash@3 displayName: 'Deploy init scripts' inputs: targetType: 'inline' script: | databricks fs rm -r dbfs:/FileStore/init-scripts/ databricks fs cp -r $(Pipeline.Workspace)/resourceBuild/init-scripts/ dbfs:/FileStore/init-scripts/ --overwrite failOnStderr: true
Bilan
Avec tout ce que nous venons de faire nous avons une CI/CD complète pour déployer sur tous les environnements.
Le workflow de travail des Data Engineers ressemble à celui-ci :
- Les Data Engineers créent leur branche de travail depuis Databricks et developpent leurs fonctionnalités
- Ils commitent leur code depuis Databricks et lancent des Pull Request dans Azure Devops pour merger
- Les pipelines de build se lancent et déploient le travail des Data Engineers sur l’environnement cible
0 commentaires