Pulumi Databricks 资源提供程序

注意

本文介绍了 Databricks 既不提供也不支持的 Pulumi。 若要联系提供商,请参阅 Pulumi 支持

本文介绍如何使用 Python 和 Pulumi(第三方基础结构即代码 (IaC))平台,该平台使你能够通过使用熟悉的编程语言、工具和工程实践来创建、部署和管理 Azure Databricks 资源。 尽管本文介绍如何使用 Python 和 Pulumi Databricks 资源提供程序,但 Pulumi 除了支持用于 Azure Databricks 的 Python 外,还支持其他语言,包括 TypeScript、JavaScript、Go 和 C#。

Pulumi Databricks 资源提供程序基于 Databricks Terraform 提供程序。 有关详细信息,请参阅 Terraform 云

要求

  • Pulumi 帐户。 如果还没有 Pulumi 帐户,请注册 Pulumi。 Pulumi 免费供个人使用,并为团队提供免费层。

  • Python 3.6 或更高版本。 要检查是否已安装 Python,请从终端或使用 PowerShell 运行 python --version 命令。 安装 Python(如果尚未安装)。

    注意

    Python 的某些安装可能要求使用 python3 而不是 python。 如果是这样,请在本文中用 python 替换 python3

  • Azure Databricks 每工作区 URL,例如 https://adb-1234567890123456.7.databricks.azure.cn

  • Azure Databricks 访问凭据。 Pulumi Databricks 项目支持以下 Azure Databricks 身份验证类型:

以下步骤演示如何使用 Python 创建 Pulumi Databricks 项目。 有关纯云提供商优先角度的教程,请参阅 Pulumi 文档中的 Azure 入门。 有关编程语言优先角度的教程,请参阅 Pulumi 文档中的 PythonNode.js(JavaScript 和 TypeScript)Go.NET(C#、VB 和 F#)

步骤 1:创建 Pulumi 项目

在此步骤中,将在本地开发计算机上为 Pulumi 项目设置必要的目录结构。 然后在此目录结构中创建 Pulumi 项目。

  1. 从终端或使用 PowerShell 创建一个空目录,然后切换到该目录,例如:

    Unix、linux 和 macOS

    mkdir pulumi-demo
    cd pulumi-demo
    

    Windows

    md pulumi-demo
    cd pulumi-demo
    
  2. 通过运行以下命令安装 Pulumi,具体取决于操作系统:

    Unix、Linux

    在 Unix 或 Linux 上使用 curl 安装 Pulumi:

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

    MacOS

    在 macOS 上使用 Homebrew 安装 Pulumi:

    brew install pulumi/tap/pulumi
    

    Windows

    通过 Chocolatey 包管理器使用具有提升权限的 PowerShell 在 Windows 上安装 Pulumi:

    choco install pulumi
    

    有关其他 Pulumi 安装选项,请参阅 Pulumi 文档中的下载和安装

  3. 运行以下命令创建一个基本的 Python Pulumi 项目:

    pulumi new python
    

    提示

    还可以从 Pulumi 联机帐户(“项目”>“创建项目”)创建 Pulumi 项目。 但是,Azure Databricks 没有项目模板。

  4. 如果出现提示,请按 Enter,然后使用 Web 浏览器登录到 Pulumi 联机帐户(如果尚未登录)。 登录后,返回到终端或 PowerShell。

  5. 提示输入“项目名称”时,通过 Enter 接受 pulumi-demo 的默认项目名称。

  6. 提示输入“项目说明”时,输入 A demo Python Pulumi Databricks project 并按 Enter。

  7. 提示输入“堆栈名称”时,通过按 Enter 接受 dev 的默认堆栈名称。 Pulumi 在 pulumi-demo 目录中创建了以下文件和子目录:

    • Pulumi.yaml,它是 Pulumi 项目的设置列表。
    • __main__.py,其中包含为 Pulumi 项目编写的 Python 代码。
    • requirements.txt,它是 Pulumi 为项目安装的支持 Python 代码包的列表。
    • .gitignore,它是文件和目录列表,如果要将此项目推送到远程 Git 存储库中,Git 会忽略这些文件和目录。
    • venv 子目录包含 Pulumi 用于项目的支持 Python 虚拟环境代码。
  8. 运行以下命令来执行项目的 dev 堆栈的初始部署:

    pulumi up
    
  9. 提示执行此更新时,按向上键导航到“是”,然后按 Enter。

  10. 复制显示的“实时查看”链接并将其粘贴到 Web 浏览器的地址栏中,这会将你转到 Pulumi 联机帐户。 其中将显示 pulumi-demo 项目的 dev 堆栈的活动详细信息。 你现在看不到太多内容,因为堆栈中还没有任何资源。 将在下一步中创建这些资源。

步骤 2:创建 Databricks 资源

在此步骤中,使用 Pulumi Databricks 资源提供程序在现有的 Azure Databricks 工作区中创建一个笔记本和一个作业来运行该笔记本。

  1. 在 Pulumi 生成的 __main.py__ 文件中,使用首选的文本编辑器或集成开发环境 (IDE) 输入以下代码。 此代码声明 Pulumi Databricks Notebook作业资源及其设置:

    """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. 通过运行以下命令,定义一个名为 resource-prefix 的配置值,并将其设置为 pulumi-demo 的硬编码值。 Pulumi 使用此配置值来命名笔记本和作业:

    pulumi config set resource-prefix "pulumi-demo"
    

    Pulumi 在与 __main__.py 文件相同的目录中创建一个名为 Pulumi.dev.yaml 的文件,并将以下代码添加到此 YAML 文件中:

    config:
      pulumi-demo:resource_prefix: pulumi-demo
    

    使用配置值可以使代码更加模块化和更可重用化。 现在,其他人可以重用 __main__.py 文件,并为 resource_prefix 变量定义不同的值,而无需更改 __main__.py 文件的内容。

  3. 通过运行以下命令,定义一个名为 node-type 的配置值,并将其设置为以下的硬编码值。 Pulumi 使用此配置值来确定作业运行的群集类型。

    pulumi config set node-type "Standard_D3_v2"
    

    现在,Pulumi.dev.yaml 文件的内容如下所示:

    config:
      pulumi-demo:node-type: Standard_D3_v2
      pulumi-demo:resource-prefix: pulumi-demo
    
  4. 若要使 Pulumi 能够使用 Azure Databricks 工作区进行身份验证,请通过运行相关命令,定义特定于 Azure Databricks 的配置值。 例如,对于 Azure Databricks 个人访问令牌身份验证,请运行以下命令。 在这些命令中:

    • <workspace-instance-url> 替换为每工作区 URL,例如 https://adb-1234567890123456.7.databricks.azure.cn

    • <access-token> 替换为访问令牌的值。 确保指定 --secret 选项。 这将指示 Pulumi 将访问令牌加密为安全最佳做法。

      备注

      默认情况下,Pulumi 使用由 Pulumi 服务管理的每堆栈加密密钥和每值盐来加密值。 若要使用替代加密提供程序,请参阅 Pulumi 文档中的配置机密加密

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

    现在,Pulumi.dev.yaml 文件的内容如下所示:

    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
    

    若要使用其他 Azure Databricks 身份验证类型,请参阅要求。 另请参阅 GitHub 的 Pulumi Databricks 存储库中的配置

步骤 3:部署资源

在此步骤中,将激活 Pulumi 为项目提供的 Python 虚拟环境,作为运行 Pulumi Python 项目模板的一部分。 此虚拟环境有助于确保同时使用正确版本的 Python、Pulumi 和 Pulumi Databricks 资源提供程序。 有多个可用的 Python 虚拟环境框架,例如 venvvirtualenvpipenv。 本文和 Pulumi Python 项目模板使用 venvvenv 已包含在 Python 中。 有关详细信息,请参阅创建虚拟环境

  1. 根据操作系统和 shell 类型,从 pulumi-demo 目录运行以下命令来激活 Python 虚拟环境:

    平台 Shell 激活虚拟环境的命令
    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. 运行以下命令,将 Pulumi Databricks 资源提供程序Python 包索引 (PyPI) 安装到虚拟环境中:

    pip install pulumi-databricks
    

    注意

    pip 的某些安装可能要求使用 pip3 而不是 pip。 如果是这样,请在本文中用 pip 替换 pip3

  3. 通过运行以下命令预览 Pulumi 将创建的资源:

    pulumi preview
    

    如果报告了任何错误,请修复它们,然后再次运行该命令。

    若要查看 Pulumi 联机帐户中有关 Pulumi 将执行的操作的详细报告,请复制显示的“实时查看”链接并将其粘贴到 Web 浏览器的地址栏中。

  4. 运行以下命令,创建资源并将其部署到 Azure Databricks 工作区:

    pulumi up
    
  5. 提示执行此更新时,按向上键导航到“是”,然后按 Enter。 如果报告了任何错误,请修复它们,然后再次运行该命令。

  6. 若要查看 Pulumi 联机帐户中有关 Pulumi 已执行的操作的详细报告,请复制显示的“实时查看”链接并将其粘贴到 Web 浏览器的地址栏中。

步骤 4:与资源交互

在此步骤中,将在运行指定笔记本的 Azure Databricks 工作区中运行作业。

  1. 若要查看作业将在工作区中运行的笔记本,请复制显示的“笔记本 URL”链接并将其粘贴到 Web 浏览器的地址栏中。
  2. 若要查看在工作区中运行笔记本的作业,请复制显示的“作业 URL”链接并将其粘贴到 Web 浏览器的地址栏中。
  3. 若要运行作业,请单击作业页上的“立即运行”按钮。
  4. 作业运行结束后,若要查看作业运行的结果,请在作业页上的“已完成的运行(过去 60 天)”列表中,单击“开始时间”列中最近的时间条目。 “输出”窗格显示运行笔记本代码的结果,输出数字 1 到 10。

(可选)步骤 5:对资源进行更改

在此可选步骤中,请更改笔记本的代码、重新部署已更改的笔记本,然后使用作业重新运行已更改的笔记本。

如果不想对笔记本进行任何更改,请跳到步骤 6:清理

  1. 回到 __main.py__ 文件,更改以下代码行:

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

    将其更改为以下内容,然后保存文件:

      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")
    

    此更改指示笔记本输出指定 DataFrame 的内容,而不是数字 1 到 10。

    注意

    确保以 data 开始、以 ''').decode("UTF-8") 结束的代码行与代码编辑器的边缘对齐。 否则,Pulumi 将会在笔记本中插入额外的空格,这可能会导致新的 Python 代码无法运行。

  2. (可选)通过运行以下命令预览 Pulumi 将更改的资源:

    pulumi preview
    

    如果报告了任何错误,请修复它们,然后再次运行该命令。

    若要查看 Pulumi 联机帐户中有关 Pulumi 将执行的操作的详细报告,请复制显示的“实时查看”链接并将其粘贴到 Web 浏览器的地址栏中。

  3. 运行以下命令,将资源更改部署到 Azure Databricks 工作区:

    pulumi up
    
  4. 提示执行此更新时,按向上键导航到“是”,然后按 Enter。 如果报告了任何错误,请修复它们,然后再次运行该命令。

  5. 若要查看 Pulumi 联机帐户中有关 Pulumi 已执行的操作的详细报告,请复制显示的“实时查看”链接并将其粘贴到 Web 浏览器的地址栏中。

  6. 若要查看工作区中已更改的笔记本,请复制显示的“笔记本 URL”链接并将其粘贴到 Web 浏览器的地址栏中。

  7. 若要使用已更改的笔记本返回作业,请复制显示的“作业 URL”链接并将其粘贴到 Web 浏览器的地址栏中。 然后单击作业页上的“立即运行”按钮。

  8. 作业运行结束后,若要查看作业运行的结果,请在作业页上的“已完成的运行(过去 60 天)”列表中,单击“开始时间”列中最近的时间条目。 “输出”窗格显示运行笔记本代码的结果,输出指定数据帧的内容。

步骤 6:清理

在此步骤中,指示 Pulumi 从 Azure Databricks 工作区中删除笔记本和作业,同时从 Pulumi 联机帐户删除 pulumi-demo 项目及其 dev 堆栈。

  1. 运行以下命令从 Azure Databricks 工作区中删除资源:

    pulumi destroy
    
  2. 提示执行此删除时,按向上键导航到“是”,然后按 Enter。

  3. 运行以下命令,从 Pulumi 联机帐户删除 Pulumi pulumi-demo 项目及其 dev 堆栈:

    pulumi stack rm dev
    
  4. 提示执行此删除时,键入 dev 并按 Enter。

  5. 若要停用 venv Python 虚拟环境,请运行以下命令:

    deactivate
    

测试

你可以在部署 Pulumi 项目之前对其进行测试。 请参阅 Pulumi 文档中的测试 Pulumi 程序

对于基于 Python 的 Pulumi 项目的单元测试,可以使用 Python 测试框架 unittest 以及 Pulumi 包的 pulumi.runtime 命名空间来编写和运行单元测试。 若要针对模拟资源运行测试,可以使用模拟来替换对 Pulumi(和 Azure Databricks)的调用。 请参阅 Pulumi 文档中的对 Pulumi 程序进行单元测试

名为 infra.py 的以下示例文件模拟本文的 main.py 文件中声明的笔记本和作业的实现。 此示例中的单元测试检查笔记本的 Base64 编码内容、作业的名称以及作业成功运行的电子邮件收件人是否全部返回预期值。 因此,此处仅使用示例值模拟那些相关属性。 此外,始终应该提供必需的资源属性值,即使你不打算在单元测试中使用它们。 在此示例中,这些必需值设置为随机 my-mock- 值,并且未测试这些值。

# 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' ]
  )
)

以下示例文件 test_main.py 测试相关属性是否返回了预期值。

# 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)

若要运行这些测试并显示其测试结果,请从 Pulumi 项目的根目录运行以下命令:

python -m unittest

有关可运行的其他测试类型的信息,请参阅 Pulumi 文档中的以下文章:

更多资源