Projeto com todos os processos de DataOps
O projeto representa todos os processos de DataOps, ele contém CI/CD, criado com o Actions Workflows do GitHub para podermos testar o código após o push. Trazendo mais segurança e uniformidade ao código, evitando futuros erros na execução, e integridade ao dividir o código entre a equipe. Estamos utilizando do Google Cloud Platform, para utilização IaaS (Infraestrutura como Serviço), usufruindo da Compute Engine, Databricks e Storage Cloud.
O desenvolvimento da ingestão de dados, estaremos utilizando das tecnologias: Python, Pyspark e Delta Lake. Esquematizando a visualização de dados, utilizaremos do próprio Databricks, e finalizando o fluxo de DataOps, ele deve conter Data Observability e Data Monitoring, nossa infraestrutura ela já consta com otimas ferramentas de monitoração da nossa aplicação, e para fecharmos com chave de ouro iremos utilizar dos loggers, para garantir rastreabilidade de erros no nosso código.
Sem contar que para entregarmos dados com a qualidade, esse projeto conta com boas práticas de Data Quality e testes unitários feito em pyspark, para além de testarmos o resultado esperado em nossas funções, atenderemos os pilares de qualidade dos dados, entre eles: precisão, completude, consistência, validade, exclusividade e pontualidade.
Até então, não é ideal utilizar spark para a pequena quantidade de dados, o ideal é acima de GB (Giga Bytes), mas é um projeto, visa trazer aprendizados da vida real, com conteúdo técnico.
Você pode realizar o clone, e executar o jupyter notebook, mas não vai funcionar como é o verdadeiro objetivo (Utilizar o GCP para execução juntamente com o Databricks).
Para executar o meu projeto, recomendo criar uma conta no google cloud platform, caso não tenha e realizar os passos abaixo de configuração e execução. Nessa doc do projeto tem todos os passos para reproduzir um equivalente ao meu, mas é necessário apenas configurar a conta e importar o arquivo e executar no ambiente configurado.
> git clone https://github.com/annamatias/gcp_dataops.git
Depois que criamos nossa conta, ele já cria um projeto automaticamente, para termos controle de qual projeto estamos mexendo, vamos renomear.
No canto superior direito, ao lado esquerdo da sua foto de perfil da conta do google, temos um menu, iremos clicar nele e ir até Configuração do projeto, conforme imagem abaixo. Eu coloquei o nome de Databricks with GCP, fique a vontade para escolher o seu.
imagem 1 - Acessando configurações
imagem 2 - Alterando nome do projeto e salvando
No canto superior esquerdo, temos um menu bar, acessando ele, vamos atrás do Databricks, o GCP te trás opção de fixar para aparecer logo em cima. Eu fixei para encontra-lo com maior facilidade.
imagem 4 - Databricks fixado
Depois que acessar o databricks, clique em Assinar e concorde com os termos e condições. Antes do botão acessar, irá mostrar o resumo do pedido e quantidade de dias que estará gratuito.
Outro ponto importante você tem que ter um cartão para faturamento, mas fica calmo que a Google não vai sair cobrando nada de você. Muito pelo contrario e é uma experiencia muito boa que eu obtive, quando passa o prazo de gratuidade e você não assina o pacote completo, ele automaticamente apaga e corta os recursos utilizados para não gerar nada, e você não será cobrado.
imagem 3 - Resumo do pedido, ao assinar o Databricks
Faça login sempre com a conta que utiliza o GCP, depois que selecionar o plano que eles indicam para você criar a conta no Databricks, e vai aparecer uma tela conferme a próxima imagem. Observe que eles pedem o nome de uma organização, você escreve o nome que achar melhor.
imagem 5 - Criando conta
Feito o processo acima, importante citar que vai ser enviado um e-mail com a confirmação da criação da conta, parecido com o e-mail abaixo.
imagem 6 - Exemplo e-mail
Depois que chegar o e-mail, volte novamente na console do GCP na aba do Databricks. Iremos clicar em "Gerenciar no fornecedor" nele, ele vai te redirecionar para um link para você fazer login e criar o seu workspace. Antes disso, iremos realizar login novamente e selecionar o plano de assinatura, é só confirmar.
imagem 7 - Gerenciar no fornecedor
imagem 8 - Plano de assinatura
Feito os passos acima, ele vai abrir o workspace, conforme dissemos anteriormente, iremos criar o nosso "Criar Workspace".
Aqui nesse passo é bem simples. Basta colocar o nome do workspace que deseja, você vai copiar do GCP o ID do projeto e colar lá, e na região SEMPRE busque utilizar us-central1
porque esse é uma das regiões gratuitas.
imagem 9 - Configuração workspace
Feito isso, você vai finalizar e vai receber um email, lá vai ter o link que está apto a mexer no databricks, ou então você pode clicar logo em seguida no workspace que criou e aguardar o link ser disponibilizado, conforme exemplo abaixo.
imagem 10 - Workspace preparando o link
Acessando o link, vamos criar um cluster, ele já aparece logo no inicio bem grande, ele já vai criar com as configurações necessárias para você mas você pode alterar de acordo com a necessidade. Como é um projeto simples vou deixar do jeito que está.
imagem 11 - Criando cluster
Reforçando recado IMPORTANTE!
O GCP é gratuito por 90 dias para novos usuários e o Databricks por 14 dias (Lembrando que os prazos sempre estão sujeito a alterações). Fique sempre atento a esse prazo, para que não tenha eventuais cobranças futuramente.
O próprio google alega que depois de 90 dias caso não tenha o upgrade, ele exclui todos os seus projetos, mas faça isso antes..."O seguro morreu de velho" - Como diz meus pais.
Neste projeto iremos realizar a conexão entre Github e Databricks, para CI/CD. Primeiro vamos conectar o nosso repositório.
Se você estive utilizando a versão gratuita talvez tenha limitações para conseguir realizar a integração, caso já tenha muitas coisas dentro do repositório.
Para adicionar, devemos ir na sessão de repositórios, como a imagem abaixo, adicionar as informações que solicitam, basicamente o link do clone do repo. Feito isso é só criar um repositório.
imagem 12 - Criando repositório
Concluindo o passo acima, já é possível visualizar o nosso repositório e as pastas.
O Databricks ele é bem completo, principalmente a sua documentação, onde pela própria interface conseguimos criar uma nova branch, realizar commits, push, pull, merge pela mesma interface.
Para termos nossa esteira de integração e entrega continua, vamos utilizar os workflows do github. Ele vai servir para manter a acuracia do código, para não haver futuros erros e depuração de código demorada para cada usuário que esteja utilizando do repositório.
Estou seguindo essa documentação do github para implementarmos workflows no python.
Primeiro de todos os workflows, baseado em DataOps, iremos implementar o Lint, ele serve para verificar se a escrita do nosso código está correta, evitando erros futuros, antes mesmo de o código estar em vigor executando.
O exemplo a seguir instala ou atualiza o ruff e o usa para fazer lint de todos os arquivos. Para obter mais informações, confira Ruff. Dei uma adaptada baseado na doc do github actions, acrescentei o nome, onde ele vai executar e o jobs build.
Para aplicar, você tem que criar uma nova pasta oculta
.github/workflows
e um arquivo yml, com o conteúdo abaixo.
name: Pylint
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.x'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Lint with Ruff
run: |
pip install ruff
ruff --format=github --target-version=py37 .
continue-on-error: true
A etapa de lint tem continue-on-error: true definido. Isto impedirá que o fluxo de trabalho falhe se a etapa de limpeza de código não for bem-sucedida. Após corrigir todos os erros de limpeza de código, você poderá remover essa opção para que o fluxo de trabalho capture novos problemas.
O nosso primeiro build, a ideia é que falhe mesmo, porque estamos configurando ele. Como estamos realizando a instalação do requeriments no nosso bash, mas ele não existe ainda. Segue um mini gif, ensinando como verificar o seu build aqui no github.
imagem 13 - Verificando build
Mas ele está pronto o nosso build, agora com a implementação do código e executando na máquina local, você consegue realizar testar tudo o que foi instalado no ambiente virtual. Eu comentei esse trecho de dependencias por enquanto para visualizar a funcionalidade e ele funciona lindamente.
imagem 14 - Execução build pylint
Somente seguir o gif abaixo, para realizar o pull após alterações.
imagem 15 - Criação de pull request
Exemplo de criação de pastas e notebook dentro de um repositório no Databricks;
imagem 16 - Criação de pastas dentro de um repositório no Databricks
Feito tudo acima, agora conseguimos utilizar do nosso cluster.
No canto superior esquerdo vamos em Data science e engineering, clique no +
para criar um notebook.
No canto superior esquerdo vamos em Data science e engineering, clique em Workspace
para ver todos os notebooks, pastas criadas dentro do databricks.
Você pode simplesmente baixar e depois arrastas ou procurar via desktop o seu arquivo, e realizar o deploy.
imagem 17 - Deploy de um arquivo
Iremos acessar via console o storage cloud, depois disso é somente adicionar um novo arquivo no caminho desejado. Como vou utilizar o arquivo no databricks, eu adicionei dentro de uma pasta /tmp
imagem 18 - Deploy de um arquivo no storage
Para isso recomendo olhar o código adicionado na estrutura.
Mas deixo aqui uma breve visualização de como é o comportamento após armazenar os dados particionado por uma coluna e no formato Delta via GCP.
imagem 18 - Console storage cloud no GCP após armanezamento
A nossa primeira vez, ela vai estar desconfigurada e vai solicitar que realizemos as devidas configurações. Para isso, no seu email utilizado para realizar os commits dentro do seu repositório, exclusivamente para ele teremos que criar um SSH com permissões para o Databricks ler e gravar os dados.
Documentações de apoio:
- Adicionar uma nova chave SSH à sua conta do GitHub
- Verificando as chaves SSH existentes
- Gerenciar seus tokens de acesso pessoal
Os passos acimas é necessário que você tenha feito o git clone do seu repositório, na sua máquina, abra o terminal de preferência e execute os comandos. Vou deixar abaixo um guia via terminal de como eu fiz e depois via interface onde eu adicionei, mas recomendo que você mesmo faça a leitura.
A geração de SSH para escritura no repositório com o seu e-mail, ela é feita em muitos lugares. Então esse conhecimento vai ser útil em experiências profissionais. Pode ocorrer num Azure DevOps, Amazon, GCP with Databricks e muitos outros.
# Para verificar se existe chave:
> ls -al ~/.ssh
# Para gerar uma nova SSH para o meu e-mail
> ssh-keygen -t ed25519 -C "your-email"
Generating public/private ed25519 key pair.
Enter file in which to save the key (/Users/annakarolinymatias/.ssh/id_ed2558689):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
# Para verificar se foi feito com sucesso
> eval "$(ssh-agent -s)"
Agent pid 59115
# Adicionando a chave
> ssh-add --apple-use-keychain ~/.ssh/id_ed25519
Enter passphrase for /Users/annakarolinymatias/.ssh/id_ed2558689:
Identity added: /Users/annakarolinymatias/.ssh/id_ed2558689 (your-email)
# Para copiar a secret SSH
> pbcopy < ~/.ssh/id_ed25519
# Para visualizar a key para adicionar no Github SSH
> cat ~/.ssh/id_ed25519.pub
ssh-ed2558689 AAAAC3NzLEJ2/zunnWAEXwg8c5m your-email
Exemplo após adicionar a key ao Github via interface
imagem 19 - Exemplo depois de adicionar a key
Feito isso, temos que gerar um token de acesso pessoal para colocar no databricks. Para isso iremos em configurações e depois configurações do desenvolvedor. Gerar um token pessoal e selecionar as permissões desejadas para esse token de acesso.
![image](https://private-user-images.githubusercontent.com/53863170/254382535-509c46a4-8173-471b-aeaa-dbbee163bc46.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjE0NDQyMjQsIm5iZiI6MTcyMTQ0MzkyNCwicGF0aCI6Ii81Mzg2MzE3MC8yNTQzODI1MzUtNTA5YzQ2YTQtODE3My00NzFiLWFlYWEtZGJiZWUxNjNiYzQ2LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDA3MjAlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwNzIwVDAyNTIwNFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWY5MDM3NmU4M2ZhMjYwMjAyZjI0NTZjNmY2NDQyNGU3ZGI4NTZlMDliMmI1NDU2MGFhMWQyYTMzNDkwZDhkM2MmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0.HDjdL6PpaOiv6R8p0gQO0_xUo4RUMYFBhL5HnsnLMZo)
imagem 20 - Caminho feito para obter o token pessoal
Após gerar esse token, acrescentamos ele dentro do nosso databricks, para que seja possível criar branchs e realizar outras operações de leitura e escrita, passando por nossa esteira de integração e entrega continua. Sendo possivel visualizar depois de cama push o nosso build em git actions.
imagem 21 - Exemplificação após acrescentar o token no databricks
Após criarmos uma branch, vamos colocar a mensagem da alteração e adicionamos, feito vai surgir um link de acesso a nossa PR (pull request), iremos acessar e finalizar o processo, conforme abaixo.
imagem 22 - Exemplo via interface de criação de PR
Direcionando para o nosso Github, conseguimos visualizar o nosso pull request e em sequência vamos criar ele.
imagem 23 - Visualização da PR no github
Depois de feito a PR, vamos esperar finalizar o nosso build e em seguida iremos completar o merge na main
.
imagem 24 - Build concluido e realização do merge
Outro ponto importante, na aba actions
é possível verificar todos os build que já ocorreram e os quais estão na fila executando.
Clicando no build também conseguimos visualizar de forma detalhada todas as configurações que acrescentamos para verificar na nossa integração continua.
imagem 25 - Visualizando builds no actions
No canto superior esquerdo vamos em Data science e engineering, clique em Workflows
para ver todos os jobs criados, e para criar um novo, você vai no canto superior direito em Create Job
.
Abordando um assunto de extrema importancia, após passar por muitos processos acima que estão inclusos dentro do DataOps, temos um dos principais pilares. O Data Quality ele diz muito sobre a qualidade dos dados e testes que podem ser implementados para garantir que a informação que temos ela realmente é confiável.
Temos esse artigo: https://www.heavy.ai/technical-glossary/data-quality, e ele é bem objetivo referente a Data Quality. De ferramentas temos algumas como o Great Expectations e o PyDeequ, ambas na linguagem Python, é claro que pode ter outras, mas essas duas é a mais falada.
Indo para a prática dos testes, primeiro eu peguei o código de ELT do notebook e consolidei em um arquivo.py com os métodos isolados para executar localmente e testar-los. Partindo desse principio, vamos alterar o nosso build para testarmos o nosso código.
Antes disso, para executar o nosso código, foi necessário realizar a instalação de algumas dependências. Caso tenha feito o clone desse repositório, você pode apenas instalar os requeriments e já ter acesso a todas as instalações.
pip install delta-spark
pip install pyspark
Feito as instalações acima, acredito que não falte mais nada, então iremos para a correção do nosso build. O que teremos de diferente é o coverage
, ele serve para verificar se estamos com a cobertura 100% de testes para os nossos códigos e utilizamos ele para verificar se ele executou com sucesso, erro ou falha os testes. Adicionamos aqui também um ignore em um erro de linha maior no flake8 e estou ignorando a pasta de notebooks, no meu caso não tem porque deixar rodar o lint nele porque é mais um arquivo de testes.
name: CI
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "3.x"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install flake8 coverage
pip install -r requirements.txt
- name: Lint with flake8
run: |
flake8 --ignore=E501 src/ tests/ --exclude=src/notebooks
- name: Run unit tests and generate coverage report
run: |
coverage run -m unittest -v
coverage report
coverage html
Subindo esse código já vamos ter um build com testes, sempre quando subirmos um push, ele será feito esse build. Falando sobre a construção de testes em pyspark, eu sempre sigo um tutorial da Cambridge, ele é bem objetivo e ele diz sobre uma estrutura base para podermos rodar os nossos testes.
- Logger, para rastrear erros em nivel de loggers (aqui diz muito sobre data observability.
- setUpClass, para criarmos uma sessão no spark, dentro dele iremos executar o nosso código spark.
- tearDownClass, ele serve para apargarmos os arquivos criados temporariamente e finalizar a sessão do spark para não ficar executando infinitamente.
Podendo visualizar o código dessa forma:
class PySparkTest(unittest.TestCase):
@classmethod
def suppress_py4j_logging(cls):
logger = logging.getLogger("py4j")
logger.setLevel(logging.WARN)
@classmethod
def create_testing_pyspark_session(cls):
builder = SparkSession.builder \
.appName("Testes Pyspark") \
.config("spark.sql.extensions", "io.delta.sql.DeltaSparkSessionExtension") \
.config("spark.sql.catalog.spark_catalog", "org.apache.spark.sql.delta.catalog.DeltaCatalog")
spark = configure_spark_with_delta_pip(builder).getOrCreate()
return spark
@classmethod
def setUpClass(cls):
cls.suppress_py4j_logging()
cls.spark = cls.create_testing_pyspark_session()
@classmethod
def tearDownClass(cls):
shutil.rmtree(
"tests/storage_test")
cls.spark.stop()
Se vocês observarem no artigo indicado, sendo ele nossa base para testes, eu fiz algumas adaptações e elas estão descritas no próprio site do Delta, para executarmos funcionalidades do Delta, além de instalarmos temos que subir algumas configurações no spark para ele reconhecer e executar de forma correta. Portanto é possível ver a diferença no nosso setup com configurações especificas direcionada ao Delta. Outro ponto importante, essa configuração ela é especifica para a instalação via pip, conforme o guia de instalação do próprio site da Delta Table.
Construindo alguns testes com unittest, não fica muito diferente do python tradicional (no caso, sem a utilização de algum framework), que é possivel verificar nessa pasta do repositório o código completo https://github.com/annamatias/gcp_dataops/blob/main/tests/unit_tests/tests_ingestion_cardiovascular_diseases_risk.py
Feito os testes, subimos uma PR e assim que subimos já podemos verificar o push, se foi com sucesso ou não. Detalhe tem todas as ocorrências possiveis de execução no nosso build, e fica tão satisfatório de ver. Deixo aqui um exemplo de build com testes.
imagem 26 - Build testes com coverage
No nosso projeto de arquitetura base, abordamos após a ingestão de dados armazenado no storage a visualização de dados. Esse tema é muito extenso, podendo ter varias ferramentas para realizar a visualização de dados. Nesse projeto vamos utilizar o próprio Databricks para a visualização, mas poderiamos fazer dashboards atrativos sobre os dados em um PowerBI e entre outras ferramentas.
Para iniciarmos, primeiro vamos alterar o ambiente para o SQL, iremos na aba paineis e criar um novo dashboard, conforme a próxima imagem.
![image](https://private-user-images.githubusercontent.com/53863170/254744419-ffb6a3cb-6c52-41a3-aa5b-d90f5d44d149.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjE0NDQyMjQsIm5iZiI6MTcyMTQ0MzkyNCwicGF0aCI6Ii81Mzg2MzE3MC8yNTQ3NDQ0MTktZmZiNmEzY2ItNmM1Mi00MWEzLWFhNWItZDkwZjVkNDRkMTQ5LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDA3MjAlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwNzIwVDAyNTIwNFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWRmNWJkZWMwNDlkOWFhODQ2MTM2OTBiODcyY2ViZmExYWU2ZGQ0MmYyNzM4OWUyYThkNzUzZjQ5MWY4YmY1ODcmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0.lCi2_KoNOtLZPO7LyBuk-Db_8a1sA3kLSWeEx4NTALs)
imagem 26 - Interface de criação de dashboards
Aqui tem muitas possibilidades, você pode instalar alguns exemplos de dash e refazer no seu. Você pode criar paineis a partir de uma consulta SQL com a visualização que é a melhor para transmitir um determinado objetivo. Lembrando que visualização de dados não é apenas criar dashboards, é transmitir de uma forma bonita, legivel, objetiva o verdadeiro valor da informação.
Finalizado.
- Github
- https://docs.github.com/pt/actions/learn-github-actions/understanding-github-actions
- https://docs.github.com/pt/actions/automating-builds-and-tests/about-continuous-integration
- https://docs.github.com/pt/actions/automating-builds-and-tests/building-and-testing-python
- https://docs.github.com/pt/actions/automating-builds-and-tests/building-and-testing-python
- GCP
- Databricks
- Data Quality
- Testes
- Data Viz
- CSV Cardiovascular
Anna Karoliny - Mentora, Professora, Desenvolvedora e Engenheira de Dados