M05 — Azure Data Factory (ADF): orquestração
Duração: 3h Pré-requisitos: M04 ok (notebook Bronze → Silver roda). Objetivo: criar o ADF, conectar a uma fonte (SQL Server público), trazer dados para o Bronze, e disparar o notebook do M04 a partir do ADF, com trigger por horário.
Por que ADF (e não Databricks Workflows)
| Critério | ADF | Databricks Workflows |
|---|---|---|
| Conectores nativos | 90+ (SAP, Oracle, Salesforce, SFTP, on-prem via Self-Hosted IR) | ~15 (foco em cloud-native) |
| Orquestração entre serviços externos | Muito forte (Logic Apps, Functions, Synapse) | Limitado |
| Custo | Pay por execução de pipeline + DIU/hora de copy | DBU já é caro; workflow é barato |
| UI / aprendizado | Visual, baixo código | Mais “code-first” |
| Quando usar | Ingestão de fontes externas, on-prem, SaaS | Pipelines internos Databricks-only |
Padrão real da indústria:
ADF orquestra a ingestão → grava BronzeADF chama notebook Databricks → transforma Bronze → Silver → GoldADF agenda + monitoraParte 1 — Criar o Data Factory
Variáveis:
$PROJ = "de"; $INIC = "w"; $AMB = "dev"; $REGS = "brs"; $REG = "brazilsouth"$RG = "rg-$PROJ-$AMB-$REGS"$ADF = "adf-$PROJ-$AMB-$REGS"$ST = "st$PROJ$INIC$AMB$REGS"$KV = "kv-$PROJ-$INIC-$AMB"Criar via CLI:
az datafactory create ` --name $ADF ` --resource-group $RG ` --location $REG ` --tags projeto=$PROJ ambiente=$AMB trilha=azure-e2eValidar:
az datafactory show -n $ADF -g $RG --query "{name:name, state:provisioningState, identityType:identity.type}" -o tablePega o principalId da Managed Identity do ADF (vai usar pra dar acesso ao Key Vault e Storage):
$ADFMI = az datafactory show -n $ADF -g $RG --query "identity.principalId" -o tsvWrite-Output "Managed Identity do ADF: $ADFMI"Se vier vazio, habilita system-assigned:
az datafactory update -n $ADF -g $RG --identity-type SystemAssignedParte 2 — Dar permissões à Managed Identity do ADF
ADF vai precisar:
- Ler/Escrever no Storage (
Storage Blob Data Contributor). - Ler segredos do Key Vault (
Key Vault Secrets User). - Disparar runs no Databricks (
Contributorno workspace, e cluster permission dentro do Databricks).
$STID = az storage account show -n $ST -g $RG --query "id" -o tsv$KVID = az keyvault show -n $KV -g $RG --query "id" -o tsv$DBWID = az databricks workspace show -n "dbw-$PROJ-$AMB-$REGS" -g $RG --query "id" -o tsv
# Storageaz role assignment create --assignee $ADFMI --role "Storage Blob Data Contributor" --scope $STID
# Key Vault (RBAC mode)az role assignment create --assignee $ADFMI --role "Key Vault Secrets User" --scope $KVID
# Databricks workspaceaz role assignment create --assignee $ADFMI --role "Contributor" --scope $DBWIDEspere 1-2 min para propagação.
Parte 3 — Conhecer os elementos do ADF
┌────────────────────────────────────────────┐│ AZURE DATA FACTORY │├────────────────────────────────────────────┤│ ││ LINKED SERVICE = "conexão" ││ ↓ aponta para... ││ DATASET = "esquema/local da fonte"││ ↓ usado em... ││ ACTIVITY = "1 passo do pipeline" ││ ↓ compõe... ││ PIPELINE = "fluxo completo" ││ ↓ disparado por... ││ TRIGGER = "quando rodar" ││ ││ INTEGRATION RUNTIME = "onde a copy roda" ││ │└────────────────────────────────────────────┘Linked Services
“Strings de conexão”. Crie um para:
- Azure Key Vault (para ler segredos).
- Azure Data Lake Gen2 (seu storage).
- Azure Databricks (workspace).
- Azure SQL (fonte de exemplo — Parte 5).
Datasets
Apontam para uma tabela/arquivo específico dentro de um Linked Service. Ex.: “tabela Customer no SQL”, “pasta /bronze/sql/customer no ADLS”.
Activities
- Copy (mais usada): copia de um dataset para outro.
- Notebook: dispara notebook Databricks.
- Lookup: lê e devolve para usar em variável.
- ForEach, If, Switch, Until: controle de fluxo.
- Web: HTTP call genérico.
Triggers
- Schedule: hora fixa (ex.: diário 06h).
- Tumbling Window: janelas de tempo sequenciais (bom para backfill).
- Storage Event: dispara quando arquivo chega no ADLS.
- Manual: você roda quando quer.
Parte 4 — Criar Linked Services (via UI, primeira vez)
ADF tem UI muito boa pro primeiro hands-on. Depois (M07) vamos versionar tudo em JSON.
- No portal, abra o ADF → Launch Studio → você vai pra
adf.azure.com. - Esquerda → ícone caixa de ferramentas (Manage) → Linked services → + New.
LS 1: Key Vault
- Tipo: Azure Key Vault.
- Nome:
LS_KV. - Azure Subscription / Key vault name: selecione seu
kv-de-w-dev. - Authentication: System Assigned Managed Identity.
- Test connection → deve dar verde. Se falhar, o role
Key Vault Secrets Usernão propagou ainda; espere 2 min. - Create.
LS 2: ADLS Gen2
- Tipo: Azure Data Lake Storage Gen2.
- Nome:
LS_ADLS. - Authentication: System Assigned Managed Identity.
- Storage account name:
stdewdevbrs. - Test connection → verde.
- Create.
LS 3: Azure Databricks
- Tipo: Azure Databricks.
- Nome:
LS_DATABRICKS. - Azure subscription / workspace: selecione
dbw-de-dev-brs. - Select cluster: Existing interactive cluster → escolha
dev-single-node.- Em prod usa-se New job cluster, que cria/destrói cluster por execução. Mais barato e isolado.
- Authentication: Managed service identity.
- Test connection → verde.
- Create.
LS 4: Fonte de dados (AdventureWorksLT no Azure SQL)
Para ter uma fonte SQL pública, vamos provisionar um Azure SQL Database serverless (essencialmente grátis em free tier para dataset de amostra).
CLI:
$SQL = "sql-$PROJ-$INIC-$AMB" # nome global$SQLADMIN = "sqladmin"$SQLPASS = "ChangeMe!" + (Get-Random)Write-Output "Senha temporária: $SQLPASS (anote!)"
az sql server create ` --name $SQL --resource-group $RG --location $REG ` --admin-user $SQLADMIN --admin-password $SQLPASS
az sql server firewall-rule create ` --resource-group $RG --server $SQL ` --name AllowAzureServices --start-ip-address 0.0.0.0 --end-ip-address 0.0.0.0
az sql db create ` --resource-group $RG --server $SQL ` --name AdventureWorksLT ` --sample-name AdventureWorksLT ` --edition GeneralPurpose --family Gen5 --capacity 2 ` --compute-model Serverless ` --auto-pause-delay 60Guarde a senha no Key Vault:
az keyvault secret set --vault-name $KV --name "sql-admin-password" --value $SQLPASSRemove-Variable SQLPASSNo ADF Studio:
- + New → Azure SQL Database → nome
LS_SQL_SOURCE. - Server:
$SQL.database.windows.net. - Database:
AdventureWorksLT. - Authentication: SQL authentication.
- User name:
sqladmin. - Password: Azure Key Vault → escolhe
LS_KVe nome do segredosql-admin-password. - Test connection → verde.
Parte 5 — Criar Pipeline: Copy SQL → Bronze + Run Notebook
Passo 5.1 — Pipeline novo
ADF Studio → Author (ícone lápis) → + → Pipeline.
Nome: pl_nyctaxi_diario_dev (ou pl_aw_customer_diario_dev se for usar AdventureWorks; ajustamos).
Passo 5.2 — Atividade 1: Copy SalesLT.Customer → Bronze
- Arraste Copy data para o canvas. Nome:
copy_customer_to_bronze. - Source:
- Linked service:
LS_SQL_SOURCE. - Use query:
SELECT * FROM SalesLT.Customer.
- Linked service:
- Sink:
- + New dataset → Azure Data Lake Storage Gen2 → Parquet.
- Nome:
ds_bronze_customer_parquet. - Linked service:
LS_ADLS. - File path:
bronze/source=adventureworks/schema=salesLT/table=customer/ingestion_date=@{formatDateTime(utcNow(),'yyyy-MM-dd')}/. - Confirme.
- Settings → Data integration units:
Auto. Parallel copies:4.
Passo 5.3 — Atividade 2: Notebook Databricks (depende de 1)
- Arraste Notebook para o canvas. Nome:
transforma_customer_silver. - Conecte a saída verde do Copy à entrada do Notebook (= dependência “on success”).
- Aba Azure Databricks → Linked service:
LS_DATABRICKS. - Aba Settings → Notebook path:
/Users/SEU_EMAIL/02_bronze_to_silver(vamos parametrizar — veja Parte 6).
Passo 5.4 — Salvar e debugar
- Clique em Validate (topo) → corrige erros eventuais.
- Debug (não publica ainda): roda o pipeline 1x.
- Acompanhe em Monitor (ícone de medidor) → veja sucesso/falha.
Se OK, Publish all (botão azul, topo).
Parte 6 — Parametrizar para reuso
Pipelines hardcoded não escalam. Vamos parametrizar.
No pipeline, criar parâmetros:
p_data_processamento(string, default =@formatDateTime(utcNow(),'yyyy-MM-dd')).p_tabela_origem(string, default =SalesLT.Customer).
Source do Copy:
- Query:
@concat('SELECT * FROM ', pipeline().parameters.p_tabela_origem, ' WHERE ModifiedDate >= ''', pipeline().parameters.p_data_processamento, '''').
Sink path (no Dataset):
- Parameterize o dataset (no Dataset → Parameters → adicione
p_table,p_date). - File path:
bronze/@concat('source=adventureworks/schema=salesLT/table=', dataset().p_table, '/ingestion_date=', dataset().p_date, '/'). - No Copy → Sink → preencha esses parâmetros vindos do pipeline.
Base parameters do Notebook:
data_processamento=@pipeline().parameters.p_data_processamento.tabela=@pipeline().parameters.p_tabela_origem.
No notebook (M04), receba com dbutils.widgets:
dbutils.widgets.text("data_processamento", "")dbutils.widgets.text("tabela", "")data_proc = dbutils.widgets.get("data_processamento")tabela = dbutils.widgets.get("tabela")Parte 7 — Trigger por horário
ADF Studio → Add trigger (topo) → New/Edit → + New:
- Nome:
tg_diario_06_brt. - Type: Schedule.
- Start date: amanhã 06h.
- Time zone:
(UTC-03:00) Brasilia. - Recurrence: 1 Day.
- OK → vincula ao pipeline → Publish.
Desligue o trigger após testar (
Manage→Triggers→ para o trigger). Não esqueça! Cluster pode subir sozinho às 6h.
Parte 8 — Monitor + Alertas
Monitor
- ADF Studio → Monitor → Pipeline runs → últimos 24h.
- Clique em uma run para ver duração por atividade, payload e erro.
Alertas (em prod)
- ADF → Alerts → + New alert rule → métrica
PipelineFailedRuns> 0 nos últimos 5 min → Action Group: e-mail / Teams.
Pegadinhas
- “Forbidden” ao testar LS → role no Storage/KV não propagou. Esperar 2 min ou reverificar atribuição.
Test connectionLS Databricks falha → MI do ADF não temContributorno workspace. Também precisa do Cluster permission “Can attach to” dentro do Databricks (Workspace → Compute → cluster → Permissions).- Notebook activity demora 5+ min só pra iniciar → cluster estava desligado. Em prod, use Job cluster novo por execução.
- Pipeline sumiu após
Publish→ você estava em uma branch Git (se configurou Git mode). Veja emmain. - Custo escondido: cada execução de pipeline cobra “Activity Run” (USD 0.001/run). Trivial. O caro são os DIUs do Copy (USD ~0.25/DIU/hora). Auto + paralelismo 4 = ok.
Linked Service em JSON (preview de M07)
Linked Services em JSON ficam assim — você vai versionar no Git:
{ "name": "LS_ADLS", "properties": { "type": "AzureBlobFS", "typeProperties": { "url": "https://stdewdevbrs.dfs.core.windows.net" }, "annotations": [], "description": "ADLS Gen2 (dev)" }}E o pipeline (resumido):
{ "name": "pl_aw_customer_diario_dev", "properties": { "activities": [ { "name": "copy_customer_to_bronze", "type": "Copy", "typeProperties": { "...": "..." } }, { "name": "transforma_customer_silver", "type": "DatabricksNotebook", "dependsOn": [{ "activity": "copy_customer_to_bronze", "dependencyConditions": ["Succeeded"] }], "linkedServiceName": { "referenceName": "LS_DATABRICKS", "type": "LinkedServiceReference" }, "typeProperties": { "notebookPath": "/Users/SEU_EMAIL/02_bronze_to_silver", "baseParameters": { "data_processamento": "@pipeline().parameters.p_data_processamento", "tabela": "@pipeline().parameters.p_tabela_origem" } } } ], "parameters": { "p_data_processamento": { "type": "string", "defaultValue": "@formatDateTime(utcNow(),'yyyy-MM-dd')" }, "p_tabela_origem": { "type": "string", "defaultValue": "SalesLT.Customer" } } }}No M07 versionamos esses JSONs.
Checklist de saída
- ADF criado com Managed Identity habilitada.
- 4 Linked Services criados e testados (KV, ADLS, Databricks, SQL).
- Pipeline com Copy + Notebook, executado em Debug com sucesso.
- Pipeline parametrizado (
p_data_processamento,p_tabela_origem). - Notebook recebe widgets corretamente.
- Trigger criado (mas desligado para não disparar sozinho).
- Aprendeu a navegar em Monitor e diagnosticar uma run.