概要
Databricks の CI (Continuous Integration(継続的インテグレーション)) パイプラインを Azure DevOps (Pipelines) にて構築する手順を紹介します。Databricks ノートブックで開発することを前提としており、Databricks Repos における Databricks Workspace 上ではノートブック形式となるが Git 上では Python ファイルとなる仕様に基づいたパイプラインとなっております。継続的な品質保証に必要となる、テスト結果の発行だけでなく、コードカバレッジの発行も実施できるようになっております。
本手順で構築できるパイプラインの概要は次のようになっております。
- カレントブランチのコードに対してテストを、PR 時や CI トリガーなどにより並列で実行が可能
- パイプライン実行の並列性を高めるために、テストケースの作成方法の工夫、Databricks Workflows 上でのテスト実行、及び、Azure Pipelines の エージェントレスジョブの活用を実施
-
tests/unit
配下のテストケースのテストをDatabricks 上でノートブックとしてのテスト実行だけでなく、Python ファイルとしてのテスト実行も行うことで、パイプライン実行後にテスト結果とコードカバレッジの確認が可能
パイプラインの全体像を、次の画像で示します。
Azure DevOps(Piplines)上で、テスト結果やコードカバレッジを下記画像のように確認できます。
Azure DevOps のパブリックプロジェクトとして公開しており、下記の URL にてパイプラインの実行結果を確認できます。
本手順で利用するレポジトリーは、 Github 上に配置してあります。
本記事の位置付け
次の開発ガイドシリーズにおける DevOps 分野の1記事であり、リンク先には記事にて記事の全体像を整理している。
GroupID | 分野 |
---|---|
T10 | Spark概要 |
T20 | データエンジニアリング |
T30 | データ品質チェック |
T40 | データサイエンス |
T50 | メタデータデプロイ |
T60 | テスト |
T70 | DevOps |
Azure Pipeline 定義
1. 処理概要
Databricks CI パイプラインとしては、次の処理を実施します。
- ノートブックでの単体テストの実施
- Databricks Repos を作成
- Databricks Workflows(Notbook Type) でのテストの実施とテスト結果の発行
- Databricks Workflows(Notbook Type) の作成と実行
- Databricks Workflows 処理の完了確認
- テスト結果(JUnit 形式の XML ファイル)を Azure Pipelines に発行
- Python スクリプトでの単体テストの実施
- コードを DBFS にコピー
- Databricks Workflows(Python script type)でのテストの実施とテスト結果の発行
- Databricks Workflows(Python script type)の作成と実行
- Databricks Workflows 処理の完了確認
- テスト結果(JUnit 形式の XML ファイル)を Azure Pipelines に発行
- 単体テストのコードカバレッジの発行
- コードカバレッジ結果の統合と発行
- DBFS からコードカバレッジ結果(.coverage)をコピー
- コードカバレッジ結果の統合( combine )
- コードカバレッジ結果を Cobertura 形式の XML ファイルへ変換
- コードカバレッジ結果を発行
- コードカバレッジ結果の統合と発行
- 事後処理
- DBFS 上のコード等を削除
- Databricks Repos 上のディレクトリを削除
2. 定義概要
Azure Pipelines にてci__execute_unit_test_on_databricks.yml
を CI パイプラインとして登録しており、複数の YAML ファイルを定義しています。YAML ファイルにおける処理フローと留意事項を下記に示します。
ci__execute_unit_test_on_databricks.yml
- 処理フロー
-
templates/jobs/create_databricks_repos_for_test.yml
を呼び出し、Databricks Repos を作成 -
templates/stages/execute_databricks_workflows_for_test_by_notebook_type.yml
を呼び出し、Databricks Workflows(Notbook Type) でのテストの実施とテスト結果の発行 -
templates/jobs/copy_codes_to_dbfs.yml
を呼び出し、コードを DBFS 上にコピー -
templates/stages/execute_databricks_workflows_for_test_by_python_type.yml
を呼び出し、Databricks Workflows(Python script type)でのテストの実施とテスト結果の発行 -
templates/jobs/publish_code_coverage.yml
を呼び出し、コードカバレッジ結果の統合と発行 -
templates/jobs/delete_codes_on_dbfs.yml
を呼び出し、DBFS 上のコード等を削除 -
templates/jobs/delete_codes_on_dbfs.yml
を呼び出し、Databricks Repos 上のディレクトリを削除
-
- 留意事項
- パイプライン外部で定義する必要がある変数をコメントアウトしており、
databricks_dev
変数グループを定義することが前提 - template により他 YAML ファイルを呼び出す
- ノートブックでのテスト、および、Python スクリプトでのテストは複数バージョンの実施が可能
- パイプライン外部で定義する必要がある変数をコメントアウトしており、
templates/jobs/create_databricks_repos_for_test.yml
- 処理フロー
- Databricks repos API により、Databricks 上の Repos 上にディレクトリを作成
- Databricks repos API により、Databricks 上の Repos を作成
- Databricks repos API により、Databricks 上の Repos における、ブランチ、あるいは、タグを更新
- 留意事項
- 特になし
templates/stages/execute_databricks_workflows_for_test_by_notebook_type.yml
- 処理フロー
-
templates/jobs/execute_databricks_notobook_task_workflows_for_unit_test.yml
を呼び出し、Databricks Workflows の作成と実行を実施 -
templates/jobs/check_status_on_databricks_workflows.yml
を呼び出し、Databricks Workflows の完了を監視 -
templates/jobs/publish_test_results_of_unittest.yml
を呼び出し、テスト結果のファイルを DBFS からコピーし、Azure Pipelines に公開 -
templates/jobs/delete_databricks_workflows.yml
を呼び出し、Databricks Workflows を削除
-
- 留意事項
-
/runs/submit
API が共有ジョブクラスターをサポートしていないため(ドキュメントへのリンク)、Databricks Workflows の作成・実行・削除を実施
-
templates/stages/execute_databricks_workflows_for_test_by_python_type.yml
- 処理フロー
-
templates/jobs/execute_databricks_python_task_workflows_for_unit_test.yml
を呼び出し、Databricks Workflows の作成と実行を実施 -
templates/jobs/check_status_on_databricks_workflows.yml
を呼び出し、Databricks Workflowsの完了を監視 -
templates/jobs/publish_test_results_of_pytest.yml
を呼び出し、テスト結果のファイルを DBFS からコピーし、Azure Pipelines に公開 -
templates/jobs/delete_databricks_workflows.yml
を呼び出し、Databricks Workflows を削除
-
- 留意事項
-
/runs/submit
API が共有ジョブクラスターをサポートしていないため(ドキュメントへのリンク)、Databricks Workflows の作成・実行・削除を実施
-
templates/jobs/execute_databricks_notobook_task_workflows_for_unit_test.yml
- 処理フロー
- Databricks REST API により、1タスクをもつ Databricks Workflows を作成
- Databricks REST API により、前の手順で作成した Databricks Workflows を実行
- 留意事項
- 特になし
templates/jobs/execute_databricks_python_task_workflows_for_unit_test.yml
- 処理フロー
- Databricks REST API により、10タスクをもつ Databricks Workflows を作成
- Databricks REST API により、前の手順で作成した Databricks Workflows を実行
- 留意事項
- 特になし
templates/jobs/check_status_on_databricks_workflows.yml
- 処理フロー
- Databricks REST API により、Databrikcs Workflows が成功(
SUCCESS
)したことを確認 - Databrikcs Workflows が実行されない(
state.life_cycle_state
がRUNNING
、あるいは、TERMINATED
とならない)場合にエラー終了とする -
SUCCESS
とならない場合には、エージェントレスジョブのDelay
タスクにより指定分(delay_for_minutes
パラメータ値)待機後に、再度ステータスを確認(最大20回) - 20回待機しても処理が完了しない場合にエラー終了となる
- Databricks REST API により、Databrikcs Workflows が成功(
- 留意事項
- カウンターによるループ処理を実施できないため、
job_names
パラメータ項目によるループ処理を実施
- カウンターによるループ処理を実施できないため、
templates/jobs/publish_test_results_of_unittest
- 処理フロー
- databricks-cli や pytest などの Python ライブラリをインストール
- Databricks CLI にて、DBFS から テスト結果のファイルをコピー
-
PublishTestResults
タスクにより、テスト結果を表示
- 留意事項
- pytest により出力されるテスト結果ファイルの命名規則に合わせて発行を行う
- テスト実施環境ごとにまとめるためにテスト環境のテスト結果ごとに発行処理を行う
templates/jobs/publish_test_results_of_pytest.yml
- 処理フロー
- databricks-cli や pytest などの Python ライブラリをインストール
- Databricks CLI にて、DBFS から テスト結果のファイルをコピー
-
PublishTestResults
タスクにより、テスト結果を表示
- 留意事項
- unittest-xml-reporting による出力されるテスト結果ファイルの命名規則に合わせて発行を行う
- テスト実施環境ごとにまとめるためにテスト環境のテスト結果ごとに発行処理を行う
templates/jobs/publish_code_coverage.yml
- 処理フロー
- databricks-cli や pytest などの Python ライブラリをインストール
- Databricks CLI にて、DBFS から コードカバレッジ結果のファイルをコピー
-
Coverage
コマンドにて、複数のコードカバレッジ結果ファイルを単一ファイルに統合し、Cobertura 形式の XML ファイルに変換 -
PublishCodeCoverageResults
タスクにより、コードカバレッジ結果を表示
- 留意事項
-
PublishCodeCoverageResults
タスクにて、複数ファイルの公開に対応していない(ドキュメントへの)ため、単一ファイルに統合 - カバレッジ生成対象ディレクトリ(
--cov
)とカバレッジ発行時の設定(PublishCodeCoverageResults
におけるpathToSources
)を同一のディレクトリに設定 - Azure Pipelines 上で コードカバレッジ結果を確認する際には、日本語は文字化けする場合がある
-
templates/jobs/delete_databricks_workflows.yml
- 処理フロー
- Databricks REST API にて、Databricks Workflows を削除
- 留意事項
-
condition
をalways
に設定することで、パイプラインの成功有無に関わらず処理を実行
-
templates/jobs/delete_codes_on_dbfs.yml
- 処理フロー
- Databricks REST API にて、DBFS 上に配置したファイルを削除
- 留意事項
-
condition
をalways
に設定することで、パイプラインの成功有無に関わらず処理を実行
-
templates/jobs/delete_databricks_respos_for_test.yml
- 処理フロー
- Databricks REST API にて、Repos 上に作成したディレクトリを削除
- 留意事項
-
condition
をalways
に設定することで、パイプラインの成功有無に関わらず処理を実行
-
3. CI パイプラインにおける Databricks ランタイムの変更手順
3-1. ノートブックでの単体テストにおける Databricks ランタイムの変更手順
1. Databricks Runtime のバージョン変更
templates/stages/execute_databricks_workflows_for_test_by_notebook_type.yml
を呼び出す際の変数を変更する。
- template: templates/stages/execute_databricks_workflows_for_test_by_notebook_type.yml
parameters:
job_suffix_name: notebook_11_5
databricks_cluster_runtime_version: 11.5.x-scala2.12
test_results_path: $(TEST_CODE_PATH_ON_DBFS)/$(PIPELINE_ID)/.test_results/notebook_11_5
delay_for_minutes: 5
依存関係がある GetAndPublishCodeCoverage
ステージの dependsOn
の項目(GetAndPublishTestResults_*
)を変更する。
- stage: GetAndPublishCodeCoverage
displayName: Get and publish code coverage
condition: succeededOrFailed()
dependsOn:
- GetAndPublishTestResults_python_9_1
- GetAndPublishTestResults_python_10_4
- GetAndPublishTestResults_notebook_11_5
jobs:
- template: templates/jobs/publish_code_coverage.yml
2. ノートブックでの単体テスト
templates/stages/execute_databricks_workflows_for_test_by_notebook_type.yml
を呼び出すテンプレートを追加。
- template: templates/stages/execute_databricks_workflows_for_test_by_notebook_type.yml
parameters:
job_suffix_name: notebook_11_5
databricks_cluster_runtime_version: 11.5.x-scala2.12
test_results_path: $(TEST_CODE_PATH_ON_DBFS)/$(PIPELINE_ID)/.test_results/notebook_11_5
delay_for_minutes: 5
依存関係がある GetAndPublishCodeCoverage
ステージの dependsOn
に項目(GetAndPublishTestResults_*
)を追加する。
- stage: GetAndPublishCodeCoverage
displayName: Get and publish code coverage
condition: succeededOrFailed()
dependsOn:
- GetAndPublishTestResults_python_9_1
- GetAndPublishTestResults_python_10_4
- GetAndPublishTestResults_notebook_10_4
- GetAndPublishTestResults_notebook_11_5
jobs:
- template: templates/jobs/publish_code_coverage.yml
3-2. Python スクリプトでの単体テストの実における Databricks ランタイムの変更手順
1. Databricks Runtime のバージョン変更
templates/stages/execute_databricks_workflows_for_test_by_notebook_type.yml
を呼び出す際の変数を変更する。
- template: templates/stages/execute_databricks_workflows_for_test_by_python_type.yml
parameters:
job_suffix_name: python_11_5
databricks_cluster_runtime_version: 11.5.x-scala2.12
delay_for_minutes: 5
依存関係がある GetAndPublishCodeCoverage
ステージの dependsOn
の項目(GetAndPublishTestResults_*
)を変更する。
- stage: GetAndPublishCodeCoverage
displayName: Get and publish code coverage
condition: succeededOrFailed()
dependsOn:
- GetAndPublishTestResults_python_10_4
- GetAndPublishTestResults_python_11_5
- GetAndPublishTestResults_notebook_10_4
jobs:
- template: templates/jobs/publish_code_coverage.yml
2. ノートブックでの単体テスト
templates/stages/execute_databricks_workflows_for_test_by_notebook_type.yml
を呼び出すテンプレートを追加。
- template: templates/stages/execute_databricks_workflows_for_test_by_python_type.yml
parameters:
job_suffix_name: python_11_5
databricks_cluster_runtime_version: 11.5.x-scala2.12
delay_for_minutes: 5
依存関係がある GetAndPublishCodeCoverage
ステージの dependsOn
に項目(GetAndPublishTestResults_*
)を追加する。
- stage: GetAndPublishCodeCoverage
displayName: Get and publish code coverage
condition: succeededOrFailed()
dependsOn:
- GetAndPublishTestResults_python_9_1
- GetAndPublishTestResults_python_10_4
- GetAndPublishTestResults_python_11_5
- GetAndPublishTestResults_notebook_10_4
jobs:
- template: templates/jobs/publish_code_coverage.yml
構築手順
0. 事前準備
1. 変数の設定について
変数グループ、あるいは、Pipeline にて、次の変数を設定。
# | 変数名 | 設定値例 | 概要 |
---|---|---|---|
1 | DATABRICKS_WORKSPACE_URL | tps://adb-5555555555555555.19.azuredatabricks.net | Databricks Workspace URL を指定。 |
2 | DATABRICKS_TOKEN | dapi1234 | Databricks トークン を指定。 |
3 | TARGET_TEST_PATH | tests/unit | Python script type の Databricks Workflows を実行する際のテストケースを保持したディレクトリを指定。 |
4 | TEST_MAIN_NOTEBOOK_PATH | tests/unit/main__ut__v1 | Notebook Type の Databricks Workflows を実行するノートブックのパスを指定。 |
次の変数は、YAML 上で定義しており、必要に応じて変更。
# | 変数名 | 設定値例 | 概要 |
---|---|---|---|
5 | PIPELINE_ID | $(System.TeamProjectId)$(System.DefinitionId)$(Build.BuildNumber) | パイプライン実行時の一意の値を指定。 |
6 | TEST_CODE_PATH_ON_DBFS | /FileStore/unit | テスト実行時に利用する DBFS 上のディレクトリを指定。 |