CI/CD com Jenkins na Databricks
Este artigo abrange o Jenkins, que é desenvolvido por terceiros. Para entrar em contato com o provedor, consulte a Ajuda do Jenkins.
Existem inúmeras ferramentas CI/CD que o senhor pode usar para gerenciar e executar seu pipeline CI/CD. Este artigo ilustra como usar o servidor de automação Jenkins. CI/CD é um padrão de design, portanto, as etapas e os estágios descritos neste artigo devem ser transferidos com algumas alterações na linguagem de definição do pipeline em cada ferramenta. Além disso, grande parte do código deste exemplo pipeline executa o código Python padrão, que o senhor pode invocar em outras ferramentas. Para obter uma visão geral da CI/CD na Databricks, consulte O que é CI/CD na Databricks?
CI/CD desenvolvimento fluxo de trabalho
A Databricks sugere o seguinte fluxo de trabalho para o desenvolvimento de CI/CD com o Jenkins:
- Crie um repositório ou use um repositório existente com seu provedor Git de terceiros.
- Conecte sua máquina de desenvolvimento local ao mesmo repositório de terceiros. Para obter instruções, consulte a documentação do provedor de Git de terceiros.
- Puxe todos os artefatos atualizados existentes (como o Notebook, os arquivos de código e os scripts de compilação) do repositório de terceiros para sua máquina de desenvolvimento local.
- Conforme desejado, crie, atualize e teste artefatos em sua máquina de desenvolvimento local. Em seguida, envie todos os artefatos novos e alterados de sua máquina de desenvolvimento local para o repositório de terceiros. Para obter instruções, consulte a documentação do provedor de Git de terceiros.
- Repita as etapas 3 e 4 conforme necessário.
- Use o Jenkins periodicamente como uma abordagem integrada para extrair automaticamente artefatos do repositório de terceiros para o computador de desenvolvimento local ou Databricks workspace; criar, testar e executar código no computador de desenvolvimento local ou Databricks workspace; e relatar os resultados dos testes e da execução. Embora seja possível executar o Jenkins manualmente, em implementações reais, o senhor instruiria o provedor terceirizado Git a executar o Jenkins sempre que ocorresse um evento específico, como uma solicitação de pull do repositório.
O restante deste artigo usa um projeto de exemplo para descrever uma maneira de usar o Jenkins para implementar o fluxo de trabalho de desenvolvimento CI/CD anterior.
Configuração da máquina de desenvolvimento local
O exemplo deste artigo usa o Jenkins para instruir os pacotes Databricks CLI e Databricks ativo Bundles para fazer o seguinte:
- Crie um arquivo Python wheel em seu computador de desenvolvimento local.
- Implemente o arquivo Python wheel construído junto com os arquivos Python adicionais e o Notebook Python de sua máquina de desenvolvimento local em um Databricks workspace.
- Teste e execute o upload do arquivo Python wheel e o Notebook nesse workspace.
Para configurar o computador de desenvolvimento local para instruir o Databricks workspace a executar os estágios de compilação e upload deste exemplo, faça o seguinte no computador de desenvolvimento local:
Etapa 1: instalar as ferramentas necessárias
Nesta etapa, o senhor instala as ferramentas de compilação Databricks CLI, Jenkins, jq
e Python wheel em sua máquina de desenvolvimento local. Essas ferramentas são necessárias para a execução deste exemplo.
-
Instale o site Databricks CLI versão 0.205 ou acima, caso ainda não o tenha feito. O Jenkins usa o Databricks CLI para passar as instruções de teste e execução deste exemplo para o seu workspace. Consulte Instalar ou atualizar a CLI da Databricks.
-
Instale e inicie o Jenkins, caso ainda não o tenha feito. Consulte Instalação do Jenkins para Linux, macOS ou Windows.
-
Instale o jq. Este exemplo usa o site
jq
para analisar algumas saídas de comando formatadas em JSON. -
Use
pip
para instalar as ferramentas de compilação do Python wheel com o seguinte comando (alguns sistemas podem exigir que o senhor usepip3
em vez depip
):Bashpip install --upgrade wheel
Etapa 2: Criar um pipeline do Jenkins
Nesta etapa, o senhor usa o Jenkins para criar um pipeline do Jenkins para o exemplo deste artigo. O Jenkins oferece alguns tipos de projetos diferentes para criar o pipeline CI/CD. O pipeline do Jenkins fornece uma interface para definir estágios em um pipeline do Jenkins usando o código Groovy para chamar e configurar os plugins do Jenkins.
Para criar o pipeline do Jenkins no Jenkins:
- Depois de iniciar o Jenkins, no painel do Jenkins, clique em New Item (Novo item ).
- Em Enter an item name (Inserir um nome de item ), digite um nome para o pipeline do Jenkins, por exemplo,
jenkins-demo
. - Clique no ícone do tipo de projeto de pipeline .
- Clique em OK . A página Configure (Configurar ) do pipeline do Jenkins é exibida.
- Na área de pipeline , na lista suspensa Definição , selecione o script de pipeline do SCM .
- Na lista suspensa SCM , selecione Git .
- Em Repository URL (URL do repositório ), digite a URL do repositório hospedado pelo seu provedor Git de terceiros.
- Em Branch Specifier , digite
*/<branch-name>
, onde<branch-name>
é o nome da ramificação em seu repositório que você deseja usar, por exemplo*/main
. - Em Caminho do script , digite
Jenkinsfile
, se ainda não estiver definido. O senhor cria oJenkinsfile
mais adiante neste artigo. - Desmarque a caixa intitulada Lightweight checkout , se já estiver marcada.
- Clique em Salvar .
Etapa 3: Adicionar variável global de ambiente ao Jenkins
Nesta etapa, o senhor adiciona três variáveis globais de ambiente ao Jenkins. Jenkins passa essas variáveis de ambiente para o site Databricks CLI. O Databricks CLI precisa dos valores para essas variáveis de ambiente para se autenticar com o seu Databricks workspace. Este exemplo usa a autenticação OAuth máquina a máquina (M2M) para uma entidade de serviço (embora outros tipos de autenticação também estejam disponíveis). Para configurar a autenticação OAuth M2M para seu Databricks workspace, consulte Autorizar o acesso autônomo ao Databricks recurso com uma entidade de serviço usando o OAuth.
As três variáveis globais de ambiente para este exemplo são:
DATABRICKS_HOST
, definido como seu URL Databricks workspace , começando comhttps://
. Consulte nomes de instância de espaço de trabalho, URLs e IDs.DATABRICKS_CLIENT_ID
definido como o ID do cliente da entidade de serviço, que também é conhecido como ID do aplicativo.DATABRICKS_CLIENT_SECRET
definido como o segredo do Databricks OAuth da entidade de serviço.
Para definir a variável global de ambiente no Jenkins, no painel do Jenkins:
- Na barra lateral, clique em gerenciar Jenkins .
- Na seção Configuração do sistema , clique em Sistema .
- Na seção Global properties (Propriedades globais ), marque a caixa tiled variável de ambiente .
- Clique em Add e insira o nome e o valor da variável de ambiente. Repita esse procedimento para cada variável de ambiente adicional.
- Quando terminar de adicionar a variável de ambiente, clique em Save (Salvar ) para retornar ao painel do Jenkins.
Projetar o pipeline do Jenkins
O Jenkins oferece alguns tipos de projetos diferentes para criar o pipeline CI/CD. Este exemplo implementa um pipeline do Jenkins. O pipeline do Jenkins fornece uma interface para definir estágios em um pipeline do Jenkins usando o código Groovy para chamar e configurar os plugins do Jenkins.
O senhor escreve uma definição de pipeline do Jenkins em um arquivo de texto chamado Jenkinsfile , que, por sua vez, é verificado no repositório de controle de origem de um projeto. Para obter mais informações, consulte o pipeline do Jenkins. Aqui está o pipeline do Jenkins para o exemplo deste artigo. Neste exemplo Jenkinsfile
, substitua os seguintes espaços reservados:
- Substitua
<user-name>
e<repo-name>
pelo nome de usuário e pelo nome do repositório hospedado pelo seu provedor Git de terceiros. Este artigo usa um URL GitHub como exemplo. - Substitua
<release-branch-name>
pelo nome da ramificação de lançamento em seu repositório. Por exemplo, isso pode sermain
. - Substitua
<databricks-cli-installation-path>
pelo caminho em seu computador de desenvolvimento local onde a CLI da Databricks está instalada. Por exemplo, no macOS, isso pode ser/usr/local/bin
. - Substitua
<jq-installation-path>
pelo caminho em sua máquina de desenvolvimento local ondejq
está instalado. Por exemplo, no macOS, isso pode ser/usr/local/bin
. - Substitua
<job-prefix-name>
por algumas cadeias de caracteres para ajudar a identificar exclusivamente o trabalho Databricks que é criado em seu workspace para este exemplo. Por exemplo, isso pode serjenkins-demo
. - Observe que
BUNDLETARGET
está definido comodev
, que é o nome do Databricks ativo Bundle target definido posteriormente neste artigo. Em implementações do mundo real, você alteraria isso para o nome do seu próprio pacote de destino. Mais detalhes sobre os alvos do pacote são fornecidos mais adiante neste artigo.
Aqui está o Jenkinsfile
, que deve ser adicionado à raiz do seu repositório:
// 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
}
}
O restante deste artigo descreve cada estágio desse pipeline do Jenkins e como configurar os artefatos e o comando para o Jenkins executar nesse estágio.
Obtenha os artefatos mais recentes do repositório de terceiros
O primeiro estágio desse pipeline do Jenkins, o estágio Checkout
, é definido da seguinte forma:
stage('Checkout') {
git branch: GITBRANCH, url: GITREPOREMOTE
}
Essa etapa garante que o diretório de trabalho que o Jenkins usa em sua máquina de desenvolvimento local tenha os artefatos mais recentes do repositório Git de terceiros. Normalmente, o Jenkins define esse diretório de trabalho como <your-user-home-directory>/.jenkins/workspace/<pipeline-name>
. Isso permite que o senhor, na mesma máquina de desenvolvimento local, mantenha sua própria cópia de artefatos em desenvolvimento separada dos artefatos que o Jenkins usa do seu repositório Git de terceiros.
Validar o pacote Databricks ativo
O segundo estágio desse pipeline do Jenkins, o estágio Validate Bundle
, é definido da seguinte forma:
stage('Validate Bundle') {
sh """#!/bin/bash
${DBCLIPATH}/databricks bundle validate -t ${BUNDLETARGET}
"""
}
Esse estágio garante que o Databricks ativo Bundle, que define o fluxo de trabalho para testar e executar seus artefatos, esteja sintaticamente correto. Databricks ativo Bundles , conhecidos simplesmente como bundles , possibilitam expressar análises completas de dados e projetos ML como uma coleção de arquivos de origem. Veja o que são Databricks ativo Bundles?
Para definir o pacote para esse artigo, crie um arquivo chamado databricks.yml
na raiz do repositório clonado em seu computador local. Neste exemplo de arquivo databricks.yml
, substitua os seguintes espaços reservados:
- Substitua
<bundle-name>
por um nome programático exclusivo para o pacote. Por exemplo, isso pode serjenkins-demo
. - Substitua
<job-prefix-name>
por algumas cadeias de caracteres para ajudar a identificar exclusivamente o trabalho Databricks que é criado em seu workspace para este exemplo. Por exemplo, isso pode serjenkins-demo
. Ele deve corresponder ao valorJOBPREFIX
em seu arquivo Jenkins. - Substitua
<spark-version-id>
pela ID da versão Databricks Runtime do seu Job clustering, por exemplo,13.3.x-scala2.12
. - Substitua
<cluster-node-type-id>
pelo ID do tipo de nó do Job clustering, por exemplo,i3.xlarge
. - Observe que
dev
no mapeamentotargets
é o mesmo queBUNDLETARGET
em seu arquivo Jenkins. Um destino de pacote especifica o host e os comportamentos de implantação relacionados.
Aqui está o arquivo databricks.yml
, que deve ser adicionado à raiz do seu repositório para que este exemplo funcione corretamente:
# 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
Para obter mais informações sobre o arquivo databricks.yml
, consulte Databricks ativo Bundle configuration.
implantado o pacote em seu workspace
O terceiro estágio do pipeline Jenkins, intitulado Deploy Bundle
, é definido da seguinte forma:
stage('Deploy Bundle') {
sh """#!/bin/bash
${DBCLIPATH}/databricks bundle deploy -t ${BUNDLETARGET}
"""
}
Esse estágio faz duas coisas:
- Como o mapeamento
artifact
no arquivodatabricks.yml
está definido comowhl
, isso instrui o Databricks CLI a criar o arquivo Python wheel usando o arquivosetup.py
no local especificado. - Depois que o arquivo Python wheel é criado em sua máquina de desenvolvimento local, o Databricks CLI implanta o arquivo Python wheel criado junto com os arquivos Python especificados e o Notebook em seu Databricks workspace. Por default, Databricks ativo Bundles implantado o arquivo Python wheel e outros arquivos para
/Workspace/Users/<your-username>/.bundle/<bundle-name>/<target-name>
.
Para permitir que o arquivo Python wheel seja criado conforme especificado no arquivo databricks.yml
, crie as seguintes pastas e arquivos na raiz do repositório clonado em seu computador local.
Para definir a lógica e os testes de unidade para o arquivo Python wheel contra o qual o Notebook será executado, crie dois arquivos denominados addcol.py
e test_addcol.py
e adicione-os a uma estrutura de pastas denominada python/dabdemo/dabdemo
dentro da pasta Libraries
do seu repositório, visualizada da seguinte forma (as elipses indicam pastas omitidas no repositório, para fins de brevidade):
├── ...
├── Libraries
│ └── python
│ └── dabdemo
│ └── dabdemo
│ ├── addcol.py
│ └── test_addcol.py
├── ...
O arquivo addcol.py
contém uma função de biblioteca que é criada posteriormente em um arquivo Python wheel e, em seguida, instalada em um cluster Databricks. Trata-se de
uma função simples que adiciona uma nova coluna, preenchida por um literal, a um Apache Spark DataFrame:
# Filename: addcol.py
import pyspark.sql.functions as F
def with_status(df):
return df.withColumn("status", F.lit("checked"))
O arquivo test_addcol.py
contém testes para passar um objeto DataFrame simulado para a função with_status
, definida em addcol.py
. O resultado do
é então comparado a um objeto DataFrame que contém os valores esperados. Se os valores corresponderem, o que acontece nesse caso, o teste será aprovado:
# 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())
Para que o Databricks CLI possa empacotar corretamente esse código de biblioteca em um arquivo Python wheel, crie dois arquivos denominados __init__.py
e __main__.py
na mesma pasta dos dois arquivos anteriores. Além disso, crie um arquivo chamado setup.py
na pasta python/dabdemo
, visualizado da seguinte forma (elipses indicam pastas omitidas, para resumir):
├── ...
├── Libraries
│ └── python
│ └── dabdemo
│ ├── dabdemo
│ │ ├── __init__.py
│ │ ├── __main__.py
│ │ ├── addcol.py
│ │ └── test_addcol.py
│ └── setup.py
├── ...
O arquivo __init__.py
contém o número da versão da biblioteca e o autor. Substitua <my-author-name>
pelo seu nome:
# Filename: __init__.py
__version__ = '0.0.1'
__author__ = '<my-author-name>'
import sys, os
sys.path.append(os.path.join(os.path.dirname(__file__), "..", ".."))
O arquivo __main__.py
contém o ponto de entrada da biblioteca:
# 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()
O arquivo setup.py
contém configurações adicionais para criar a biblioteca em um arquivo Python wheel. Substitua <my-url>
, <my-author-name>@<my-organization>
e <my-package-description>
por valores significativos:
# 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"]
)
Teste a lógica dos componentes do site Python wheel
O estágio Run Unit Tests
, o quarto estágio deste pipeline do Jenkins, usa o pytest
para testar a lógica de uma biblioteca e garantir que ela funcione como foi construída. Esse estágio é definido da seguinte forma:
stage('Run Unit Tests') {
sh """#!/bin/bash
${DBCLIPATH}/databricks bundle run -t ${BUNDLETARGET} run-unit-tests
"""
}
Essa etapa usa o site Databricks CLI para executar um trabalho de notebook. Esse Job executa o Python Notebook com o nome de arquivo run-unit-test.py
. A execução do Notebook pytest
contraria a lógica da biblioteca.
Para executar os testes de unidade deste exemplo, adicione um arquivo do Notebook Python chamado run_unit_tests.py
com o seguinte conteúdo à raiz do repositório clonado em seu computador local:
# 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."
Use o Python wheel
A quinta etapa desse pipeline do Jenkins, intitulada Run Notebook
, executa um notebook Python que chama a lógica no arquivo Python wheel criado, como segue:
stage('Run Notebook') {
sh """#!/bin/bash
${DBCLIPATH}/databricks bundle run -t ${BUNDLETARGET} run-dabdemo-notebook
"""
}
Esse estágio executa o Databricks CLI, que, por sua vez, instrui o workspace a executar um Notebook Job. Este Notebook cria um objeto DataFrame, passa-o para a função with_status
da biblioteca, imprime o resultado e informa os resultados da execução do Job. Crie o Notebook adicionando um arquivo Python Notebook chamado dabdaddemo_notebook.py
com o seguinte conteúdo na raiz do repositório clonado em seu computador de desenvolvimento local:
# 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 |
# +------------+-----------+-------------------------+---------+
Avaliar os resultados da execução do Notebook Job
O estágio Evaluate Notebook Runs
, o sexto estágio desse pipeline do Jenkins, avalia os resultados da execução do Notebook Job anterior. Esse estágio é definido da seguinte forma:
stage('Evaluate Notebook Runs') {
sh """#!/bin/bash
${DBCLIPATH}/databricks bundle run -t ${BUNDLETARGET} evaluate-notebook-runs
"""
}
Essa etapa executa o Databricks CLI, que, por sua vez, instrui o workspace a executar um arquivo Job Python. Esse arquivo Python determina os critérios de falha e sucesso para a execução do Notebook Job e informa esse resultado de falha ou sucesso. Crie um arquivo chamado evaluate_notebook_runs.py
com o seguinte conteúdo na raiz do seu repositório clonado em sua máquina de desenvolvimento local:
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
)
Importar e relatar resultados de testes
A sétima etapa desse pipeline do Jenkins, intitulada Import Test Results
, usa o Databricks CLI para enviar os resultados do teste do seu workspace para a máquina de desenvolvimento local. A oitava e última etapa, intitulada Publish Test Results
, publica os resultados do teste no Jenkins usando o plugin junit
Jenkins. Isso permite que você visualize relatórios e painéis relacionados ao status dos resultados do teste. Esses estágios são definidos da seguinte forma:
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
}
Envie todas as alterações de código para seu repositório de terceiros
Agora você deve enviar o conteúdo do seu repositório clonado em sua máquina de desenvolvimento local para seu repositório de terceiros. Antes de fazer o push, adicione as seguintes entradas ao arquivo .gitignore
no repositório clonado, pois provavelmente não deve fazer o push de arquivos de trabalho internos do Databricks ativo Bundle, relatórios de validação, arquivos de compilação do Python e caches do Python no repositório de terceiros. Normalmente, o senhor deseja gerar novamente novos relatórios de validação e a última versão do Python wheel integrada ao seu Databricks workspace, em vez de usar relatórios de validação e compilações do Python wheel potencialmente desatualizados:
.databricks/
.vscode/
Libraries/python/dabdemo/build/
Libraries/python/dabdemo/__pycache__/
Libraries/python/dabdemo/dabdemo.egg-info/
Validation/
executar seu pipeline Jenkins
Agora o senhor está pronto para executar o pipeline do Jenkins manualmente. Para fazer isso, no painel do Jenkins:
- Clique no nome do pipeline do Jenkins.
- Na barra lateral, clique em Criar agora .
- Para ver os resultados, clique na última execução do pipeline (por exemplo,
#1
) e, em seguida, clique em Console Output (Saída do console ).
Nesse ponto, o pipeline de CI/CD concluiu um ciclo de integração e implantação. Ao automatizar esse processo, o senhor pode garantir que seu código seja testado e implantado por um processo eficiente, consistente e repetível. Para instruir o provedor terceirizado Git a executar o Jenkins sempre que ocorrer um evento específico, como uma solicitação de pull do repositório, consulte a documentação do provedor terceirizado Git.