Uwaga
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Uwaga / Notatka
W tym artykule opisano usługę Jenkins, która jest opracowywana przez inną firmę. Aby skontaktować się z dostawcą, zobacz Pomoc usługi Jenkins.
Istnieje wiele narzędzi CI/CD, których można użyć do zarządzania i uruchamiania potoków CI/CD. W tym artykule pokazano, jak używać serwera automatyzacji Jenkins . CI/CD jest wzorcem projektowym, więc kroki i etapy opisane w tym artykule można przenieść z drobnymi zmianami do języka definicji potoku w każdym narzędziu. Ponadto większość kodu w tym przykładowym potoku uruchamia standardowy kod języka Python, który można wywołać w innych narzędziach. Aby zapoznać się z omówieniem ciągłej integracji/ciągłego wdrażania w usłudze Azure Databricks, zobacz Ciągła integracja/ciągłe wdrażanie w usłudze Azure Databricks.
Aby uzyskać informacje na temat korzystania z usługi Azure DevOps z usługą Azure Databricks, zobacz Ciągła integracja i ciągłe dostarczanie w usłudze Azure Databricks przy użyciu usługi Azure DevOps.
Przepływ pracy CI/CD (ciągła integracja/ciągłe dostarczanie)
Usługa Databricks sugeruje następujący przepływ pracy na potrzeby programowania ciągłej integracji/ciągłego wdrażania za pomocą usługi Jenkins:
- Utwórz repozytorium lub użyj istniejącego repozytorium z zewnętrznym dostawcą Git.
- Połącz lokalną maszynę programową z tym samym repozytorium innej firmy. Aby uzyskać instrukcje, sprawdź dokumentację zewnętrznego dostawcy Git.
- Pobierz wszystkie istniejące zaktualizowane artefakty (takie jak notesy, pliki kodu i skrypty kompilacji) z repozytorium innej firmy w dół na lokalną maszynę deweloperzą.
- Zgodnie z potrzebami utwórz, zaktualizuj i przetestuj artefakty na lokalnej maszynie dewelopera. Następnie wypchnij wszystkie nowe i zmienione artefakty z lokalnej maszyny deweloperskiej do zewnętrznego repozytorium. Aby uzyskać instrukcje, zapoznaj się z dokumentacją dostawcy zewnętrznego Git.
- Powtórz kroki 3 i 4 zgodnie z potrzebami.
- Użyj narzędzia Jenkins okresowo jako zintegrowanego podejścia do automatycznego ściągania artefaktów z repozytorium innej firmy na lokalną maszynę deweloperzą lub obszar roboczy usługi Azure Databricks; kompilowanie, testowanie i uruchamianie kodu na lokalnym komputerze deweloperskim lub w obszarze roboczym usługi Azure Databricks; oraz raportowanie wyników testów i przebiegów. Chociaż można uruchomić narzędzie Jenkins ręcznie, w rzeczywistych implementacjach należy poinstruować dostawcę usługi Git innej firmy, aby uruchamiał narzędzie Jenkins za każdym razem, gdy wystąpi określone zdarzenie, takie jak żądanie ściągnięcia repozytorium.
W pozostałej części tego artykułu użyto przykładowego projektu do opisania jednego ze sposobów użycia narzędzia Jenkins do zaimplementowania poprzedniego przepływu pracy tworzenia ciągłej integracji/ciągłego wdrażania.
Aby uzyskać informacje na temat korzystania z usługi Azure DevOps zamiast serwera Jenkins, zobacz Ciągła integracja i dostarczanie w usłudze Azure Databricks przy użyciu usługi Azure DevOps.
Konfiguracja lokalnej maszyny dewelopera
W tym przykładzie użyto narzędzia Jenkins w celu poinstruowania interfejsu wiersza polecenia usługi Databricks i pakietów zasobów usługi Databricks w celu wykonania następujących czynności:
- Skompiluj plik wheel języka Python na lokalnej maszynie dewelopera.
- Wdróż skompilowany plik wheel języka Python wraz z dodatkowymi plikami języka Python i notatnikami języka Python ze swojej lokalnej maszyny deweloperskiej do obszaru roboczego usługi Azure Databricks.
- Przetestuj i uruchom przekazany plik koła języka Python i notesy w tym obszarze roboczym.
Aby skonfigurować lokalną maszynę dewelopera w celu poinstruowania obszaru roboczego usługi Azure Databricks w celu wykonania etapów kompilacji i przekazywania na potrzeby tego przykładu, wykonaj następujące czynności na lokalnej maszynie dewelopera:
Krok 1. Instalowanie wymaganych narzędzi
W tym kroku zainstalujesz narzędzia, takie jak interfejs wiersza polecenia Databricks, Jenkins, jq
oraz narzędzia do kompilacji pakietów Python na lokalnej maszynie deweloperskiej. Te narzędzia są wymagane do uruchomienia tego przykładu.
Zainstaluj interfejs wiersza polecenia usługi Databricks w wersji 0.205 lub nowszej, jeśli jeszcze tego nie zrobiono. Usługa Jenkins używa interfejsu wiersza polecenia usługi Databricks do przekazania tych przykładowych testów i uruchamiania instrukcji do obszaru roboczego. Zobacz Instalowanie lub aktualizowanie interfejsu wiersza poleceń Databricks.
Zainstaluj i uruchom narzędzie Jenkins, jeśli jeszcze tego nie zrobiono. Zobacz Instalowanie serwera Jenkins dla systemów Linux, macOS lub Windows.
Zainstaluj pakiet jq. W tym przykładzie użyto
jq
metody , aby przeanalizować niektóre dane wyjściowe polecenia w formacie JSON.Użyj polecenia
pip
, aby zainstalować narzędzia do budowania pakietów w formacie wheel dla języka Python za pomocą następującego polecenia (niektóre systemy mogą wymagać użycia polecenia zamiastpip3
).pip install --upgrade wheel
Krok 2: Tworzenie pipeline'u Jenkins
W tym kroku użyjesz narzędzia Jenkins do utworzenia potoku Jenkins na potrzeby przykładu w tym artykule. Jenkins udostępnia kilka różnych typów projektów do tworzenia potoków CI/CD. Jenkins Pipelines udostępniają interfejs do definiowania etapów w potoku Jenkins za pomocą kodu Groovy do wywoływania i konfigurowania wtyczek Jenkins.
Aby utworzyć potok serwera Jenkins w usłudze Jenkins:
- Po uruchomieniu narzędzia Jenkins na pulpicie nawigacyjnym usługi Jenkins kliknij pozycję Nowy element.
- W polu Wprowadź nazwę elementu wpisz nazwę potoku Jenkins, na przykład
jenkins-demo
. - Kliknij ikonę Pipeline projektu.
- Kliknij przycisk OK. Zostanie wyświetlona strona Konfigurowanie potoku narzędzia Jenkins.
- W obszarze Pipeline, na liście rozwijanej Definicja wybierz pozycję Skrypt potokowy z SCM.
- Z listy rozwijanej SCM wybierz pozycję Git.
- W polu Adres URL repozytorium wpisz adres URL repozytorium hostowanego przez zewnętrznego dostawcę Git.
- W polu Specyfikator gałęzi wpisz
*/<branch-name>
, gdzie<branch-name>
jest nazwą gałęzi w repozytorium, którego chcesz użyć, na przykład*/main
. - Dla Ścieżki skryptu wpisz
Jenkinsfile
, jeśli nie jest jeszcze ustawiona. W dalszej części tego artykułu utworzyszJenkinsfile
. - Usuń zaznaczenie pola o nazwie Uproszczone kasowanie, jeśli zostało już zaznaczone.
- Kliknij przycisk Zapisz.
Krok 3. Dodawanie globalnych zmiennych środowiskowych do usługi Jenkins
W tym kroku do serwera Jenkins zostaną dodane trzy globalne zmienne środowiskowe. Usługa Jenkins przekazuje te zmienne środowiskowe do interfejsu wiersza polecenia usługi Databricks. Interfejs wiersza polecenia usługi Databricks wymaga wartości tych zmiennych środowiskowych do uwierzytelniania w obszarze roboczym usługi Azure Databricks. W tym przykładzie użyto uwierzytelniania maszyny do maszyny OAuth (M2M) dla głównej usługi (chociaż dostępne są również inne typy uwierzytelniania). Aby skonfigurować uwierzytelnianie OAuth M2M dla obszaru roboczego usługi Azure Databricks, zobacz Autoryzowanie nienadzorowanego dostępu do zasobów usługi Azure Databricks przy użyciu jednostki usługi przy użyciu protokołu OAuth.
Trzy globalne zmienne środowiskowe dla tego przykładu to:
-
DATABRICKS_HOST
, ustaw adres URL obszaru roboczego usługi Azure Databricks, zaczynając odhttps://
. Zobacz Nazwy wystąpień obszaru roboczego, adresy URL i identyfikatory. -
DATABRICKS_CLIENT_ID
, ustaw jako identyfikator klienta głównego użytkownika usługi, znany również jako jego identyfikator aplikacji. -
DATABRICKS_CLIENT_SECRET
, ustaw wartość na tajnego klucza OAuth jednostki usługi Azure Databricks.
Aby ustawić globalne zmienne środowiskowe w usłudze Jenkins, na pulpicie nawigacyjnym usługi Jenkins:
- Na pasku bocznym kliknij pozycję Zarządzaj serwerem Jenkins.
- W sekcji Konfiguracja systemu kliknij pozycję System.
- W sekcji Właściwości globalne zaznacz pole z kafelkiem Zmienne środowiskowe.
- Kliknij przycisk Dodaj , a następnie wprowadź nazwę i wartość zmiennej środowiskowej. Powtórz to dla każdej dodatkowej zmiennej środowiskowej.
- Po zakończeniu dodawania zmiennych środowiskowych kliknij przycisk Zapisz, aby powrócić do pulpitu nawigacyjnego usługi Jenkins.
Zaprojektuj potok Jenkins
Jenkins udostępnia kilka różnych typów projektów do tworzenia potoków CI/CD. W tym przykładzie zaimplementowano potok Jenkins. Jenkins Pipelines udostępniają interfejs do definiowania etapów w potoku Jenkins za pomocą kodu Groovy do wywoływania i konfigurowania wtyczek Jenkins.
Definicję potoku narzędzia Jenkins można napisać w pliku tekstowym o nazwie Jenkinsfile, który następnie jest zapisywany w repozytorium kontroli wersji projektu. Aby uzyskać więcej informacji, zobacz Jenkins Pipeline. Oto potok Jenkins dla przykładu w tym artykule. W tym przykładzie Jenkinsfile
zastąp następujące symbole zastępcze:
- Zastąp
<user-name>
nazwą użytkownika i<repo-name>
nazwą repozytorium hostowanych przez zewnętrznego dostawcę usług Git. W tym artykule jako przykład jest używany adres URL usługi GitHub. - Zastąp
<release-branch-name>
nazwą gałęzi wydania w repozytorium. Na przykład może to byćmain
. - Zastąp
<databricks-cli-installation-path>
ścieżką na lokalnej maszynie deweloperskiej, na której zainstalowano interfejs wiersza polecenia Databricks. Na przykład w systemie macOS może to być/usr/local/bin
. - Zastąp
<jq-installation-path>
ścieżką na lokalnym komputerze deweloperskim, na którymjq
jest zainstalowany. Na przykład w systemie macOS może to być/usr/local/bin
. - Zastąp
<job-prefix-name>
jakimś ciągiem znaków, aby ułatwić unikatowe zidentyfikowanie zadań utworzonych w obszarze roboczym na potrzeby tego przykładu. Na przykład może to byćjenkins-demo
. - Zwróć uwagę, że
BUNDLETARGET
jest ustawiony nadev
, która jest nazwą Pakietu Zasobów Databricks zdefiniowanego w dalszej części tego artykułu. W rzeczywistych implementacjach można to zmienić na nazwę docelowego pakietu. Więcej szczegółów na temat elementów docelowych pakietu znajduje się w dalszej części tego artykułu.
Oto element Jenkinsfile
, który należy dodać do katalogu głównego repozytorium:
// 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
}
}
W pozostałej części tego artykułu opisano każdy etap w potoku Jenkins oraz sposób konfigurowania artefaktów i poleceń, które Jenkins ma uruchomić na tym etapie.
Ściąganie najnowszych artefaktów z repozytorium innej firmy
Pierwszy etap w tym potoku Jenkins, etap Checkout
, jest definiowany w następujący sposób:
stage('Checkout') {
git branch: GITBRANCH, url: GITREPOREMOTE
}
Ten etap zapewnia, że katalog roboczy używany przez narzędzie Jenkins na lokalnej maszynie dewelopera zawiera najnowsze artefakty z repozytorium Git innej firmy. Zazwyczaj narzędzie Jenkins ustawia ten katalog roboczy na <your-user-home-directory>/.jenkins/workspace/<pipeline-name>
. Dzięki temu na tej samej lokalnej maszynie programistycznej możesz zachować własną kopię artefaktów w środowisku deweloperskim niezależnie od artefaktów używanych przez usługę Jenkins z repozytorium Git innej firmy.
Weryfikowanie pakietu zasobów usługi Databricks
Drugi etap w tym potoku Jenkins, etap Validate Bundle
, jest zdefiniowany w następujący sposób:
stage('Validate Bundle') {
sh """#!/bin/bash
${DBCLIPATH}/databricks bundle validate -t ${BUNDLETARGET}
"""
}
Ten etap zapewnia, że pakiet zasobów usługi Databricks, który definiuje przepływy pracy na potrzeby testowania i uruchamiania artefaktów, jest poprawny składniowo. Pakiety zasobów usługi Databricks, znane po prostu jako pakiety, umożliwiają wyrażanie pełnych danych, analiz i projektów uczenia maszynowego jako kolekcji plików źródłowych. Zobacz Co to są pakiety zasobów Databricks?.
Aby zdefiniować pakiet dla tego artykułu, utwórz plik o nazwie databricks.yml
w katalogu głównym sklonowanego repozytorium na komputerze lokalnym. W tym przykładowym pliku databricks.yml
zastąp następujące elementy zastępcze:
- Zastąp
<bundle-name>
unikatową nazwą programową pakietu. Na przykład może to byćjenkins-demo
. - Zastąp
<job-prefix-name>
jakimś ciągiem znaków, aby ułatwić unikatowe zidentyfikowanie zadań utworzonych w obszarze roboczym na potrzeby tego przykładu. Na przykład może to byćjenkins-demo
. Powinna być zgodna z wartościąJOBPREFIX
w pliku Jenkinsfile. - Zastąp element
<spark-version-id>
identyfikatorem wersji środowiska Databricks Runtime dla klastrów zadań, na przykład13.3.x-scala2.12
. - Zastąp
<cluster-node-type-id>
identyfikatorem typu węzła dla klastrów zadań, na przykładStandard_DS3_v2
. - Zwróć uwagę, że
dev
w mapowaniu jest to samo cotargets
wBUNDLETARGET
pliku Jenkinsfile. Cel pakietu określa serwer oraz powiązane zachowania wdrożeniowe.
databricks.yml
Oto plik, który należy dodać do katalogu głównego repozytorium, aby ten przykład działał poprawnie:
# 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
Aby uzyskać więcej informacji na temat pliku databricks.yml
, zobacz Konfiguracja pakietu zasobów Databricks.
Wdrażanie pakietu w obszarze roboczym
Trzeci etap potoku narzędzia Jenkins, zatytułowany Deploy Bundle
, jest definiowany w następujący sposób:
stage('Deploy Bundle') {
sh """#!/bin/bash
${DBCLIPATH}/databricks bundle deploy -t ${BUNDLETARGET}
"""
}
Ten etap obejmuje dwie rzeczy:
- Ponieważ mapowanie w pliku
artifact
jest ustawione na wartośćdatabricks.yml
, powoduje to, że Databricks CLI buduje plik Python wheel przy użyciu plikuwhl
w określonej lokalizacji. - Po zbudowaniu koła Pythona na lokalnej maszynie deweloperskiej, Databricks CLI wdraża skompilowany plik koła Pythona wraz z określonymi skryptami i notatnikami Pythona do obszaru roboczego Azure Databricks. Domyślnie Pakiety zasobów Databricks wdrażają plik wheel języka Python i inne pliki do
/Workspace/Users/<your-username>/.bundle/<bundle-name>/<target-name>
.
Aby umożliwić skompilowanie pliku wheel języka Python zgodnie z określeniami w pliku databricks.yml
, utwórz następujące foldery i pliki w katalogu głównym sklonowanego repozytorium na komputerze lokalnym.
Aby zdefiniować logikę i testy jednostkowe dla pliku wheel w języku Python, względem którego zostanie uruchomiony notebook, utwórz dwa pliki o nazwach addcol.py
oraz test_addcol.py
. Następnie dodaj je do struktury folderów o nazwie python/dabdemo/dabdemo
, znajdującej się w folderze repozytorium Libraries
, zwizualizowanej w następujący sposób (wielokropek wskazuje pominięte foldery w repozytorium dla zwięzłości):
├── ...
├── Libraries
│ └── python
│ └── dabdemo
│ └── dabdemo
│ ├── addcol.py
│ └── test_addcol.py
├── ...
Plik addcol.py
zawiera funkcję biblioteki wbudowaną później w plik wheel języka Python, a następnie zainstalowaną w klastrze usługi Azure Databricks. Jest to prosta funkcja, która dodaje nową kolumnę wypełniną literałem do ramki danych platformy Apache Spark:
# Filename: addcol.py
import pyspark.sql.functions as F
def with_status(df):
return df.withColumn("status", F.lit("checked"))
Plik test_addcol.py
zawiera testy, które umożliwiają przekazanie pozornego obiektu ramki danych do funkcji with_status
, zdefiniowanej w pliku addcol.py
. Wynik jest następnie porównywany z obiektem DataFrame zawierającym oczekiwane wartości. Jeśli wartości są zgodne, co w takim przypadku wykonuje, test zakończy się pomyślnie:
# 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())
Aby umożliwić interfejsowi wiersza polecenia usługi Databricks poprawne spakowanie tego kodu biblioteki do pliku koła języka Python, utwórz dwa pliki o nazwie __init__.py
i __main__.py
w tym samym folderze co poprzednie dwa pliki. Ponadto utwórz plik o nazwie setup.py
w folderze python/dabdemo
, wizualizowany w następujący sposób (wielokropek oznacza pominięte foldery dla zwięzłości):
├── ...
├── Libraries
│ └── python
│ └── dabdemo
│ ├── dabdemo
│ │ ├── __init__.py
│ │ ├── __main__.py
│ │ ├── addcol.py
│ │ └── test_addcol.py
│ └── setup.py
├── ...
Plik __init__.py
zawiera numer wersji biblioteki i jego autora. Zastąp <my-author-name>
swoim imieniem:
# Filename: __init__.py
__version__ = '0.0.1'
__author__ = '<my-author-name>'
import sys, os
sys.path.append(os.path.join(os.path.dirname(__file__), "..", ".."))
Plik __main__.py
zawiera punkt wejścia biblioteki:
# 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()
Plik setup.py
zawiera dodatkowe ustawienia do budowania biblioteki jako pliku wheel w języku Python. Zastąp <my-url>
, <my-author-name>@<my-organization>
oraz <my-package-description>
znaczącymi wartościami.
# 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"]
)
Testowanie logiki składników koła języka Python
Etap Run Unit Tests
, czwarty etap w ramach tego ciągu Jenkins, używa pytest
do testowania logiki biblioteki, aby upewnić się, że działa poprawnie po budowie. Ten etap jest definiowany w następujący sposób:
stage('Run Unit Tests') {
sh """#!/bin/bash
${DBCLIPATH}/databricks bundle run -t ${BUNDLETARGET} run-unit-tests
"""
}
Ten etap używa CLI Databricks w celu uruchomienia zadania notatnika. To zadanie uruchamia notes języka Python z nazwą pliku run-unit-test.py
. Ten notatnik działa pytest
na podstawie logiki biblioteki.
Aby uruchomić testy jednostkowe dla tego przykładu, dodaj plik notesu języka Python o nazwie run_unit_tests.py
z następującą zawartością do katalogu głównego sklonowanego repozytorium na komputerze lokalnym.
# 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."
Korzystanie z wbudowanego koła języka Python
Piąty etap tego potoku narzędzia Jenkins o nazwie Run Notebook
, uruchamia notes języka Python, który wywołuje logikę w skompilowanym pliku wheel języka Python w następujący sposób:
stage('Run Notebook') {
sh """#!/bin/bash
${DBCLIPATH}/databricks bundle run -t ${BUNDLETARGET} run-dabdemo-notebook
"""
}
Ten etap uruchamia CLI Databricks, który z kolei instruuje obszar roboczy, aby uruchomić zadanie notatnika. Ten notes tworzy obiekt ramki danych, przekazuje go do funkcji biblioteki with_status
, wyświetla wynik i zgłasza wyniki uruchomienia zadania. Utwórz notes, dodając plik języka Python nazwany dabdaddemo_notebook.py
z następującą zawartością do katalogu głównego sklonowanego repozytorium na lokalnym komputerze deweloperskim:
# 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 |
# +------------+-----------+-------------------------+---------+
Ocena wyników uruchomienia zadania notebooka
Etap Evaluate Notebook Runs
, szósty etap tego potoku Jenkins, ocenia wyniki poprzedniego uruchomienia zadania notebooka. Ten etap jest definiowany w następujący sposób:
stage('Evaluate Notebook Runs') {
sh """#!/bin/bash
${DBCLIPATH}/databricks bundle run -t ${BUNDLETARGET} evaluate-notebook-runs
"""
}
Ten etap uruchamia interfejs wiersza polecenia usługi Databricks, który z kolei instruuje obszar roboczy, aby uruchomić zadanie z pliku Python. Ten plik w języku Python określa kryteria niepowodzenia i powodzenia uruchomienia zadania notesu i zgłasza ten błąd lub wynik powodzenia. Utwórz plik o nazwie evaluate_notebook_runs.py
z następującą zawartością w katalogu głównym sklonowanego repozytorium na lokalnym komputerze deweloperskim.
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
)
Importowanie i raportowanie wyników testów
Siódmy etap w tym potoku Jenkins, zatytułowany Import Test Results
, używa Databricks CLI do wysyłania wyników testów z obszaru roboczego do lokalnej maszyny deweloperskiej. Ósmy i ostatni etap, zatytułowany Publish Test Results
, publikuje wyniki testów dla serwera Jenkins przy użyciu junit
wtyczki Jenkins. Dzięki temu można wizualizować raporty i pulpity nawigacyjne związane ze stanem wyników testu. Te etapy są definiowane w następujący sposób:
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
}
Wypychanie wszystkich zmian kodu do repozytorium innej firmy
Teraz należy wypchnąć zawartość sklonowanego repozytorium na lokalnym komputerze deweloperskim do repozytorium innej firmy. Przed przesłaniem zmian, należy najpierw dodać następujące wpisy do pliku .gitignore
w sklonowanym repozytorium, ponieważ nie powinno się przesyłać wewnętrznych plików roboczych Databricks Asset Bundle, raportów weryfikacyjnych, plików zbudowanych w Pythonie i pamięci podręcznych Pythona do repozytorium innej firmy. Zazwyczaj należy ponownie wygenerować nowe raporty weryfikacji i najnowsze kompilacje koła języka Python w obszarze roboczym usługi Azure Databricks, zamiast używać potencjalnie nieaktualnych raportów weryfikacji i kompilacji koła języka Python:
.databricks/
.vscode/
Libraries/python/dabdemo/build/
Libraries/python/dabdemo/__pycache__/
Libraries/python/dabdemo/dabdemo.egg-info/
Validation/
Uruchamianie potoku narzędzia Jenkins
Teraz możesz przystąpić do ręcznego uruchamiania potoku serwera Jenkins. W tym celu z poziomu pulpitu nawigacyjnego narzędzia Jenkins:
- Kliknij nazwę pipeline'u Jenkinsa.
- Na pasku bocznym kliknij pozycję Skompiluj teraz.
- Aby wyświetlić wyniki, kliknij najnowsze uruchomienie potoku (na przykład
#1
), a następnie kliknij pozycję Dane wyjściowe konsoli.
W tym momencie pipeline CI/CD zakończył cykl integracji i wdrażania. Automatyzując ten proces, możesz upewnić się, że kod został przetestowany i wdrożony przez wydajny, spójny i powtarzalny proces. Aby poinstruować dostawcę git innej firmy, aby uruchamiał narzędzie Jenkins za każdym razem, gdy wystąpi określone zdarzenie, takie jak żądanie ściągnięcia repozytorium, zapoznaj się z dokumentacją dostawcy git innej firmy.