メインコンテンツまでスキップ

Databricks での Jenkins を使用した CI/CD

注記

この記事では、第三者が開発したJenkinsについて説明します。 プロバイダーに連絡するには、Jenkinsヘルプを参照してください

CI/CD パイプラインの管理と実行に使用できる CI/CD ツールは多数あります。 この記事では、 Jenkins 自動化サーバーの使用方法について説明します。 CI/CD は設計パターンであるため、この記事で概説する手順とステージは、各ツールのパイプライン定義言語にいくつかの変更を加えて移行する必要があります。 さらに、このパイプライン例のコードの多くは、他のツールで呼び出すことができる標準の Python コードを実行します。 Databricks の CI/CD の概要については、「 Databricks の CI/CD とは」を参照してください。

CI/CD開発ワークフロー

Databricks では、Jenkins を使用した CI/CD 開発について、次のワークフローを提案しています。

  1. リポジトリを作成するか、既存のリポジトリをサードパーティの Git プロバイダーで使用します。
  2. ローカルの開発マシンを同じサードパーティリポジトリに接続します。 手順については、サードパーティの Git プロバイダーのドキュメントを参照してください。
  3. 既存の更新されたアーティファクト (ノートブック、コード ファイル、ビルド スクリプトなど) をサード パーティのリポジトリからローカル開発マシンにプルします。
  4. 必要に応じて、ローカル開発マシンでアーティファクトを作成、更新、およびテストします。 次に、新しいアーティファクトや変更されたアーティファクトをローカルの開発マシンからサードパーティのリポジトリにプッシュします。 手順については、サードパーティの Git プロバイダーのドキュメントを参照してください。
  5. 必要に応じて、手順 3 と 4 を繰り返します。
  6. Jenkins は、サードパーティのリポジトリからアーティファクトをローカルの開発マシンや Databricks ワークスペースに自動的にプルするための統合アプローチとして定期的に使用します。ローカルの開発マシンまたは Databricks ワークスペースでコードをビルド、テスト、および実行します。テストと実行の結果の報告。 Jenkins は手動で実行することもできますが、実際の実装では、リポジトリのプルリクエストなどの特定のイベントが発生するたびに Jenkins を実行するようにサードパーティの Git プロバイダーに指示します。

この記事の残りの部分では、サンプル プロジェクトを使用して、Jenkins を使用して前述の CI/CD 開発ワークフローを実装する 1 つの方法について説明します。

ローカル開発マシンのセットアップ

この記事の例では、Jenkins を使用して、 Databricks CLIDatabricks アセット バンドル に次の操作を指示します。

  1. ローカルの開発マシンで Python wheel ファイルをビルドします。
  2. ビルドされた Python wheel ファイルを、追加の Python ファイルおよび Python ノートブックと共に、ローカル開発マシンから Databricks ワークスペースにデプロイします。
  3. アップロードした Python wheel ファイルとノートブックをそのワークスペースでテストして実行します。

この例のビルドとアップロードのステージを実行するように Databricks ワークスペースに指示するようにローカル開発マシンを設定するには、ローカル開発マシンで次の操作を行います。

ステップ 1: 必要なツールをインストールする

この手順では、 Databricks CLI、Jenkins、jq、および Python wheel ビルド ツールをローカル開発マシンにインストールします。 この例を実行するには、これらのツールが必要です。

  1. Databricks CLI バージョン 0.205 以降をまだインストールしていない場合は、インストールします。 Jenkins は Databricks CLI を使用して、この例のテストと実行の手順をワークスペースに渡します。 「Databricks CLI のインストールまたは更新」を参照してください。

  2. Jenkins をまだインストールしていない場合は、インストールして起動します。 LinuxmacOS またはWindows用の Jenkinsのインストール を参照してください。

  3. jqをインストールします。 この例では、 jq を使用して JSON 形式のコマンド出力を解析します。

  4. pip を使用して、次のコマンドで Python wheel ビルドツールをインストールします (一部のシステムでは、pipの代わりに pip3 を使用する必要がある場合があります)。

    Bash
    pip install --upgrade wheel

ステップ 2: Jenkins パイプラインを作成する

この手順では、Jenkins を使用して、この記事の例の Jenkins パイプラインを作成します。 Jenkins には、CI/CD パイプラインを作成するためのいくつかの異なるプロジェクトの種類が用意されています。 Jenkins パイプラインは、 Groovy コードを使用して Jenkins プラグインを呼び出し、設定することで、Jenkins パイプラインのステージを定義するためのインターフェイスを提供します。

Jenkins プロジェクトの種類

Jenkins で Jenkins パイプラインを作成するには:

  1. Jenkins を起動したら、Jenkins ダッシュボード から [New Item (新規アイテム )] をクリックします。
  2. [ 項目名を入力してください ] に、Jenkins パイプラインの名前 ( jenkins-demoなど) を入力します。
  3. 「パイプライン」 プロジェクト・タイプ・アイコンをクリックします。
  4. [OK] をクリックします。Jenkins パイプラインの [設定] ページが表示されます。
  5. [ パイプライン] 領域の [ 定義 ] ドロップダウン リストで、[ SCM からのパイプライン スクリプト ] を選択します。
  6. [SCM ] ドロップダウン リストで、[ Git ] を選択します。
  7. [リポジトリ URL ] に、サードパーティの Git プロバイダーによってホストされているリポジトリの URL を入力します。
  8. [ブランチ指定子] に「*/<branch-name>」と入力します。ここで、<branch-name> は、使用するリポジトリ内のブランチの名前 (例: */mainです)。
  9. [ スクリプト パス ] に「 Jenkinsfile」と入力します (まだ設定されていない場合)。 Jenkinsfileは、この記事の後半で作成します。
  10. ライトウェイトチェックアウトというタイトルのチェックボックスが既にオンになっている場合は、チェックを外してください
  11. [ 保存 ]をクリックします。

ステップ 3: Jenkins にグローバル環境変数を追加する

この手順では、3 つのグローバル環境変数を Jenkins に追加します。 Jenkins は、これらの環境変数を Databricks CLI に渡します。 Databricks CLI では、Databricks ワークスペースで認証するために、これらの環境変数の値が必要です。 この例では OAuth サービスプリンシパルに M2M (Machine-to-Machine) 認証を使用します (ただし、他の認証タイプも使用できます)。 ワークスペースの OAuthM2M 認証を設定するには、「DatabricksDatabricksを使用してサービスプリンシパルを使用して リソースへの無人アクセスを承認OAuth する」を参照してください。

この例の 3 つのグローバル環境変数は次のとおりです。

  • DATABRICKS_HOSTで、 https://で始まる Databricks ワークスペース URL に設定します。 ワークスペースインスタンス名、URL、ID を参照してください。
  • DATABRICKS_CLIENT_IDは、サービスプリンシパルのクライアント ID (アプリケーション ID とも呼ばれる) に設定します。
  • DATABRICKS_CLIENT_SECRETで、サービスプリンシパルの Databricks OAuth シークレットに設定します。

Jenkins でグローバル環境変数を設定するには、Jenkins ダッシュボード から次の操作を行います。

  1. サイドバーで、「 Jenkinsを管理 」をクリックします。
  2. システム構成 」セクションで、「 システム 」をクリックします。
  3. [グローバル プロパティ ] セクションで、タイル化された [環境変数 ] ボックスをオンにします。
  4. [追加 ] をクリックし、環境変数 の [名前 ] と [値 ] を入力します。追加の環境変数ごとにこれを繰り返します。
  5. 環境変数の追加が完了したら、[ 保存 ] をクリックして Jenkins ダッシュボード に戻ります。

Jenkins パイプラインの設計

Jenkins には、CI/CD パイプラインを作成するためのいくつかの異なるプロジェクトの種類が用意されています。 この例では、Jenkins パイプラインを実装します。 Jenkins パイプラインは、 Groovy コードを使用して Jenkins プラグインを呼び出し、設定することで、Jenkins パイプラインのステージを定義するためのインターフェイスを提供します。

Jenkins パイプライン定義は Jenkinsfile というテキスト ファイルに記述し、このファイルはプロジェクトのソース コントロール リポジトリにチェックインされます。 詳細については、「 Jenkins パイプライン」を参照してください。 この記事の例の Jenkins パイプラインを次に示します。 この例では、 Jenkinsfileで、次のプレースホルダーを置き換えます。

  • <user-name><repo-name> は、サードパーティの Git プロバイダーによってホストされているユーザーのユーザー名とリポジトリ名に置き換えます。この記事では、例として GitHub の URL を使用します。
  • <release-branch-name> をリポジトリ内のリリースブランチの名前に置き換えてください。 たとえば、これは mainです。
  • <databricks-cli-installation-path> を、Databricks CLI がインストールされているローカル開発マシン上のパスに置き換えます。たとえば、macOS では /usr/local/bin.
  • <jq-installation-path>jq がインストールされているローカル開発マシン上のパスに置き換えてください。 たとえば、macOSでは /usr/local/bin になります。
  • この例では、ワークスペースで作成された Databricks ジョブを一意に識別するのに役立つ文字列に <job-prefix-name> を置き換えます。 たとえば、これは jenkins-demoです。
  • BUNDLETARGET は、この記事の後半で定義する Databricks Asset Bundle ターゲットの名前である devに設定されていることに注意してください。実際の実装では、これを独自のバンドル ターゲットの名前に変更します。 バンドル ターゲットの詳細については、この記事の後半で説明します。

リポジトリのルートに追加する必要がある Jenkinsfileを次に示します。

Groovy
// Filename: Jenkinsfile
node {
def GITREPOREMOTE = "https://github.com/<user-name>/<repo-name>.git"
def GITBRANCH = "<release-branch-name>"
def DBCLIPATH = "<databricks-cli-installation-path>"
def JQPATH = "<jq-installation-path>"
def JOBPREFIX = "<job-prefix-name>"
def BUNDLETARGET = "dev"

stage('Checkout') {
git branch: GITBRANCH, url: GITREPOREMOTE
}
stage('Validate Bundle') {
sh """#!/bin/bash
${DBCLIPATH}/databricks bundle validate -t ${BUNDLETARGET}
"""
}
stage('Deploy Bundle') {
sh """#!/bin/bash
${DBCLIPATH}/databricks bundle deploy -t ${BUNDLETARGET}
"""
}
stage('Run Unit Tests') {
sh """#!/bin/bash
${DBCLIPATH}/databricks bundle run -t ${BUNDLETARGET} run-unit-tests
"""
}
stage('Run Notebook') {
sh """#!/bin/bash
${DBCLIPATH}/databricks bundle run -t ${BUNDLETARGET} run-dabdemo-notebook
"""
}
stage('Evaluate Notebook Runs') {
sh """#!/bin/bash
${DBCLIPATH}/databricks bundle run -t ${BUNDLETARGET} evaluate-notebook-runs
"""
}
stage('Import Test Results') {
def DATABRICKS_BUNDLE_WORKSPACE_ROOT_PATH
def getPath = "${DBCLIPATH}/databricks bundle validate -t ${BUNDLETARGET} | ${JQPATH}/jq -r .workspace.file_path"
def output = sh(script: getPath, returnStdout: true).trim()

if (output) {
DATABRICKS_BUNDLE_WORKSPACE_ROOT_PATH = "${output}"
} else {
error "Failed to capture output or command execution failed: ${getPath}"
}

sh """#!/bin/bash
${DBCLIPATH}/databricks workspace export-dir \
${DATABRICKS_BUNDLE_WORKSPACE_ROOT_PATH}/Validation/Output/test-results \
${WORKSPACE}/Validation/Output/test-results \
-t ${BUNDLETARGET} \
--overwrite
"""
}
stage('Publish Test Results') {
junit allowEmptyResults: true, testResults: '**/test-results/*.xml', skipPublishingChecks: true
}
}

この記事の残りの部分では、この Jenkins パイプラインの各ステージと、そのステージで Jenkins を実行するためのアーティファクトとコマンドの設定方法について説明します。

サードパーティのリポジトリから最新のアーティファクトをプルする

この Jenkins パイプラインの最初のステージである Checkout ステージは、次のように定義されます。

Groovy
stage('Checkout') {
git branch: GITBRANCH, url: GITREPOREMOTE
}

このステージでは、Jenkins がローカル開発マシンで使用する作業ディレクトリに、サードパーティの Git リポジトリからの最新のアーティファクトがあることを確認します。 通常、Jenkins はこの作業ディレクトリを <your-user-home-directory>/.jenkins/workspace/<pipeline-name>に設定します。 これにより、同じローカル開発マシン上で、Jenkins がサードパーティの Git リポジトリから使用するアーティファクトとは別に、開発中のアーティファクトの独自のコピーを保持できます。

Databricks アセット バンドルの検証

この Jenkins パイプラインの 2 番目のステージである Validate Bundle ステージは、次のように定義されます。

Groovy
stage('Validate Bundle') {
sh """#!/bin/bash
${DBCLIPATH}/databricks bundle validate -t ${BUNDLETARGET}
"""
}

このステージでは、アーティファクトをテストおよび実行するためのワークフローを定義する Databricks Asset Bundle が構文的に正しいことを確認します。 Databricks Asset Bundles は、単に バンドル と呼ばれ、完全なデータ分析を表現し、MLプロジェクトをソースファイルの集合体として表現することを可能にします。「Databricks アセットバンドルとは」を参照してください。

この記事のバンドルを定義するには、ローカル コンピューター上のクローンされたリポジトリのルートに databricks.yml という名前のファイルを作成します。 この例 databricks.yml ファイルでは、次のプレースホルダーを置き換えます。

  • <bundle-name> をバンドルの一意のプログラム名に置き換えます。たとえば、これは jenkins-demoです。
  • この例では、ワークスペースで作成された Databricks ジョブを一意に識別するのに役立つ文字列に <job-prefix-name> を置き換えます。 たとえば、これは jenkins-demoです。 Jenkinsfile の JOBPREFIX 値と一致する必要があります。
  • <spark-version-id> を、ジョブ クラスターの Databricks Runtime バージョン ID (13.3.x-scala2.12 など) に置き換えます。
  • <cluster-node-type-id> をジョブ クラスターのノード タイプ ID に置き換えます (例: n2-highmem-4)。
  • targetsマッピングのdevは、Jenkinsfile のBUNDLETARGETと同じであることに注意してください。バンドル・ターゲットは、ホストおよび関連するデプロイメント動作を指定します。

以下は、この例が正しく動作するためにリポジトリのルートに追加する必要がある databricks.yml ファイルです。

YAML
# Filename: databricks.yml
bundle:
name: <bundle-name>

variables:
job_prefix:
description: A unifying prefix for this bundle's job and task names.
default: <job-prefix-name>
spark_version:
description: The cluster's Spark version ID.
default: <spark-version-id>
node_type_id:
description: The cluster's node type ID.
default: <cluster-node-type-id>

artifacts:
dabdemo-wheel:
type: whl
path: ./Libraries/python/dabdemo

resources:
jobs:
run-unit-tests:
name: ${var.job_prefix}-run-unit-tests
tasks:
- task_key: ${var.job_prefix}-run-unit-tests-task
new_cluster:
spark_version: ${var.spark_version}
node_type_id: ${var.node_type_id}
num_workers: 1
spark_env_vars:
WORKSPACEBUNDLEPATH: ${workspace.root_path}
notebook_task:
notebook_path: ./run_unit_tests.py
source: WORKSPACE
libraries:
- pypi:
package: pytest
run-dabdemo-notebook:
name: ${var.job_prefix}-run-dabdemo-notebook
tasks:
- task_key: ${var.job_prefix}-run-dabdemo-notebook-task
new_cluster:
spark_version: ${var.spark_version}
node_type_id: ${var.node_type_id}
num_workers: 1
data_security_mode: SINGLE_USER
spark_env_vars:
WORKSPACEBUNDLEPATH: ${workspace.root_path}
notebook_task:
notebook_path: ./dabdemo_notebook.py
source: WORKSPACE
libraries:
- whl: '/Workspace${workspace.root_path}/files/Libraries/python/dabdemo/dist/dabdemo-0.0.1-py3-none-any.whl'
evaluate-notebook-runs:
name: ${var.job_prefix}-evaluate-notebook-runs
tasks:
- task_key: ${var.job_prefix}-evaluate-notebook-runs-task
new_cluster:
spark_version: ${var.spark_version}
node_type_id: ${var.node_type_id}
num_workers: 1
spark_env_vars:
WORKSPACEBUNDLEPATH: ${workspace.root_path}
spark_python_task:
python_file: ./evaluate_notebook_runs.py
source: WORKSPACE
libraries:
- pypi:
package: unittest-xml-reporting

targets:
dev:
mode: development

databricks.yml ファイルの詳細については、「アセットバンドルの設定Databricks」を参照してください。

バンドルをワークスペースにデプロイする

ジェンキンス・パイプラインの第3段階は、 Deploy Bundleと題され、次のように定義されています。

Groovy
stage('Deploy Bundle') {
sh """#!/bin/bash
${DBCLIPATH}/databricks bundle deploy -t ${BUNDLETARGET}
"""
}

このステージでは、次の 2 つのことを行います。

  1. ファイル内の マッピングがartifact databricks.yml``whlに設定されているため、指定した場所にあるDatabricksCLI Python wheelsetup.pyファイルを使用して ファイルをビルドするように に指示します。
  2. Python wheel ファイルがローカル開発マシンでビルドされた後、Databricks CLI はビルドされた Python wheel ファイルを、指定した Python ファイルおよびノートブックと共に Databricks ワークスペースにデプロイします。デフォルトにより、 Databricks Asset Bundles は Python wheel ファイルと他のファイルを /Workspace/Users/<your-username>/.bundle/<bundle-name>/<target-name> にデプロイします。

Python wheel ファイルを databricks.yml ファイルで指定されたとおりにビルドできるようにするには、ローカル マシン上のクローン リポジトリのルートに次のフォルダーとファイルを作成します。

ノートブックが実行される Python wheel ファイルのロジックと単体テストを定義するには、 addcol.pytest_addcol.pyという名前の 2 つのファイルを作成し、リポジトリの Libraries フォルダー内の python/dabdemo/dabdemo という名前のフォルダー構造に次のように視覚化して追加します (省略記号はリポジトリ内の省略されたフォルダーを示します。 簡潔にするため):

├── ...
├── Libraries
│ └── python
│ └── dabdemo
│ └── dabdemo
│ ├── addcol.py
│ └── test_addcol.py
├── ...

addcol.pyファイルには、後で Python wheel ファイルに組み込まれ、 Databricks クラスターにインストールされるライブラリ関数が含まれています。 そうです リテラルが入力された新しい列を Apache Spark DataFrame に追加する単純な関数です。

Python
# Filename: addcol.py
import pyspark.sql.functions as F

def with_status(df):
return df.withColumn("status", F.lit("checked"))

test_addcol.pyファイルには、モックDataFrameオブジェクトをwith_status関数に渡すためのテストが含まれています。これは、addcol.py定義されています。ザ 次に、result が、予期される値を含む DataFrame オブジェクトと比較されます。 値が一致する場合 (この場合は一致します)、テストは成功します。

Python
# Filename: test_addcol.py
import pytest
from pyspark.sql import SparkSession
from dabdemo.addcol import *

class TestAppendCol(object):

def test_with_status(self):
spark = SparkSession.builder.getOrCreate()

source_data = [
("paula", "white", "paula.white@example.com"),
("john", "baer", "john.baer@example.com")
]

source_df = spark.createDataFrame(
source_data,
["first_name", "last_name", "email"]
)

actual_df = with_status(source_df)

expected_data = [
("paula", "white", "paula.white@example.com", "checked"),
("john", "baer", "john.baer@example.com", "checked")
]
expected_df = spark.createDataFrame(
expected_data,
["first_name", "last_name", "email", "status"]
)

assert(expected_df.collect() == actual_df.collect())

Databricks CLIでこのライブラリ コードを Python wheel ファイルに正しくパッケージ化するには、前の 2 つのファイルと同じフォルダに __init__.py__main__.py という名前の 2 つのファイルを作成します。また、次のように視覚化された python/dabdemo フォルダーに setup.py という名前のファイルを作成します (省略記号は簡潔にするために省略されたフォルダーを示します)。

├── ...
├── Libraries
│ └── python
│ └── dabdemo
│ ├── dabdemo
│ │ ├── __init__.py
│ │ ├── __main__.py
│ │ ├── addcol.py
│ │ └── test_addcol.py
│ └── setup.py
├── ...

__init__.pyファイルには、ライブラリのバージョン番号と作成者が含まれています。<my-author-name>を自分の名前に置き換えます。

Python
# Filename: __init__.py
__version__ = '0.0.1'
__author__ = '<my-author-name>'

import sys, os

sys.path.append(os.path.join(os.path.dirname(__file__), "..", ".."))

__main__.pyファイルには、ライブラリのエントリポイントが含まれています。

Python
# Filename: __main__.py
import sys, os

sys.path.append(os.path.join(os.path.dirname(__file__), "..", ".."))

from addcol import *

def main():
pass

if __name__ == "__main__":
main()

setup.pyファイルには、ライブラリを Python wheel ファイルにビルドするための追加設定が含まれています。 <my-url><my-author-name>@<my-organization>、および <my-package-description> を意味のある値に置き換えます。

Python
# Filename: setup.py
from setuptools import setup, find_packages

import dabdemo

setup(
name = "dabdemo",
version = dabdemo.__version__,
author = dabdemo.__author__,
url = "https://<my-url>",
author_email = "<my-author-name>@<my-organization>",
description = "<my-package-description>",
packages = find_packages(include = ["dabdemo"]),
entry_points={"group_1": "run=dabdemo.__main__:main"},
install_requires = ["setuptools"]
)

Python wheelのコンポーネント ロジックをテストする

この Jenkins パイプラインの 4 番目のステージである Run Unit Tests ステージでは、 pytest を使用してライブラリのロジックをテストし、ビルドどおりに動作することを確認します。 このステージは、次のように定義されます。

Groovy
stage('Run Unit Tests') {
sh """#!/bin/bash
${DBCLIPATH}/databricks bundle run -t ${BUNDLETARGET} run-unit-tests
"""
}

このステージでは、Databricks CLI を使用してノートブック ジョブを実行します。 このジョブは、ファイル名 run-unit-test.pyの Python ノートブックを実行します。 このノートブックは、ライブラリのロジックに対して pytest 実行されます。

この例の単体テストを実行するには、次の内容を含む run_unit_tests.py という名前の Python ノートブック ファイルを、ローカル マシン上のクローン リポジトリのルートに追加します。

Python
# Databricks notebook source

# COMMAND ----------

# MAGIC %sh
# MAGIC
# MAGIC mkdir -p "/Workspace${WORKSPACEBUNDLEPATH}/Validation/reports/junit/test-reports"

# COMMAND ----------

# Prepare to run pytest.
import sys, pytest, os

# Skip writing pyc files on a readonly filesystem.
sys.dont_write_bytecode = True

# Run pytest.
retcode = pytest.main(["--junit-xml", f"/Workspace{os.getenv('WORKSPACEBUNDLEPATH')}/Validation/reports/junit/test-reports/TEST-libout.xml",
f"/Workspace{os.getenv('WORKSPACEBUNDLEPATH')}/files/Libraries/python/dabdemo/dabdemo/"])

# Fail the cell execution if there are any test failures.
assert retcode == 0, "The pytest invocation failed. See the log for details."

ビルドされたPython wheelを使用する

この Jenkins パイプラインの 5 番目のステージ ( Run Notebookと題されている) では、次のように、ビルドされた Python wheel ファイル内のロジックを呼び出す Python ノートブックが実行されます。

Groovy
stage('Run Notebook') {
sh """#!/bin/bash
${DBCLIPATH}/databricks bundle run -t ${BUNDLETARGET} run-dabdemo-notebook
"""
}

このステージでは、 Databricks CLIが実行され、ノートブック ジョブを実行するようにワークスペースに指示します。 このノートブックは、DataFrame オブジェクトを作成し、ライブラリの with_status 関数に渡し、結果を出力して、ジョブの実行結果を報告します。 ノートブックを作成するには、 dabdaddemo_notebook.py という名前の Python ノートブック ファイルを、次の内容で、ローカル開発マシン上のクローン リポジトリのルートに追加します。

Python
# Databricks notebook source

# COMMAND ----------

# Restart Python after installing the wheel.
dbutils.library.restartPython()

# COMMAND ----------

from dabdemo.addcol import with_status

df = (spark.createDataFrame(
schema = ["first_name", "last_name", "email"],
data = [
("paula", "white", "paula.white@example.com"),
("john", "baer", "john.baer@example.com")
]
))

new_df = with_status(df)

display(new_df)

# Expected output:
#
# +------------+-----------+-------------------------+---------+
# │first_name │last_name │email │status |
# +============+===========+=========================+=========+
# │paula │white │paula.white@example.com │checked |
# +------------+-----------+-------------------------+---------+
# │john │baer │john.baer@example.com │checked |
# +------------+-----------+-------------------------+---------+

ノートブック ジョブの実行結果を評価する

この Jenkins パイプラインの 6 番目のステージである Evaluate Notebook Runs ステージでは、前のノートブック ジョブの実行結果が評価されます。 このステージは、次のように定義されます。

Groovy
stage('Evaluate Notebook Runs') {
sh """#!/bin/bash
${DBCLIPATH}/databricks bundle run -t ${BUNDLETARGET} evaluate-notebook-runs
"""
}

このステージでは、 Databricks CLIが実行され、ワークスペースに Python ファイル ジョブを実行するように指示します。 この Python ファイルは、ノートブック ジョブの実行の失敗と成功の基準を決定し、この失敗または成功の結果を報告します。 次の内容を含む evaluate_notebook_runs.py という名前のファイルを、ローカル開発マシンのクローンされたリポジトリのルートに作成します。

Python
import unittest
import xmlrunner
import json
import glob
import os

class TestJobOutput(unittest.TestCase):

test_output_path = f"/Workspace${os.getenv('WORKSPACEBUNDLEPATH')}/Validation/Output"

def test_performance(self):
path = self.test_output_path
statuses = []

for filename in glob.glob(os.path.join(path, '*.json')):
print('Evaluating: ' + filename)

with open(filename) as f:
data = json.load(f)

duration = data['tasks'][0]['execution_duration']

if duration > 100000:
status = 'FAILED'
else:
status = 'SUCCESS'

statuses.append(status)
f.close()

self.assertFalse('FAILED' in statuses)

def test_job_run(self):
path = self.test_output_path
statuses = []

for filename in glob.glob(os.path.join(path, '*.json')):
print('Evaluating: ' + filename)

with open(filename) as f:
data = json.load(f)
status = data['state']['result_state']
statuses.append(status)
f.close()

self.assertFalse('FAILED' in statuses)

if __name__ == '__main__':
unittest.main(
testRunner = xmlrunner.XMLTestRunner(
output = f"/Workspace${os.getenv('WORKSPACEBUNDLEPATH')}/Validation/Output/test-results",
),
failfast = False,
buffer = False,
catchbreak = False,
exit = False
)

テスト結果をインポートして報告する

この Jenkins パイプラインの 7 番目のステージ ( Import Test Resultsという名前) では、Databricks CLI を使用して、ワークスペースからローカルの開発マシンにテスト結果を送信します。 Publish Test Resultsというタイトルの 8 番目の最終ステージでは、junit Jenkins プラグインを使用してテスト結果を Jenkins に公開します。これにより、テスト結果のステータスに関連するレポートとダッシュボードを視覚化できます。 これらのステージは、次のように定義されます。

Groovy
stage('Import Test Results') {
def DATABRICKS_BUNDLE_WORKSPACE_FILE_PATH
def getPath = "${DBCLIPATH}/databricks bundle validate -t ${BUNDLETARGET} | ${JQPATH}/jq -r .workspace.file_path"
def output = sh(script: getPath, returnStdout: true).trim()

if (output) {
DATABRICKS_BUNDLE_WORKSPACE_FILE_PATH = "${output}"
} else {
error "Failed to capture output or command execution failed: ${getPath}"
}

sh """#!/bin/bash
${DBCLIPATH}/databricks workspace export-dir \
${DATABRICKS_BUNDLE_WORKSPACE_FILE_PATH}/Validation/Output/test-results \
${WORKSPACE}/Validation/Output/test-results \
--overwrite
"""
}
stage('Publish Test Results') {
junit allowEmptyResults: true, testResults: '**/test-results/*.xml', skipPublishingChecks: true
}

ジェンキンスのテスト結果

すべてのコード変更をサードパーティのリポジトリにプッシュします

これで、クローンしたリポジトリの内容をローカル開発マシンにプッシュします。これで、サードパーティのリポジトリにプッシュできます。 プッシュする前に、まずクローンしたリポジトリの .gitignore ファイルに次のエントリを追加する必要があります。これは、内部の Databricks アセット バンドル作業ファイル、検証レポート、Python ビルド ファイル、Python キャッシュをサードパーティ リポジトリにプッシュする必要がないためです。 通常、新しい検証レポートを再生成し、最新の Python wheel を Databricks ワークスペースに組み込む必要があります。古い可能性のある検証レポートや Python wheel ビルドを使用するのではなく、次のようにします。

.databricks/
.vscode/
Libraries/python/dabdemo/build/
Libraries/python/dabdemo/__pycache__/
Libraries/python/dabdemo/dabdemo.egg-info/
Validation/

実行 your Jenkins パイプライン

これで、Jenkins パイプラインを手動で実行する準備が整いました。 これを行うには、Jenkinsダッシュボード から次の操作を行います。

  1. Jenkins パイプラインの名前をクリックします。
  2. サイドバーの「 今すぐ構築 」をクリックします。
  3. 結果を表示するには、最新のパイプライン実行( #1など)をクリックし、[ コンソール出力 ]をクリックします。

この時点で、CI/CD パイプラインは統合とデプロイのサイクルを完了しています。 このプロセスを自動化することで、効率的で一貫性があり、反復可能なプロセスによってコードがテストおよびデプロイされていることを確認できます。 リポジトリのプルリクエストなど、特定のイベントが発生するたびにJenkinsを実行するようにサードパーティのGitプロバイダーに指示するには、サードパーティのGitプロバイダーのドキュメントを参照してください。