Provedor de recursos Pulumi do Databricks

Observação

Este artigo aborda o Pulumi, que não é fornecido nem tem suporte do Databricks. Para entrar em contato com o provedor, confira o Suporte do Pulumi.

Este artigo mostra como usar o Python e o Pulumi, uma plataforma de IaC (infraestrutura como código) de terceiros que permite criar, implantar e gerenciar recursos do Azure Databricks usando linguagens de programação, ferramentas e práticas de engenharia familiares. Embora este artigo mostre como usar o Python e o provedor de recursos Pulumi do Databricks, o Pulumi dá suporte a outras linguagens além do Python para o Azure Databricks, incluindo TypeScript, JavaScript, Go e C#.

O provedor de recursos Pulumi do Databricks é baseado no provedor Terraform do Databricks. Para obter mais informações, confira Terraform Cloud.

Requisitos

As etapas a seguir mostram como criar um projeto do Databricks do Pulumi com o Python. Para ver um tutorial de uma perspectiva puramente do provedor de nuvem, confira Introdução ao Azure na documentação do Pulumi. Para ver um tutorial de uma perspectiva de linguagem com a programação em primeiro lugar, consulte Python, Node.js (JavaScript, TypeScript), Go e .NET (C#, VB, F#) na documentação do Pulumi.

Etapa 1: Criar um projeto do Pulumi

Nesta etapa, no computador de desenvolvimento local, você configura a estrutura de diretórios necessária para um projeto do Pulumi. Em seguida, você cria o projeto do Pulumi dentro dessa estrutura de diretórios.

  1. No terminal ou no PowerShell, crie um diretório vazio e alterne para ele, por exemplo:

    Unix, Linux, e macOS

    mkdir pulumi-demo
    cd pulumi-demo
    

    Windows

    md pulumi-demo
    cd pulumi-demo
    
  2. Instale o Pulumi executando o seguinte comando, dependendo do sistema operacional:

    Unix, Linux

    Instale o Pulumi no Unix ou Linux usando curl:

    curl -fsSL https://get.pulumi.com | sh
    

    MacOS

    Instale o Pulumi no macOS usando o Homebrew:

    brew install pulumi/tap/pulumi
    

    Windows

    Instale o Pulumi no Windows usando o PowerShell com permissões elevadas por meio do gerenciador de pacotes Chocolatey:

    choco install pulumi
    

    Para conhecer opções alternativas de instalação do Pulumi, consulte Baixar e instalar na documentação do Pulumi.

  3. Crie um projeto básico de Python do Pulumi executando o seguinte comando:

    pulumi new python
    

    Dica

    Você também pode criar um projeto do Pulumi em sua conta do Pulumi online (Projetos > Criar projeto). No entanto, não há nenhum modelo de projeto para o Azure Databricks.

  4. Se solicitado, pressione a tecla Enter e use o navegador da Web para entrar em sua conta do Pulumi online, se você ainda não estiver conectado. Depois de entrar, retorne ao terminal ou ao PowerShell.

  5. Quando solicitado um nome de projeto, aceite o nome de projeto padrão pulumi-demo pressionando Enter.

  6. Quando solicitada uma descrição do projeto, insira A demo Python Pulumi Databricks project e pressione Enter.

  7. Quando solicitado um nome de pilha, aceite o nome de pilha padrão dev pressionando Enter. O Pulumi cria os seguintes arquivos e subdiretórios em seu diretório pulumi-demo:

    • Pulumi.yaml, que é uma lista de configurações de seu projeto do Pulumi.
    • __main__.py, que contém o código de Python que você escreve para o projeto do Pulumi.
    • requirements.txt, que é uma lista de pacotes de código Python de suporte que o Pulumi instala para o projeto.
    • .gitignore, que é uma lista de arquivos e diretórios que o Git ignora se você quer efetuar push do projeto para um repositório Git remoto.
    • O subdiretório venv contém o código do ambiente virtual Python de suporte que o Pulumi usa para seu projeto.
  8. Execute uma implantação inicial da pilha dev do projeto executando o seguinte comando:

    pulumi up
    
  9. Quando solicitado a executar essa atualização, pressione a tecla de direção para cima para navegar até sim e pressione Enter.

  10. Copie o link Exibir ao Vivo que aparece e cole-o na barra de endereços do navegador da Web, que leva você para sua conta do Pulumi online. Os detalhes da atividade de pilha dev para seu projeto pulumi-demo são exibidos. Não há muito o que ver agora, porque ainda não há recursos na pilha. Esses recursos serão criados na próxima etapa.

Etapa 2: Criar recursos do Databricks

Nesta etapa, você usa o provedor de recursos Pulumi do Databricks para criar, no workspace existente do Azure Databricks, um notebook e um trabalho para executar esse notebook.

  1. No arquivo __main.py__ gerado pelo Pulumi, use seu editor de texto ou IDE (ambiente de desenvolvimento integrado) preferido para inserir o código a seguir. Esse código declara os recursos de Notebook e Trabalho do Databricks do Pulumi e suas configurações:

    """A Python Pulumi program"""
    
    import pulumi
    from pulumi_databricks import *
    from base64 import b64encode
    
    # Get the authenticated user's workspace home directory path and email address.
    # See https://www.pulumi.com/registry/packages/databricks/api-docs/getcurrentuser
    user_home_path     = get_current_user().home
    user_email_address = get_current_user().user_name
    
    # Define the name prefix to prepend to the resource names that are created
    # for the Notebook and Job resources. To do this, you can use a Pulumi
    # configuration value instead of hard-coding the name prefix in this file.
    #
    # To set a Pulumi configuration value, run the following command, which sets
    # a "resource-prefix" configuration value to "pulumi-demo" in the
    # associated "Pulumi.<stack-name>.yaml" configuration file:
    #
    # pulumi config set resource-prefix "pulumi-demo"
    #
    # For more information about defining and retrieving hard-coded values, see
    # https://www.pulumi.com/docs/intro/concepts/config
    config = pulumi.config.Config()
    resource_prefix = config.require('resource-prefix')
    
    # Define cluster resource settings.
    node_type = config.require('node-type')
    
    # Create a Notebook resource.
    # See https://www.pulumi.com/registry/packages/databricks/api-docs/notebook
    # This example adds a single cell to the notebook, which is constructed from
    # a single base64-encoded string. In practice, you would replace this:
    #
    # language       = "PYTHON",
    # content_base64 = b64encode(b"display(spark.range(10))").decode("UTF-8")
    #
    # With this:
    #
    # source         = "path/to/local/my-notebook.py"
    #
    # To provide more notebook content easier and faster. Also, the notebook's language
    # is automatically detected. If you specify a notebook path, be sure that it does
    # not end in .ipynb, as Pulumi relies on the workspace import API, which doesn't
    # rely on any specific extensions such as .ipynb in the notebook path.
    notebook = Notebook(
      resource_name  = f"{resource_prefix}-notebook",
      path           = f"{user_home_path}/Pulumi/{resource_prefix}-notebook.py",
      language       = 'PYTHON',
      content_base64 = b64encode(b"display(spark.range(10))").decode("UTF-8")
    )
    
    # Export the URL of the Notebook, so that you can easily browse to it later.
    # See https://www.pulumi.com/docs/intro/concepts/stack/#outputs
    pulumi.export('Notebook URL', notebook.url)
    
    # Create a Job resource.
    # See https://www.pulumi.com/registry/packages/databricks/api-docs/job
    # This job uses the most recent Databricks Runtime long-term support (LTS)
    # runtime programmatic version ID at the time this article was first published,
    # which is 14.3.x-scala2.12. You can replace this with a later version.
    job = Job(
      resource_name = f"{resource_prefix}-job",
      name = f"{resource_prefix}-job",
      tasks = [
        JobTaskArgs(
          task_key = f"{resource_prefix}-task",
          new_cluster   = JobNewClusterArgs(
            num_workers   = 1,
            spark_version = "14.3.x-scala2.12",
            node_type_id  = node_type
          ),
          notebook_task = JobNotebookTaskArgs(
            notebook_path = f"{user_home_path}/Pulumi/{resource_prefix}-notebook.py"
          )
        )
      ],
      email_notifications = JobEmailNotificationsArgs(
        on_successes = [ user_email_address ],
        on_failures  = [ user_email_address ]
      )
    )
    
    # Export the URL of the Job, so that you can easily browse to it later.
    # See https://www.pulumi.com/docs/intro/concepts/stack/#outputs
    pulumi.export('Job URL', job.url)
    
  2. Defina um valor de configuração chamado resource-prefix e defina-o como o valor embutido em código pulumi-demo executando o comando a seguir. O Pulumi usa esse valor de configuração para nomear o notebook e o trabalho:

    pulumi config set resource-prefix "pulumi-demo"
    

    O Pulumi cria um arquivo chamado Pulumi.dev.yaml no mesmo diretório que o arquivo __main__.py e adiciona o seguinte código a este arquivo YAML:

    config:
      pulumi-demo:resource_prefix: pulumi-demo
    

    O uso de valores de configuração permite que o código seja mais modular e reutilizável. Agora, outra pessoa pode reutilizar seu arquivo __main__.py e definir um valor diferente para a variável resource_prefix sem alterar o conteúdo do arquivo __main__.py.

  3. Defina um valor de configuração chamado node-type e defina-o como o valor embutido em código executando o comando a seguir. O Pulumi usa esse valor de configuração para determinar o tipo de cluster em que o trabalho é executado.

    pulumi config set node-type "Standard_D3_v2"
    

    Agora, o conteúdo do arquivo Pulumi.dev.yaml tem a seguinte aparência:

    config:
      pulumi-demo:node-type: Standard_D3_v2
      pulumi-demo:resource-prefix: pulumi-demo
    
  4. Para permitir que o Pulumi se autentique em seu workspace do Azure Databricks, defina valores de configuração específicos do Azure Databricks executando os comandos relacionados. Por exemplo, para a autenticação de token de acesso pessoal do Azure Databricks, execute os comandos a seguir. Nestes comandos:

    • Substitua <workspace-instance-url> por sua URL por workspace, por exemplo, https://adb-1234567890123456.7.azuredatabricks.net.

    • Substitua <access-token> pelo valor de seu token de acesso. Especifique a opção --secret. Isso instrui o Pulumi a criptografar seu token de acesso como uma melhor prática de segurança.

      Observação

      Por padrão, o Pulumi usa uma chave de criptografia por pilha gerenciada pelo Serviço Pulumi e um sal por valor para criptografar os valores. Para usar um provedor de criptografia alternativo, consulte Configurando a Criptografia de Segredos na documentação do Pulumi.

    pulumi config set databricks:host "<workspace-instance-url>"
    pulumi config set databricks:token "<access-token>" --secret
    

    Agora, o conteúdo do arquivo Pulumi.dev.yaml tem a seguinte aparência:

    config:
      databricks:host: <your-workspace-instance-url>
      databricks:token:
        secure: <an-encrypted-version-of-your-access-token>
      pulumi-demo:node-type: Standard_D3_v2
      pulumi-demo:resource_prefix: pulumi-demo
    

    Para usar um tipo de autenticação diferente do Azure Databricks, consulte os Requisitos. Consulte também a Configuração no repositório do Databricks para Pulumi no GitHub.

Etapa 3: Implantar os recursos

Nesta etapa, você ativa um ambiente virtual de Python que o Pulumi fornece para seu projeto como parte da execução do modelo de projeto de Python do Pulumi. Esse ambiente virtual ajuda a garantir que você esteja usando a versão correta do Python, do Pulumi e do provedor de recursos Pulumi do Databricks juntos. Várias estruturas de ambiente virtual do Python estão disponíveis, como venv, virtualenv e pipenv. Este artigo e o modelo de projeto de Python do Pulumi usam venv. venv já está incluído com Python. Para obter mais informações, confira Como criar ambientes virtuais.

  1. Ative o ambiente virtual do Python executando o seguinte comando do diretório pulumi-demo, dependendo do sistema operacional e do tipo de shell:

    Plataforma Shell Comando para ativar o ambiente virtual
    Unix, Linux, macOS bash/zsh source venv/bin/activate
    fish source venv/bin/activate.fish
    csh/tcsh source venv/bin/activate.csh
    PowerShell Core venv/bin/Activate.ps1
    Windows cmd.exe venv\Scripts\activate.bat
    PowerShell venv\Scripts\Activate.ps1
  2. Instale o provedor de recursos Pulumi do Databricks do PyPI (Índice de Pacotes do Python) em seu ambiente virtual executando o seguinte comando:

    pip install pulumi-databricks
    

    Observação

    Algumas instalações de pip podem exigir que você use pip3 em vez de pip. Nesse caso, substitua pip por pip3 neste artigo.

  3. Visualize os recursos que o Pulumi criará executando o seguinte comando:

    pulumi preview
    

    Se erros forem relatados, corrija-os e execute o comando novamente.

    Para ver um relatório detalhado em sua conta do Pulumi online do que o Pulumi fará, copie o link Exibir ao Vivo que aparece e cole-o na barra de endereços do navegador da Web.

  4. Crie e implante os recursos no workspace do Azure Databricks executando o seguinte comando:

    pulumi up
    
  5. Quando solicitado a executar essa atualização, pressione a tecla de direção para cima para navegar até sim e pressione Enter. Se erros forem relatados, corrija-os e execute o comando novamente.

  6. Para ver um relatório detalhado em sua conta do Pulumi online do que o Pulumi fez, copie o link Exibir ao Vivo que aparece e cole-o na barra de endereços do navegador da Web.

Etapa 4: Interagir com os recursos

Nesta etapa, você executa o trabalho no workspace do Azure Databricks, que executa o notebook especificado.

  1. Para exibir o notebook que o trabalho executará em seu workspace, copie o link da URL do Notebook que aparece e cole-o na barra de endereços do navegador da Web.
  2. Para ver o trabalho que executa o notebook em seu workspace, copie o link da URL do Trabalho que aparece e cole-o na barra de endereços do navegador da Web.
  3. Para executar o trabalho, clique no botão Executar agora na página do trabalho.
  4. Quando o trabalho terminar de ser executado, para exibir os resultados da execução dele, na lista Execuções concluídas (últimos 60 dias) na página do trabalho, clique na entrada de hora mais recente na coluna Hora de Início. O painel Saída mostra o resultado da execução do código do notebook, que imprime os números de 1 a 10.

(Opcional) Etapa 5: Fazer alterações em um recurso

Nesta etapa opcional, você altera o código do notebook, reimplanta o notebook alterado e usa o trabalho para executá-lo novamente.

Se não quiser fazer nenhuma alteração no notebook, pule para a Etapa 6: Limpar.

  1. De volta ao arquivo __main.py__, altere esta linha de código:

    content_base64 = b64encode(b"display(spark.range(10))").decode("UTF-8")
    

    Faça isso e salve o arquivo:

      content_base64 = b64encode(b'''
    data = [
             { "Category": 'A', "ID": 1, "Value": 121.44 },
             { "Category": 'B', "ID": 2, "Value": 300.01 },
             { "Category": 'C', "ID": 3, "Value": 10.99 },
             { "Category": 'E', "ID": 4, "Value": 33.87}
           ]
    
    df = spark.createDataFrame(data)
    
    display(df)
    ''').decode("UTF-8")
    

    Essa alteração instrui o notebook a imprimir o conteúdo do DataFrame especificado em vez dos números de 1 a 10.

    Observação

    Verifique se as linhas de código que começam com data e terminam com ''').decode("UTF-8") estão alinhadas com a borda do editor de código. Caso contrário, o Pulumi inserirá espaço em branco adicional no notebook que poderá fazer com que o novo código Python falhe na execução.

  2. Opcionalmente, visualize o recurso que Pulumi alterará executando o seguinte comando:

    pulumi preview
    

    Se erros forem relatados, corrija-os e execute o comando novamente.

    Para ver um relatório detalhado em sua conta do Pulumi online do que o Pulumi fará, copie o link Exibir ao Vivo que aparece e cole-o na barra de endereços do navegador da Web.

  3. Implante a alteração do recurso no workspace do Azure Databricks executando o seguinte comando:

    pulumi up
    
  4. Quando solicitado a executar essa atualização, pressione a tecla de direção para cima para navegar até sim e pressione Enter. Se erros forem relatados, corrija-os e execute o comando novamente.

  5. Para ver um relatório detalhado em sua conta do Pulumi online do que o Pulumi fez, copie o link Exibir ao Vivo que aparece e cole-o na barra de endereços do navegador da Web.

  6. Para ver o notebook alterado em seu workspace, copie o link da URL do Notebook que aparece e cole-o na barra de endereços do navegador da Web.

  7. Para executar novamente o trabalho com o notebook alterado, copie o link da URL do Trabalho que aparece e cole-o na barra de endereços do navegador da Web. Em seguida, clique no botão Executar agora na página do trabalho.

  8. Quando o trabalho terminar de ser executado, para exibir os resultados da execução dele, na lista Execuções concluídas (últimos 60 dias) na página do trabalho, clique na entrada de hora mais recente na coluna Hora de Início. O painel Saída mostra o resultado da execução do código do notebook, que imprime o conteúdo do DataFrame especificado.

Etapa 6: Limpeza

Nesta etapa, você instrui o Pulumi a remover o notebook e o trabalho do workspace do Azure Databricks, bem como a remover o projeto pulumi-demo e sua pilha dev da conta do Pulumi online.

  1. Remova os recursos do workspace do Azure Databricks executando o seguinte comando:

    pulumi destroy
    
  2. Quando solicitado a executar essa remoção, pressione a tecla de direção para cima para navegar até sim e pressione Enter.

  3. Remova o projeto pulumi-demo do Pulumi e sua pilha dev de sua conta do Pulumi online executando o seguinte comando:

    pulumi stack rm dev
    
  4. Quando solicitado a executar essa remoção, digite dev e pressione Enter.

  5. Para desativar o ambiente virtual do Python venv, execute o seguinte comando:

    deactivate
    

Testando

Você pode testar o seu projeto Pulumi antes de implantá-lo. Consulte Testar programas Pulumi na documentação do Pulumi.

Para testes de unidade de projetos Pulumi baseados em Python, você pode escrever e executar testes de unidade usando a estrutura de teste unittest do Python junto com o namespace pulumi.runtime do pacote Pulumi. Para executar testes em recursos simulados, substitua chamadas para Pulumi (e para o Azure Databricks) por simulações. Consulte Testar unidades de programas Pulumi na documentação do Pulumi.

O arquivo de exemplo a seguir chamado infra.py simula uma implementação do notebook e do trabalho declarados no arquivo main.py deste artigo. Os testes de unidade neste exemplo verificam se o nome do trabalho, o destinatário do email e o conteúdo do notebook codificados em Base64 para trabalho bem-sucedido executam todos os valores esperados de retorno. Dessa forma, somente essas propriedades relacionadas são simuladas aqui com valores de exemplo. Além disso, os valores de propriedade de recurso necessários sempre devem ser fornecidos, mesmo se não planejar usá-los em seus testes de unidade. Neste exemplo, esses valores necessários são definidos como valores my-mock- aleatórios e esses valores não são testados.

# infra.py

from pulumi_databricks import (
  Notebook,
  Job,
  JobEmailNotificationsArgs
)

notebook = Notebook(
  resource_name  = 'my-mock-notebook-resource-name',
  path           = 'my-mock-notebook-path',
  content_base64 = 'ZGlzcGxheShzcGFyay5yYW5nZSgxMCkp'
)

job = Job(
  resource_name = 'my-mock-job-resource-name',
  name          = 'pulumi-demo-job',
  email_notifications = JobEmailNotificationsArgs(
    on_successes = [ 'someone@example.com' ]
  )
)

O arquivo de exemplo test_main.py a seguir testa se as propriedades relacionadas retornam seus valores esperados.

# test_main.py

import pulumi
from pulumi_databricks import *
import unittest
import infra

# Set up mocking.
class MyMocks(pulumi.runtime.Mocks):
  def new_resource(self, type_, name, inputs, provider, id_):
    return [name + '_id', inputs]

  def call(self, token, args, provider):
    return {}

pulumi.runtime.set_mocks(MyMocks())

class TestNotebookAndJob(unittest.TestCase):
  @pulumi.runtime.test
  def test_notebook(self):
    def check_notebook_content_base64(args):
      content_base64 = args
      # Does the notebook's Base64-encoded content match the expected value?
      self.assertIn('ZGlzcGxheShzcGFyay5yYW5nZSgxMCkp', content_base64)

    # Pass the mocked notebook's content_base64 property value to the test.
    return pulumi.Output.all(infra.notebook.content_base64).apply(check_notebook_content_base64)

  @pulumi.runtime.test
  def test_job(self):
    def check_job_name_and_email_onsuccesses(args):
      name, email_notifications = args
      # Does the job's name match the expected value?
      self.assertIn('pulumi-demo-job', name)
      # Does the email address for successful job runs match the expected value?
      self.assertIn('someone@example.com', email_notifications['on_successes'])

    # Pass into the test the mocked job's property values for the job's name
    # and the job's email address for successful runs.
    return pulumi.Output.all(
      infra.job.name,
      infra.job.email_notifications
    ).apply(check_job_name_and_email_onsuccesses)

Para executar esses testes e exibir seus resultados do teste, execute o seguinte comando no diretório raiz do projeto Pulumi:

python -m unittest

Para obter informações sobre outros tipos de testes que você pode executar, consulte os seguintes artigos na documentação do Pulumi:

Mais recursos