Crie clusters, Notebook e Job com o Terraform

Este artigo mostra como usar o provedor Databricks Terraform para criar clusters, um Notebook e um Job em um espaço de trabalho existente do Databricks.

Este artigo é um companheiro para os seguintes artigos do Databricks que estão começando a começar:

Você também pode adaptar as configurações do Terraform nestes artigos para criar clusters personalizados, Notebook e Job em seu workspace.

o passo 1: Criar e configurar o projeto Terraform

  1. Crie um projeto Terraform seguindo as instruções na seção Requisitos dos artigos de visão geral do provedor Databricks Terraform.

  2. Para criar clusters, crie um arquivo chamado cluster.tf e adicione o conteúdo a seguir ao arquivo. Este conteúdo cria clusters com a menor quantidade de recurso permitida. Esses clusters usam a versão mais recente do Databricks Runtime Long Term Support (LTS).

    Para clusters que funcionam com o Unity Catalog:

    variable "cluster_name" {}
    variable "cluster_autotermination_minutes" {}
    variable "cluster_num_workers" {}
    variable "cluster_data_security_mode" {}
    
    # Create the cluster with the "smallest" amount
    # of resources allowed.
    data "databricks_node_type" "smallest" {
      local_disk = true
    }
    
    # Use the latest Databricks Runtime
    # Long Term Support (LTS) version.
    data "databricks_spark_version" "latest_lts" {
      long_term_support = true
    }
    
    resource "databricks_cluster" "this" {
      cluster_name            = var.cluster_name
      node_type_id            = data.databricks_node_type.smallest.id
      spark_version           = data.databricks_spark_version.latest_lts.id
      autotermination_minutes = var.cluster_autotermination_minutes
      num_workers             = var.cluster_num_workers
      data_security_mode      = var.cluster_data_security_mode
    }
    
    output "cluster_url" {
     value = databricks_cluster.this.url
    }
    

    Para todo-propósito de um clusters :

    variable "cluster_name" {
      description = "A name for the cluster."
      type        = string
      default     = "My Cluster"
    }
    
    variable "cluster_autotermination_minutes" {
      description = "How many minutes before automatically terminating due to inactivity."
      type        = number
      default     = 60
    }
    
    variable "cluster_num_workers" {
      description = "The number of workers."
      type        = number
      default     = 1
    }
    
    # Create the cluster with the "smallest" amount
    # of resources allowed.
    data "databricks_node_type" "smallest" {
      local_disk = true
    }
    
    # Use the latest Databricks Runtime
    # Long Term Support (LTS) version.
    data "databricks_spark_version" "latest_lts" {
      long_term_support = true
    }
    
    resource "databricks_cluster" "this" {
      cluster_name            = var.cluster_name
      node_type_id            = data.databricks_node_type.smallest.id
      spark_version           = data.databricks_spark_version.latest_lts.id
      autotermination_minutes = var.cluster_autotermination_minutes
      num_workers             = var.cluster_num_workers
    }
    
    output "cluster_url" {
     value = databricks_cluster.this.url
    }
    
  3. Para criar clusters, crie outro arquivo chamado cluster.auto.tfvars e adicione o conteúdo a seguir ao arquivo. Este arquivo contém valores de variáveis para customizar os clusters. Substitua os valores do espaço reservado pelos seus próprios valores.

    Para clusters que funcionam com o Unity Catalog:

    cluster_name                    = "My Cluster"
    cluster_autotermination_minutes = 60
    cluster_num_workers             = 1
    cluster_data_security_mode      = "SINGLE_USER"
    

    Para todo-propósito de um clusters :

    cluster_name                    = "My Cluster"
    cluster_autotermination_minutes = 60
    cluster_num_workers             = 1
    
  4. Para criar um Notebook, crie outro arquivo chamado notebook.tf e adicione o seguinte conteúdo ao arquivo:

    variable "notebook_subdirectory" {
      description = "A name for the subdirectory to store the notebook."
      type        = string
      default     = "Terraform"
    }
    
    variable "notebook_filename" {
      description = "The notebook's filename."
      type        = string
    }
    
    variable "notebook_language" {
      description = "The language of the notebook."
      type        = string
    }
    
    resource "databricks_notebook" "this" {
      path     = "${data.databricks_current_user.me.home}/${var.notebook_subdirectory}/${var.notebook_filename}"
      language = var.notebook_language
      source   = "./${var.notebook_filename}"
    }
    
    output "notebook_url" {
     value = databricks_notebook.this.url
    }
    
  5. Se você estiver criando clusters, salve o seguinte código Notebook em um arquivo no mesmo diretório do arquivo notebook.tf:

    Para o Python Notebook para execução de sua primeira carga de trabalho ETL no Databricks, um arquivo chamado notebook-getting-started-etl-quick-start.py com o seguinte conteúdo:

    # Databricks notebook source
    # Import functions
    from pyspark.sql.functions import col, current_timestamp
    
    # Define variables used in code below
    file_path = "/databricks-datasets/structured-streaming/events"
    username = spark.sql("SELECT regexp_replace(current_user(), '[^a-zA-Z0-9]', '_')").first()[0]
    table_name = f"{username}_etl_quickstart"
    checkpoint_path = f"/tmp/{username}/_checkpoint/etl_quickstart"
    
    # Clear out data from previous demo execution
    spark.sql(f"DROP TABLE IF EXISTS {table_name}")
    dbutils.fs.rm(checkpoint_path, True)
    
    # Configure Auto Loader to ingest JSON data to a Delta table
    (spark.readStream
      .format("cloudFiles")
      .option("cloudFiles.format", "json")
      .option("cloudFiles.schemaLocation", checkpoint_path)
      .load(file_path)
      .select("*", col("_metadata.file_path").alias("source_file"), current_timestamp().alias("processing_time"))
      .writeStream
      .option("checkpointLocation", checkpoint_path)
      .trigger(availableNow=True)
      .toTable(table_name))
    
    # COMMAND ----------
    
    df = spark.read.table(table_name)
    
    # COMMAND ----------
    
    display(df)
    

    Para o SQL Notebook para tutorial: query data with Notebook, um arquivo chamado notebook-getting-started-quick-start.sql com o seguinte conteúdo:

    -- Databricks notebook source
    -- MAGIC %python
    -- MAGIC diamonds = (spark.read
    -- MAGIC   .format("csv")
    -- MAGIC   .option("header", "true")
    -- MAGIC   .option("inferSchema", "true")
    -- MAGIC   .load("/databricks-datasets/Rdatasets/data-001/csv/ggplot2/diamonds.csv")
    -- MAGIC )
    -- MAGIC 
    -- MAGIC diamonds.write.format("delta").save("/mnt/delta/diamonds")
    
    -- COMMAND ----------
    
    DROP TABLE IF EXISTS diamonds;
    
    CREATE TABLE diamonds USING DELTA LOCATION '/mnt/delta/diamonds/'
    
    -- COMMAND ----------
    
    SELECT color, avg(price) AS price FROM diamonds GROUP BY color ORDER BY COLOR
    

    Para o Python Notebook for tutorial: execução an end-to-end lakehouse analítica pipeline, um arquivo chamado notebook-getting-started-lakehouse-e2e.py com o seguinte conteúdo:

    # Databricks notebook source
    external_location = "<your_external_location>"
    catalog = "<your_catalog>"
    
    dbutils.fs.put(f"{external_location}/foobar.txt", "Hello world!", True)
    display(dbutils.fs.head(f"{external_location}/foobar.txt"))
    dbutils.fs.rm(f"{external_location}/foobar.txt")
    
    display(spark.sql(f"SHOW SCHEMAS IN {catalog}"))
    
    # COMMAND ----------
    
    from pyspark.sql.functions import col
    
    # Set parameters for isolation in workspace and reset demo
    username = spark.sql("SELECT regexp_replace(current_user(), '[^a-zA-Z0-9]', '_')").first()[0]
    database = f"{catalog}.e2e_lakehouse_{username}_db"
    source = f"{external_location}/e2e-lakehouse-source"
    table = f"{database}.target_table"
    checkpoint_path = f"{external_location}/_checkpoint/e2e-lakehouse-demo"
    
    spark.sql(f"SET c.username='{username}'")
    spark.sql(f"SET c.database={database}")
    spark.sql(f"SET c.source='{source}'")
    
    spark.sql("DROP DATABASE IF EXISTS ${c.database} CASCADE")
    spark.sql("CREATE DATABASE ${c.database}")
    spark.sql("USE ${c.database}")
    
    # Clear out data from previous demo execution
    dbutils.fs.rm(source, True)
    dbutils.fs.rm(checkpoint_path, True)
    
    
    # Define a class to load batches of data to source
    class LoadData:
    
      def __init__(self, source):
        self.source = source
    
      def get_date(self):
        try:
          df = spark.read.format("json").load(source)
        except:
            return "2016-01-01"
        batch_date = df.selectExpr("max(distinct(date(tpep_pickup_datetime))) + 1 day").first()[0]
        if batch_date.month == 3:
          raise Exception("Source data exhausted")
          return batch_date
    
      def get_batch(self, batch_date):
        return (
          spark.table("samples.nyctaxi.trips")
            .filter(col("tpep_pickup_datetime").cast("date") == batch_date)
        )
    
      def write_batch(self, batch):
        batch.write.format("json").mode("append").save(self.source)
    
      def land_batch(self):
        batch_date = self.get_date()
        batch = self.get_batch(batch_date)
        self.write_batch(batch)
    
    RawData = LoadData(source)
    
    # COMMAND ----------
    
    RawData.land_batch()
    
    # COMMAND ----------
    
    # Import functions
    from pyspark.sql.functions import col, current_timestamp
    
    # Configure Auto Loader to ingest JSON data to a Delta table
    (spark.readStream
      .format("cloudFiles")
      .option("cloudFiles.format", "json")
      .option("cloudFiles.schemaLocation", checkpoint_path)
      .load(file_path)
      .select("*", col("_metadata.file_path").alias("source_file"), current_timestamp().alias("processing_time"))
      .writeStream
      .option("checkpointLocation", checkpoint_path)
      .trigger(availableNow=True)
      .option("mergeSchema", "true")
      .toTable(table))
    
    # COMMAND ----------
    
    df = spark.read.table(table_name)
    
    # COMMAND ----------
    
    display(df)
    
  6. Se você estiver criando um Notebook, crie outro arquivo chamado notebook.auto.tfvars e adicione o conteúdo a seguir ao arquivo. Este arquivo contém valores variáveis para personalizar a configuração Notebook .

    Para o Python Notebook para execução de sua primeira carga de trabalho ETL no Databricks:

    notebook_subdirectory = "Terraform"
    notebook_filename     = "notebook-getting-started-etl-quick-start.py"
    notebook_language     = "PYTHON"
    

    Para o SQL Notebook para tutorial: query os dados com Notebook:

    notebook_subdirectory = "Terraform"
    notebook_filename     = "notebook-getting-started-quickstart.sql"
    notebook_language     = "SQL"
    

    Para o Python Notebook para tutorial: execução de um pipeline analítico completo de lakehouse:

    notebook_subdirectory = "Terraform"
    notebook_filename     = "notebook-getting-started-lakehouse-e2e.py"
    notebook_language     = "PYTHON"
    
  7. Se você estiver criando um Notebook, em seu workspace do Databricks, certifique-se de configurar todos os requisitos para que o Notebook seja executado com sucesso, consultando as seguintes instruções para:

  8. Para criar o Job, crie outro arquivo chamado job.tf e adicione o conteúdo a seguir ao arquivo. Este conteúdo cria um Job para execução do Notebook.

    variable "job_name" {
      description = "A name for the job."
      type        = string
      default     = "My Job"
    }
    
    resource "databricks_job" "this" {
      name = var.job_name
      existing_cluster_id = databricks_cluster.this.cluster_id
      notebook_task {
        notebook_path = databricks_notebook.this.path
      }
      email_notifications {
        on_success = [ data.databricks_current_user.me.user_name ]
        on_failure = [ data.databricks_current_user.me.user_name ]
      }
    }
    
    output "job_url" {
      value = databricks_job.this.url
    }
    
  9. Se você estiver criando um Job, crie outro arquivo chamado job.auto.tfvars e adicione o conteúdo a seguir ao arquivo. Este arquivo contém um valor variável para personalizar a configuração Job .

    job_name = "My Job"
    

Passo 2: Execução das configurações

Nesta passo, você executa as configurações do Terraform para aprimorar os clusters, o Notebook e o Job em seu workspace do Databricks.

  1. Verifique se suas configurações do Terraform são válidas executando o comando terraform validate . Se algum erro for relatado, corrija-o e execute o comando novamente.

    terraform validate
    
  2. Verifique o que o Terraform fará em seu workspace, antes que o Terraform realmente o faça, executando o comando terraform plan.

    terraform plan
    
  3. aprimore os clusters, o Notebook e o Job em seu workspace executando o comando terraform apply. Quando solicitado a melhorar, digite yes e pressione Enter.

    terraform apply
    

    A Terraform aprimorou os recursos que estão especificados em seu projeto. aprimorar esses recursos (especialmente um clusters) pode levar vários minutos.

Passo 3: Explorar os resultados

  1. Se você criou um clusters, na saída do comando terraform apply, copie o link ao lado de cluster_url e cole-o na barra de endereços do navegador da web.

  2. Se você criou um Notebook, na saída do comando terraform apply, copie o link ao lado de notebook_url e cole-o na barra de endereços do navegador da web.

    Observação

    Antes de usar o Notebook, pode ser necessário personalizar seu conteúdo. Consulte a documentação relacionada sobre como personalizar o Notebook.

  3. Se você criou um Job, na saída do comando terraform apply, copie o link ao lado de job_url e cole-o na barra de endereços do navegador da web.

    Observação

    Antes de executar o Notebook, você pode precisar customizar seu conteúdo. Consulte os links no início deste artigo para obter a documentação relacionada sobre como personalizar o Notebook.

  4. Se você criou um Job, execute o Job da seguinte forma:

    1. Clique em execução agora na página Job .

    2. Depois que a execução do Job terminar, para view os resultados da execução do Job , na lista Execuções concluídas (últimos 60 dias) na página Job , clique na entrada de tempo mais recente na coluna de horário de início . O painel Output mostra o resultado da execução do código do Notebook .

Passo 4: Limpar

Nesta passo, você exclui os recursos anteriores de seu workspace.

  1. Verifique o que o Terraform fará em seu workspace, antes que o Terraform realmente o faça, executando o comando terraform plan.

    terraform plan
    
  2. Exclua os clusters, o Notebook e o Job de seu workspace executando o comando terraform destroy. Quando solicitado a excluir, digite yes e pressione Enter.

    terraform destroy
    

    O Terraform exclui os recursos especificados em seu projeto.