Databricks 上的最佳做法和建议的 CI/CD 工作流

CI/CD(持续集成和持续交付)已成为现代数据工程和分析的基石,因为它可确保代码更改经过集成、测试和快速可靠地部署。 Databricks 认识到您的组织偏好、现有工作流和特定技术环境可能会影响您多样化的 CI/CD 要求,并提供一个灵活的框架以支持各种 CI/CD 选项。

本页介绍了帮助你设计和构建符合独特需求和约束的可靠自定义 CI/CD 管道的最佳做法。 利用这些见解,可以加速数据工程和分析计划,提高代码质量,并降低部署失败的风险。

CI/CD 的核心原则

无论实现具体细节如何,有效的 CI/CD 管道都共享基本原则。 以下通用最佳做法适用于组织首选项、开发人员工作流和云环境,并确保在各种实现之间保持一致性,无论团队优先考虑笔记本优先开发还是基础结构即代码工作流。 采用这些原则作为防护措施,同时定制组织技术堆栈和流程的具体细节。

  • 全盘版本控制
    • 在 Git 中存储笔记本、脚本、基础结构定义(IaC)和作业配置。
    • 使用与标准开发、过渡和生产部署环境一致的分支策略(如 Gitflow)。
  • 自动测试
    • 使用库(例如适用于 Python 的 pytestScalaTest for Scala )为业务逻辑实现单元测试。
    • 使用 Databricks CLI 捆绑包验证等工具验证笔记本和工作流功能。
    • 对工作流和数据管道(例如 Spark 数据帧的 chispa)使用集成测试。
  • 使用基础结构即代码 (IaC)
    • 使用 Databricks 资产捆绑包 YAML 或 Terraform 定义群集、作业和工作区配置。
    • 参数化而不是硬编码特定于环境的设置,例如群集大小和机密。
  • 隔离环境
    • 维护单独的工作区,用于开发、过渡和生产。
    • 使用 MLflow 模型注册表 跨环境进行模型版本控制。
  • 选择与云生态系统匹配的工具:
    • Azure:Azure DevOps 和 Databricks 资产捆绑包或 Terraform。
    • AWS:GitHub Actions 和 Databricks 资产捆绑包或 Terraform。
    • GCP:云生成和 Databricks 资产捆绑包或 Terraform。
  • 监视和自动执行回滚
    • 跟踪部署成功率、作业性能和测试覆盖率。
    • 为失败的部署实现自动回滚机制。
  • 统一资产管理
    • 使用 Databricks 资产捆绑 包将代码、作业和基础结构部署为单个单元。 避免对笔记本、库和工作流进行孤立的管理。

用于 CI/CD 的 Databricks 资产捆绑包

Databricks 资产捆绑包提供了一种强大的统一方法来管理 Databricks 生态系统中的代码、工作流和基础结构,建议用于 CI/CD 管道。 通过将这些元素捆绑到单个 YAML 定义的单元中,捆绑包可以简化部署并确保跨环境的一致性。 但是,对于习惯于传统 CI/CD 工作流的用户,采用捆绑包可能需要改变思维模式。

例如,Java 开发人员用于使用 Maven 或 Gradle 生成 JAR,使用 JUnit 运行单元测试,并将这些步骤集成到 CI/CD 管道中。 同样,Python 开发人员通常将代码打包到轮子中并使用 pytest 进行测试,而 SQL 开发人员则专注于查询验证和笔记本管理。 借助捆绑包,这些工作流聚合为一种更具结构化和规范性的格式,强调捆绑代码和基础结构进行无缝部署。

以下部分探讨开发人员如何调整其工作流,以有效地利用捆绑包。

若要快速开始使用 Databricks 资产捆绑包,请尝试教程: 使用 Databricks 资产捆绑包开发作业 ,或使用 Databricks 资产捆绑开发 DLT 管道

CI/CD 源代码管理建议

实现 CI/CD 时,开发人员首先需要做出的选择是如何存储和版本化源文件。 通过捆绑包,可以轻松包含所有内容(源代码、生成项目和配置文件)并将其定位在同一源代码存储库中,但另一个选项是将捆绑配置文件与代码相关的文件分开。 选择取决于团队的工作流、项目复杂性和 CI/CD 要求,但 Databricks 建议执行以下作:

  • 对于小型项目或代码和配置之间的紧密耦合,请使用单个存储库进行代码和捆绑配置以简化工作流。
  • 对于较大的团队或独立发布周期,请使用单独的存储库进行代码和捆绑配置,但建立明确的 CI/CD 管道,以确保版本之间的兼容性。

无论您选择将代码相关的文件与捆绑配置文件放在一起还是分开,都要在上传到 Databricks 或外部存储时使用版本化的项目(例如 Git 提交哈希),以确保可追溯性和回滚功能。

用于代码和配置的单个存储库

在此方法中,源代码和捆绑配置文件都存储在同一存储库中。 这简化了工作流并确保了原子更改。

优点 缺点
  • 所有相关的项目、代码和 YAML 配置一起进行版本控制,减少了协调开销。
  • 单个拉取请求可以更新已编译的生成文件及其相应的捆绑包配置。
  • CI/CD 管道可以从单个存储库生成、测试、验证和部署。
  • 随着时间的推移,存储库可能会随着代码和配置文件而膨胀。
  • 代码和捆绑包更改需要协调发布。

示例:捆绑包中的 Python 代码

此示例在一个存储库中具有 Python 文件和捆绑文件:

databricks-dab-repo/
├── databricks.yml               # Bundle definition
├── resources/
│   ├── workflows/
│   │   ├── my_pipeline.yml      # YAML pipeline def
│   │   └── my_pipeline_job.yml  # YAML job def that runs pipeline
│   ├── clusters/
│   │   ├── dev_cluster.yml      # development cluster def
│   │   └── prod_cluster.yml     # production def
├── src/
│   ├── dlt_pipeline.ipynb       # pipeline notebook
│   └── mypython.py              # Additional Python
└── README.md

用于代码和配置的单独存储库

在此方法中,源代码驻留在一个存储库中,而捆绑配置文件则保存在另一个存储库中。 此选项非常适合大型团队或项目,其中单独的组处理应用程序开发和 Databricks 工作流管理。

优点 缺点
  • 开发代码的团队可以专注于其存储库,而数据工程团队管理捆绑配置。
  • 允许对已编译代码(例如 JAR 和捆绑配置)进行独立的发布更新和版本控制,而无需将它们耦合。
  • 每个存储库更小、更易于管理。
  • 需要在部署期间在存储库之间进行额外的协调。
  • 必须确保捆绑存储库中引用了正确的依赖项版本,例如 JAR 版本。

示例:Java 项目和捆绑包

在此示例中,Java 项目及其文件位于一个存储库中,捆绑文件位于另一个存储库中。

存储库 1:Java 文件

第一个存储库包含所有与 Java 相关的文件:

java-app-repo/
├── pom.xml                  # Maven build configuration
├── src/
│   ├── main/
│   │   ├── java/            # Java source code
│   │   │   └── com/
│   │   │       └── mycompany/
│   │   │           └── app/
│   │   │               └── App.java
│   │   └── resources/       # Application resources
│   └── test/
│       ├── java/            # Unit tests for Java code
│       │   └── com/
│       │       └── mycompany/
│       │           └── app/
│       │               └── AppTest.java
│       └── resources/       # Test-specific resources
├── target/                  # Compiled JARs and classes
└── README.md

  • 开发人员在src/main/javasrc/main/scala中编写应用程序代码。
  • 单元测试存储在 src/test/javasrc/test/scala 中。
  • 在进行拉取请求或提交时,CI/CD 管道会执行以下操作:
    • 将代码编译为 JAR,例如 target/my-app-1.0.jar
    • 将 JAR 上传到 Databricks Unity 目录卷。 请参阅 上传 JAR

存储库 2:捆绑文件

第二个存储库仅包含捆绑配置文件:

databricks-dab-repo/
├── databricks.yml               # Bundle definition
├── resources/
│   ├── jobs/
│   │   ├── my_java_job.yml  # YAML job dev
│   │   └── my_other_job.yml # Additional job definitions
│   ├── clusters/
│   │   ├── dev_cluster.yml  # development cluster def
│   │   └── prod_cluster.yml # production def
└── README.md
  • 捆绑包配置 databricks.yml 和作业定义独立进行维护。

  • databricks.yml引用上传的 JAR 项目,例如:

    - jar: /Volumes/artifacts/my-app-${{ GIT_SHA }}.)jar
    

建议的工作流如下:无论您是将代码文件与捆绑配置文件共同定位还是分开存放,建议采用以下工作流。

  1. 编译并测试代码

    • 在执行拉取请求时触发,或在提交到主分支时触发。
    • 编译代码并运行单元测试。
    • 输出带有版本号的文件,例如 my-app-1.0.jar
  2. 将编译的文件(如 JAR)上传到 Databricks Unity 目录卷并存储。

    • 将编译的文件存储在 Databricks Unity 目录卷或项目存储库(如 AWS S3 或 Azure Blob 存储)中。
    • 使用一种绑定到 Git 提交哈希或语义版本控制的版本控制方案,例如 dbfs:/mnt/artifacts/my-app-${{ github.sha }}.jar
  3. 验证捆绑包

    • 运行 databricks bundle validate 以确保 databricks.yml 配置正确。
    • 此步骤可确保提前捕获错误配置(例如缺少的库)。
  4. 部署捆绑包

    • 使用 databricks bundle deploy 将捆绑包部署到测试或生产环境。
    • databricks.yml中引用上传的已编译库。 有关引用库的信息,请参阅 Databricks 资产捆绑库依赖项

用于机器学习的 CI/CD

与传统的软件开发相比,机器学习项目引入了独特的 CI/CD 挑战。 为 ML 项目实现 CI/CD 时,可能需要考虑以下事项:

  • 多团队协调:数据科学家、工程师和 MLOps 团队通常使用不同的工具和工作流。 Databricks 将这些流程与 MLflow 统一起来用于试验跟踪,与 Delta Sharing 统一起来用于数据治理,与 Databricks 资产捆绑包统一起来用于基础结构即代码。
  • 数据和模型版本控制:ML 管道不仅需要跟踪代码,还需要训练数据架构、特征分布和模型项目。 Databricks Delta Lake 为数据版本控制提供 ACID 事务和时间旅行,而 MLflow 模型注册表处理模型世系。
  • 跨环境可重现性:ML 模型依赖于特定的数据、代码和基础结构组合。 Databricks 资产捆绑包通过 YAML 定义确保跨开发、暂存和生产环境对这些组件进行原子部署。
  • 连续重新训练和监视:模型因数据偏移而降级。 Databricks 工作流支持自动重新训练管道,而 MLflow 与 Prometheus 和 Lakehouse Monitoring 集成以实现性能跟踪。

用于 ML CI/CD 的 MLOps 堆栈

Databricks 通过 MLOps Stacks 解决 ML CI/CD 复杂性,这是一个生产级框架,它结合了 Databricks 资产捆绑、预配置的 CI/CD 工作流和模块化 ML 项目模板。 这些堆栈强制实施最佳做法,同时允许跨数据工程、数据科学和 MLOps 角色实现多团队协作的灵活性。

团队 职责 示例捆绑包组件 示例工件
数据工程师 构建 ETL 流程,确保数据质量 DLT YAML、群集策略 etl_pipeline.ymlfeature_store_job.yml
数据科学家 开发模型训练逻辑,验证指标 MLflow 项目,基于笔记本的工作流 train_model.ymlbatch_inference_job.yml
MLOps 工程师 协调部署,监视管道 环境变量,监视仪表板 databricks.ymllakehouse_monitoring.yml

ML CI/CD 协作可能如下所示:

  • 数据工程师将 ETL 管道更改提交到捆绑包,从而触发自动架构验证和过渡部署。
  • 数据科学家提交 ML 代码,该代码运行单元测试并部署到过渡工作区以进行集成测试。
  • MLOps 工程师查看验证指标,并使用 MLflow 注册表将经过审查的模型提升到生产。

有关实现详细信息,请参阅:

通过将团队与标准化捆绑包和 MLOps Stack 保持一致,组织可以简化协作,同时在整个 ML 生命周期内保持可审核性。

面向 SQL 开发人员的 CI/CD

使用 Databricks SQL 管理流式处理表和具体化视图的 SQL 开发人员可以利用 Git 集成和 CI/CD 管道来简化工作流和维护高质量的管道。 通过引入对查询的 Git 支持,SQL 开发人员可以专注于编写查询,同时利用 Git 对文件 .sql 进行版本控制,从而支持协作和自动化,而无需深入的基础结构专业知识。 此外,SQL 编辑器还支持实时协作,并与 Git 工作流无缝集成。

对于以 SQL 为中心的工作流:

  • 版本控制 SQL 文件

    • 使用 Databricks Git 文件夹或外部 Git 提供程序(例如 GitHub、Azure DevOps)将.sql文件存储在 Git 存储库中。
    • 使用分支(例如开发、过渡、生产)来管理特定于环境的更改。
  • .sql 文件集成到 CI/CD 管道中以自动执行部署:

    • 在拉取请求期间验证语法和架构更改。
    • .sql 文件部署到 Databricks SQL 工作流或作业。
  • 为环境隔离进行参数化

    • 使用文件中的变量 .sql 动态引用特定于环境的资源,例如数据路径或表名称:

      CREATE OR REFRESH STREAMING TABLE ${env}_sales_ingest AS SELECT * FROM read_files('s3://${env}-sales-data')
      
  • 计划和监视刷新

    • 使用 Databricks 作业中的 SQL 任务来计划对表和具体化视图的更新 (REFRESH MATERIALIZED VIEW view_name)。
    • 使用系统表监视刷新历史记录。

工作流可能是:

  1. 开发:在本地或 Databricks SQL 编辑器中编写和测试 .sql 脚本,然后将其提交到 Git 分支。
  2. 验证:在拉取请求期间,通过自动化的 CI 检查来验证语法和架构兼容性。
  3. 部署:合并后,使用 CI/CD 管道将.sql脚本部署到目标环境,例如 GitHub Actions 或 Azure Pipelines。
  4. 监视:使用 Databricks 仪表板和警报监控查询性能和数据实时性。

面向仪表板开发人员的 CI/CD

Databricks 支持使用 Databricks 资产捆绑包将仪表板集成到 CI/CD 工作流中。 此功能使仪表板开发人员能够:

  • 版本控制仪表板,可确保可审核性并简化团队之间的协作。
  • 在不同环境中自动部署仪表板、作业和管道,进行端到端的协调。
  • 减少手动错误,并确保在环境中一致地应用更新。
  • 在遵循 CI/CD 最佳做法的同时维护高质量的分析工作流。

对于 CI/CD 中的仪表板,请执行以下操作:

  • databricks bundle generate使用命令将现有仪表板导出为 JSON 文件,并生成包含在捆绑包中的 YAML 配置:

    resources:
      dashboards:
        sales_dashboard:
          display_name: 'Sales Dashboard'
          file_path: ./dashboards/sales_dashboard.lvdash.json
          warehouse_id: ${var.warehouse_id}
    
  • 将这些文件 .lvdash.json 存储在 Git 存储库中,以有效跟踪更改和协作。

  • 使用 databricks bundle deploy 自动在 CI/CD 管道中部署仪表板。 例如,用于部署的 GitHub Actions 步骤:

    name: Deploy Dashboard
      run: databricks bundle deploy --target=prod
    env:
      DATABRICKS_TOKEN: ${{ secrets.DATABRICKS_TOKEN }}
    
  • 例如 ${var.warehouse_id},使用变量参数化 SQL 仓库或数据源等配置,确保跨开发、过渡和生产环境无缝部署。

  • 使用此选项 bundle generate --watch 可以持续同步本地仪表板 JSON 文件以及 Databricks UI 中所做的更改。 如果发生差异,在部署时使用 --force 标志用本地版本覆盖远程仪表板。

有关捆绑包中的仪表板的信息,请参阅 仪表板资源。 有关捆绑命令的详细信息,请参阅 bundle 命令组