CI/CD(持续集成和持续交付)已成为现代数据工程和分析的基石,因为它可确保代码更改经过集成、测试和快速可靠地部署。 Databricks 认识到您的组织偏好、现有工作流和特定技术环境可能会影响您多样化的 CI/CD 要求,并提供一个灵活的框架以支持各种 CI/CD 选项。
本页介绍了帮助你设计和构建符合独特需求和约束的可靠自定义 CI/CD 管道的最佳做法。 利用这些见解,可以加速数据工程和分析计划,提高代码质量,并降低部署失败的风险。
CI/CD 的核心原则
无论实现具体细节如何,有效的 CI/CD 管道都共享基本原则。 以下通用最佳做法适用于组织首选项、开发人员工作流和云环境,并确保在各种实现之间保持一致性,无论团队优先考虑笔记本优先开发还是基础结构即代码工作流。 采用这些原则作为防护措施,同时定制组织技术堆栈和流程的具体细节。
- 全盘版本控制
- 在 Git 中存储笔记本、脚本、基础结构定义(IaC)和作业配置。
- 使用与标准开发、过渡和生产部署环境一致的分支策略(如 Gitflow)。
- 自动测试
- 使用库(例如适用于 Python 的 pytest 和 ScalaTest 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 提交哈希),以确保可追溯性和回滚功能。
用于代码和配置的单个存储库
在此方法中,源代码和捆绑配置文件都存储在同一存储库中。 这简化了工作流并确保了原子更改。
优点 | 缺点 |
---|---|
|
|
示例:捆绑包中的 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 工作流管理。
优点 | 缺点 |
---|---|
|
|
示例: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/java
或src/main/scala
中编写应用程序代码。 - 单元测试存储在
src/test/java
或src/test/scala
中。 - 在进行拉取请求或提交时,CI/CD 管道会执行以下操作:
- 将代码编译为 JAR,例如
target/my-app-1.0.jar
。 - 将 JAR 上传到 Databricks Unity 目录卷。 请参阅 上传 JAR。
- 将代码编译为 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
建议的 CI/CD 工作流
建议的工作流如下:无论您是将代码文件与捆绑配置文件共同定位还是分开存放,建议采用以下工作流。
编译并测试代码
- 在执行拉取请求时触发,或在提交到主分支时触发。
- 编译代码并运行单元测试。
- 输出带有版本号的文件,例如
my-app-1.0.jar
。
将编译的文件(如 JAR)上传到 Databricks Unity 目录卷并存储。
- 将编译的文件存储在 Databricks Unity 目录卷或项目存储库(如 AWS S3 或 Azure Blob 存储)中。
- 使用一种绑定到 Git 提交哈希或语义版本控制的版本控制方案,例如
dbfs:/mnt/artifacts/my-app-${{ github.sha }}.jar
。
验证捆绑包
- 运行
databricks bundle validate
以确保databricks.yml
配置正确。 - 此步骤可确保提前捕获错误配置(例如缺少的库)。
- 运行
部署捆绑包
- 使用
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.yml 、feature_store_job.yml |
数据科学家 | 开发模型训练逻辑,验证指标 | MLflow 项目,基于笔记本的工作流 |
train_model.yml 、batch_inference_job.yml |
MLOps 工程师 | 协调部署,监视管道 | 环境变量,监视仪表板 |
databricks.yml 、lakehouse_monitoring.yml |
ML CI/CD 协作可能如下所示:
- 数据工程师将 ETL 管道更改提交到捆绑包,从而触发自动架构验证和过渡部署。
- 数据科学家提交 ML 代码,该代码运行单元测试并部署到过渡工作区以进行集成测试。
- MLOps 工程师查看验证指标,并使用 MLflow 注册表将经过审查的模型提升到生产。
有关实现详细信息,请参阅:
- MLOps Stacks 捆绑包:捆绑包初始化和部署的分步指南。
- MLOps Stacks GitHub 存储库:用于训练、推理和 CI/CD 的预配置模板。
通过将团队与标准化捆绑包和 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
)。 - 使用系统表监视刷新历史记录。
- 使用 Databricks 作业中的 SQL 任务来计划对表和具体化视图的更新 (
工作流可能是:
- 开发:在本地或 Databricks SQL 编辑器中编写和测试
.sql
脚本,然后将其提交到 Git 分支。 - 验证:在拉取请求期间,通过自动化的 CI 检查来验证语法和架构兼容性。
- 部署:合并后,使用 CI/CD 管道将.sql脚本部署到目标环境,例如 GitHub Actions 或 Azure Pipelines。
- 监视:使用 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
命令组。