Cet article est le 2è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,…)
Databricks nous met à disposition un provider Terraform avec lequel nous pouvons déployer des clusters, des Sql Warehouses, des pipelines, … Nous allons voir dans cet article comment utiliser ce provider avec quelques exemples de workload. Vous trouverez l’ensemble du code source ici.
Initialisation des scripts Terraform
Il est préférable de séparer les scripts gérant l’infrastructure Azure (Article 1) des scripts gérant le paramétrage du workspace.
Si on enchaine tout d’un coup lors de la création de l’environnement (Infra Azure + scripts de paramétrage Databricks), on risque d’avoir des erreurs car la création du workspace prend du temps et peut ne pas être complètement terminée lorsque le paramétrage va commencer à se faire.
Commençons tout d’abord par initialiser le provider Databricks :
data "azurerm_databricks_workspace" "this" { name = "dbw-blog-dev-01" resource_group_name = "rg-blog-dev-01" } provider "databricks" { host = data.azurerm_databricks_workspace.this.workspace_url }
Dans cet exemple, nous faisons référence au workspace créé dans le précédent article. On s’aperçoit alors que nos scripts ne peuvent paramétrer qu’un seul workspace.
Secret Scope
Il est possible de créer un secret scope Databricks qui pointe vers un Key Vault. C’est intéressant pour variabiliser les client id et les secrets des SPN à utiliser mais aussi pour variabiliser tout ce qui serait nécessaire dans des scripts :
data "azurerm_key_vault" "key_vault_databricks" { name = "kv-blog-dcube-dev-01" resource_group_name = "rg-blog-dev-01" } resource "databricks_secret_scope" "databricks_secret_scope_key_vault" { name = "key-vault-secret" initial_manage_principal = "users" keyvault_metadata { resource_id = data.azurerm_key_vault.key_vault_databricks.id dns_name = data.azurerm_key_vault.key_vault_databricks.vault_uri } }
Dans cet exemple, nous faisons référence au Key Vault créé et nous ajoutons un secret scope qui s’y rattache. Vous verrez alors des droits sur le Key Vault pour l’identité « AzureDatabriks ».
Création d’un SQL Warehouse
Les Sql Warehouse font partie des workloads Databricks qui permettent d’exécuter des scripts sur du compute. Dans Terraform, c’est appelé « Sql Enpoint ». Voici un exemple d’utilisation :
resource "databricks_sql_endpoint" "this" { name = "Sql Warehouse example" cluster_size = "2X-Small" enable_serverless_compute = true tags { custom_tags { key = "Application" value = "ArticleBlog" } } } resource "databricks_sql_global_config" "this" { security_policy = "DATA_ACCESS_CONTROL" data_access_config = { "spark.hadoop.fs.azure.account.auth.type" : "OAuth", "spark.hadoop.fs.azure.account.oauth.provider.type" : "org.apache.hadoop.fs.azurebfs.oauth2.ClientCredsTokenProvider", "spark.hadoop.fs.azure.account.oauth2.client.id" : "{{secrets/key-vault-secret/spn-id}}", "spark.hadoop.fs.azure.account.oauth2.client.secret" : "{{secrets/key-vault-secret/spn-secret}}", "spark.hadoop.fs.azure.account.oauth2.client.endpoint" : "https://login.microsoftonline.com/${data.azurerm_client_config.current.tenant_id}/oauth2/token" } sql_config_params = { "ANSI_MODE" : "true" } }
Ici, nous créons un SQL Warehouse serverless qui utilise un SPN pour s’identifier. Cette identification est importante pour donner des permissions sur le Data Lake à ce SPN. On voit qu’on fait appel au secret scope « key-vault-secret » précédemment créé. Cette syntaxe permet d’aller chercher dans le Key Vault les secrets « spn-id » et « spn-secret ».
Création d’un pipeline Delta Live Table (DLT)
Delta Live Table permet d’automatiser l’exécution de scripts de type ETL. Vous pouvez les paramétrer par l’interface graphique et les faire pointer vers un notebook. Mais l’utilisation des scripts Terraform rend plus industriel les déploiements et nous assure ainsi d’avoir des environnements identiques.
La déclaration d’un pipeline DLT dans Terraform ressemble beaucoup au JSON que l’on retrouve dans l’interface web de Databricks. Ainsi, vous pouvez mettre en place les pipelines depuis l’interface graphique et récupérer le JSON pour reproduire le paramétrage dans Terraform, comme ceci :
Et voici à quoi cela ressemble une fois en Terraform :
resource "databricks_pipeline" "plague-tale-2-update-gold-data" { name = "pipeline DLT de test" storage = "dbfs:/pipelines/pipeline-dlt-de-test" target = "GOLD" cluster { label = "default" num_workers = 1 node_type_id = "Standard_DS3_v2" spark_conf = { "spark.databricks.cluster.profile" : "singleNode" "fs.azure.account.oauth2.client.id" : "{{secrets/key-vault-secret/spn-id}}" "fs.azure.account.oauth.provider.type" : "org.apache.hadoop.fs.azurebfs.oauth2.ClientCredsTokenProvider" "spark.databricks.unityCatalog.userIsolation.python.preview" : "true" "spark.master" : "local[*, 4]" "fs.azure.account.oauth2.client.endpoint" : "https://login.microsoftonline.com/${data.azurerm_client_config.current.tenant_id}/oauth2/token" "spark.databricks.delta.preview.enabled" : true "fs.azure.account.auth.type" : "OAuth" "fs.azure.account.oauth2.client.secret" : "{{secrets/key-vault-secret/spn-secret}}" } } library { notebook { path = "/shared/Notebooks/pipeline-dlt-de-test" } } continuous = false development = false channel = "current" photon = false edition = "advanced" }
Vous pouvez voir qu’il est assez simple de reproduire la configuration avec Terraform. Les Data Engineer peuvent se créer leurs pipelines sur un environnement de développement puis reproduire la configuration dans Terraform pour déployer sur les autres environnements.
Création d’un job
Pour finir, nous allons maintenant voir un dernier exemple de ce que l’on peut faire avec le provider Databricks de Terraform.
Nous allons créer un job qui va se lancer en exécutant un script shell d’initialisation pour installer les dépendances puis il va exécuter un notebook. De la même manière que pour les pipelines, le plus simple est de commencer par créer le job dans l’interface graphique et de récupérer le JSON pour ensuite faire le script Terraform.
Dans cet exemple, on a une configuration Spark pour accéder au Data lake avec un SPN, pour le reste, c’est très basic.
Et voici comment transformer ça en Terraform :
resource "databricks_job" "this" { name = "Mon-Job-De-Test" new_cluster { num_workers = 0 spark_version = "11.2.x-scala2.12" node_type_id = "Standard_DS3_v2" data_security_mode = "SINGLE_USER" spark_conf = { "spark.databricks.cluster.profile" : "singleNode" "fs.azure.account.oauth2.client.id" : "{{secrets/key-vault-secret/spn-id}}" "fs.azure.account.oauth.provider.type" : "org.apache.hadoop.fs.azurebfs.oauth2.ClientCredsTokenProvider" "spark.master" : "local[*, 4]" "fs.azure.account.oauth2.client.endpoint" : "https://login.microsoftonline.com/${data.azurerm_client_config.current.tenant_id}/oauth2/token" "spark.databricks.delta.preview.enabled" : true "fs.azure.account.auth.type" : "OAuth" "fs.azure.account.oauth2.client.secret" : "{{secrets/key-vault-secret/spn-secret}}" } custom_tags = { "ResourceClass" = "SingleNode" } init_scripts { dbfs { destination = "dbfs:/FileStore/init-scripts/init.sh" } } } notebook_task { notebook_path = /Shared/Notebooks/MonNotebookDeTest } }
Pour aller un peu plus loin dans l’automatisation, si on a plusieurs jobs à créer et qu’ils sont sur le même modèle, on peut se baser sur un tableau de variable de cette manière :
variable "databricks_job_list" { type = list(object({ name = string num_workers = number libraries = list(string) init_script = string notebook_path = string })) }
Ainsi, on peut boucler pour créer autant de jobs que l’on aura d’éléments de la variable :
resource "databricks_job" "this" { count = length(var.databricks_job_list) name = var.databricks_job_list[count.index].name dynamic "library" { for_each = toset(var.databricks_job_list[count.index].libraries) content { pypi { package = library.value } } } new_cluster { num_workers = var.databricks_job_list[count.index].num_workers spark_version = var.databricks_cluster_version node_type_id = var.databricks_job_cluster_worker_type data_security_mode = "SINGLE_USER" spark_conf = { "spark.databricks.cluster.profile" : "singleNode" "fs.azure.account.oauth2.client.id" : "{{secrets/key-vault-secret/spn-id}}" "fs.azure.account.oauth.provider.type" : "org.apache.hadoop.fs.azurebfs.oauth2.ClientCredsTokenProvider" "spark.master" : "local[*, 4]" "fs.azure.account.oauth2.client.endpoint" : "https://login.microsoftonline.com/${data.azurerm_client_config.current.tenant_id}/oauth2/token" "spark.databricks.delta.preview.enabled" : true "fs.azure.account.auth.type" : "OAuth" "fs.azure.account.oauth2.client.secret" : "{{secrets/key-vault-secret/spn-secret}}" } custom_tags = { "ResourceClass" = "SingleNode" } dynamic "init_scripts" { for_each = length(var.databricks_job_list[count.index].init_script) > 0 ? [var.databricks_job_list[count.index].init_script] : [] content { dbfs { destination = "dbfs:/FileStore/init-scripts/${init_scripts.value}" } } } } notebook_task { notebook_path = var.databricks_job_list[count.index].notebook_path } }
On a pu voir quelques exemples mais ce provider Databricks permet de faire encore plus de choses. Si vous désirez automatiser la création de vos environnements, il facilite le travail, plutôt que de passer par les API Rest de Databricks.
Nous allons voir dans l’article suivant comment intégrer tout ceci dans les pipelines de CI/CD.
Liens
Code source : https://github.com/dcube/databricks_template/tree/main/infra/databricks
Terraform :
- https://registry.terraform.io/providers/databricks/databricks/latest/docs/resources/sql_endpoint
- https://registry.terraform.io/providers/databricks/databricks/latest/docs/resources/pipeline
- https://registry.terraform.io/providers/databricks/databricks/latest/docs/resources/job
Databricks :
0 commentaires