# Notebook fora do cluster: migrar para Spark Connect no EMR on EKS

Em 24/09/2026 o Amazon EMR on EKS ganhou sessões interativas via Spark Connect: o driver Spark vira um servidor gRPC no seu cluster EKS e o cliente PySpark fica no IDE de quem escreve o código. Tratei isso como uma migração, não como uma feature — e a parte difícil não é conectar, é o que o endpoint arrasta de rede, de IAM e de custo parado.

- URL: https://fernando.moretes.com/blog/notebook-fora-do-cluster-migrar-para-spark-connect-no-emr-on-eks

- Markdown: https://fernando.moretes.com/blog/notebook-fora-do-cluster-migrar-para-spark-connect-no-emr-on-eks/article.md?lang=pt

- Published: 2026-09-25T10:26:00.087Z

- Category: AWS & Cloud

- Tags: emr-on-eks, spark-connect, kubernetes, data-platform, iam, finops, pyspark

- Reading time: 8 min

- Source: [Run interactive workloads on Amazon EMR on EKS with Spark Connect](https://aws.amazon.com/about-aws/whats-new/2026/09/emr-eks-spark-connect-interactive/)

---

O anúncio de 24 de setembro de 2026 cabe em uma linha: o Amazon EMR on EKS passou a oferecer sessões Spark interativas via Spark Connect, do `emr-7.14.0` em diante. A migração que ele habilita não cabe em uma linha. Tirar o kernel de dentro do cluster e deixar só o driver lá é uma troca de protocolo, de superfície de rede e de modelo de autorização ao mesmo tempo — e cada uma dessas três coisas tem um jeito próprio de falhar às duas da manhã.

## O ponto de partida: o notebook que morava dentro do cluster

O padrão anterior de exploração interativa no EMR on EKS era um managed endpoint do tipo `JUPYTER_ENTERPRISE_GATEWAY`. O kernel roda no cluster, o Livy intermedeia, e o estado da sessão vive no mesmo pod que interpreta o código. Funciona, e cobra três preços que só aparecem na operação.

**A ferramenta é imposta:** quem escreve PySpark abandona o VS Code com linter, type checking e o mesmo `pyproject.toml` do repositório de produção, e passa a escrever numa aba de navegador. Depuração é `print`, não breakpoint.

**O ciclo de deploy é falso:** o código explorado no notebook não é o código que vai para produção. Ele é copiado, adaptado, e a adaptação é onde nasce o defeito que ninguém revisou.

**A janela de manutenção contamina a análise:** upgrade de add-on do EKS, rotação de node group, mudança de AMI — tudo isso derruba o kernel de quem estava no meio de uma investigação, porque o kernel é um pod do seu cluster.

Nenhum desses três problemas é sobre Spark. São problemas de acoplamento entre ambiente de desenvolvimento e plano de execução. É exatamente esse acoplamento que o Spark Connect corta: o cliente é uma biblioteca PySpark leve que fala gRPC com um servidor no driver. O que atravessa a rede é plano lógico, não bytecode.

## A jornada, na ordem em que ela realmente acontece

1. **1. Inventariar o que a sessão vai tocar** — Antes de qualquer `create-security-configuration`, liste os buckets S3, os bancos do Glue Data Catalog e as sub-redes que a exploração precisa. O execution role do endpoint é o teto de acesso de todo mundo que conectar nele — decidir isso depois é decidir errado.

2. **2. Provisionar o AWS Load Balancer Controller e uma sub-rede privada** — O Spark Connect roteia gRPC por um Network Load Balancer interno, e o controller é quem o cria. Cluster sem controller instalado, ou sem sub-rede privada na VPC, não chega a criar o endpoint — falha de pré-requisito, não de configuração do Spark.

3. **3. Criar a security configuration com namespace de sistema** — A infraestrutura do Spark Connect roda num namespace de sistema, separado do namespace de usuário do virtual cluster. E a relação é 1:1 — uma security configuration por virtual cluster, sem reuso. Isso muda o desenho de multi-tenant antes de você escrever a primeira célula.

4. **4. Recriar o virtual cluster com `--session-enabled true`** — Sem essa flag e sem `--security-configuration-id`, o virtual cluster não aceita endpoint Spark Connect. Para quem já roda `StartJobRun` em produção, este é o passo com risco real: é um recurso novo ao lado do antigo, não uma alteração no lugar.

5. **5. Criar o primeiro endpoint e esperar o NLB** — `create-managed-endpoint --type SPARK_CONNECT` com `--session-idle-timeout-in-minutes`. O primeiro endpoint de cada cluster EKS demora minutos a mais: ele provisiona o NLB interno e o VPC interface endpoint (PrivateLink) que todos os endpoints seguintes reaproveitam.

6. **6. Fixar a versão do cliente no repositório, não no README** — `pyspark[connect]==3.5.8` para `emr-7.14.0`; a linha `emr-spark-8.1.0` fixa o cliente em `pyspark[connect]==4.0.2`. Divergência de versão dá erro de conexão ou comportamento estranho, e UDF Python com minor de Python diferente falha com `PYTHON_VERSION_MISMATCH`.

7. **7. Automatizar a renovação do token** — `GetManagedEndpointSessionCredentials` devolve um token temporário usado como `x-aws-proxy-auth` na URL do auth proxy. Quando ele expira, as chamadas gRPC falham com erro de autenticação e é preciso uma `SparkSession` nova — helper no repositório, não instrução no wiki.

## O que muda quando o protocolo vira gRPC

A arquitetura cliente-servidor do Spark Connect parece um detalhe de implementação e é a mudança mais operacional de todas. O cliente PySpark constrói um plano não resolvido, serializa e manda por gRPC sobre TLS; o driver no EKS resolve, otimiza e executa. Três consequências concretas:

**A sessão sobrevive ao seu processo local.** O contexto Spark é persistente e atravessa células e scripts — você mistura Python local com operação remota. Ctrl+C no cliente não derruba o driver, e é por isso que `sessionIdleTimeoutInMinutes` (padrão 60) é o único freio entre um desenvolvedor distraído e um pod de driver vivo a noite inteira.

**A superfície de rede é nova e é interna.** O gRPC entra por um NLB interno numa sub-rede privada, com um VPC interface endpoint na frente. Nada exposto na internet — mas há um componente de rede a mais no diagrama de ameaça, com Flow Logs, health check e grupo de segurança próprios.

**O que não é DataFrame não passa.** Spark Connect suporta DataFrame e SQL em PySpark; API baseada em RDD não é suportada. Isso não é asterisco de rodapé: é o critério de triagem de qual job legado pode ser explorado interativamente e qual precisa ser reescrito antes. Descobrir isso no meio da migração custa duas sprints.

## Da célula ao executor: o caminho de uma operação DataFrame

O cliente nunca fala com o driver direto: passa pelo plano de controle para pegar URL e token, e depois pelo auth proxy dentro do cluster.

### 👤 Cliente — estação de trabalho ou notebook gerenciado

- pyspark[connect] 3.5.8 (emr-7.14.0) (frontend)
- SageMaker Unified Studio notebook gerenciado (frontend)

### 🔐 AWS — plano de controle emr-containers

- CreateManagedEndpoint type=SPARK_CONNECT (security)
- GetManagedEndpointSession Credentials — token (security)

### 📡 VPC — entrada privada de gRPC

- VPC interface endpoint AWS PrivateLink (network)
- NLB interno sub-rede privada (network)

### 🟧 AWS — seu cluster EKS (virtual cluster session-enabled)

- Auth proxy x-aws-proxy-auth (security)
- Spark driver servidor gRPC (pod) (compute)
- Executores dynamicAllocation 3→5 (compute)

### 💾 Dados e evidência

- Amazon S3 dados + logs do Spark (storage)
- Glue Data Catalog metadados de tabela (data)

### Fluxos

- dev -> client: escreve e depura com breakpoint
- dev -> studio: alternativa gerenciada
- client -> api: describe: pega authProxyUrl
- client -> creds: token temporário (SigV4)
- client -> pl: gRPC/TLS — plano lógico
- studio -> pl: mesma sessão, outro cliente
- pl -> nlb: roteia sem sair da VPC
- nlb -> proxy: valida o token da sessão
- proxy -> driver: contexto Spark persistente
- driver -> exec: agenda tasks em pods
- exec -> s3: leitura via execution role IAM
- driver -> glue: resolve tabela e schema
- driver -> s3: s3MonitoringConfiguration

## Três números para levar à reunião de aprovação

- **60 min** — Timeout de ociosidade padrão. `sessionIdleTimeoutInMinutes`. É o único freio automático contra driver e executores vivos depois do fim do expediente.
- **US$ 16,43** — Por mês de NLB parado. US$ 0,0225/h × 730h em us-east-1, antes de qualquer NLCU. O NLB só é removido quando o último virtual cluster session-enabled é apagado.
- **0 RDD** — APIs legadas que atravessam. DataFrame e SQL passam; RDD não é suportado. É o critério de triagem do acervo de jobs antes de prometer migração.

## IAM é o único controle de acesso — e isso redesenha o namespace

Aqui está a decisão que separa quem migrou com cuidado de quem vai descobrir o problema numa auditoria. Endpoints Spark Connect no EMR on EKS **não suportam Lake Formation fine-grained access control** e **não suportam Trusted Identity Propagation**. A documentação é explícita: para impor controle de acesso, use o execution role IAM associado ao endpoint.

Em ambiente com BACEN, PCI-DSS ou LGPD no escopo, isso tem uma leitura direta: o endpoint é a unidade de autorização, não o usuário. Se dez pessoas de dois produtos diferentes compartilham um endpoint, elas compartilham permissão de dado — e o log do CloudTrail vai mostrar o execution role, não quem digitou a query. Rastreabilidade individual você recupera pela sessão (cada uma tem `id` próprio e roda como pods etiquetados por projeto e usuário), não pela identidade do principal que leu o S3.

A consequência de desenho é a multiplicação de recursos. Como cada security configuration tem relação 1:1 com um virtual cluster, isolar por domínio de dado significa um virtual cluster por domínio, cada um com sua security configuration, seu namespace de sistema e seu execution role. E a política de quem cria endpoint precisa de `iam:PassRole` com condição `iam:PassedToService` igual a `emr-containers.amazonaws.com` — sem essa condição, você acabou de dar à engenharia de dados uma primitiva de escalonamento de privilégio.

## Antes e depois, com a terceira coluna que ninguém coloca na tabela
| Critério | Livy / JEG (`JUPYTER_ENTERPRISE_GATEWAY`) | Spark Connect (`SPARK_CONNECT`) | Spark local no laptop |
| --- | --- | --- | --- |
| Onde o código é interpretado | Kernel dentro do cluster; o IDE é o do gateway | Cliente local; só o plano lógico vai por gRPC | Tudo local, com dado de amostra que não representa produção |
| Entrada de rede que você passa a operar | Endpoint gerenciado do EMR, sem NLB próprio | NLB interno + VPC interface endpoint, um por cluster EKS | Nenhuma — e nenhum caminho auditável até o dado real |
| Controle de acesso fino ao dado | Caminhos com Lake Formation e propagação de identidade | Apenas execution role IAM: sem FGAC, sem TIP | Credencial pessoal no `~/.aws`, o pior dos mundos |
| O que quebra primeiro | Manutenção do EKS mata o kernel no meio da análise | Token expira e a `SparkSession` precisa ser refeita | O job passa local e falha em escala, na sexta à noite |

## O custo que não aparece na planilha do POC

Todo custo é de manutenção, e sessão interativa é a categoria de carga que mais premia o desperdício silencioso. Vale montar a conta antes.

**A base já existia:** o EMR on EKS cobra uplift sobre o consumo real — US$ 0,01012 por vCPU-hora e US$ 0,00111125 por GB-hora em us-east-1 — sobre o cluster EKS (US$ 0,10/hora) e o EC2 por baixo.

**O endpoint do exemplo da documentação** — driver com 4 GB, três executores de 2 vCPU e 4 GB, `dynamicAllocation` até cinco — consome algo como 7 vCPU e 16 GB quando está aberto. Isso é aproximadamente US$ 0,089/hora só de uplift. Em 176 horas úteis por mês, cerca de US$ 15,60 por sessão viva, antes do EC2.

**O componente novo é o piso:** o NLB interno nasce com o primeiro endpoint e só é removido quando o último virtual cluster session-enabled é apagado. US$ 0,0225/hora são US$ 16,43/mês rodando, com zero sessão conectada, mais NLCU.

O desenho que evita a surpresa é banal e quase ninguém faz: `sessionIdleTimeoutInMinutes` bem abaixo do padrão de 60 para endpoint de exploração, tag de projeto e usuário obrigatória para atribuir o gasto no Cost Explorer, e um alarme sobre número de endpoints `ACTIVE` — não sobre a fatura, que chega tarde demais.

> **Os quatro modos de falha que eu vi na ordem errada:** **Token expirado é falha de autenticação, não de rede:** as chamadas gRPC caem e o time abre ticket de VPC. **Versão do cliente divergente** dá erro de conexão ou comportamento estranho, e UDF Python com minor diferente falha com `PYTHON_VERSION_MISMATCH` — nenhum dos dois grita a causa. **Security configuration não se apaga** antes de todos os endpoints que a usam serem apagados; script de teardown que ignora a ordem trava. **O limite de API é baixo onde dói:** `GetManagedEndpointSessionCredentials` tem bucket de 25 com reposição de 1 por segundo, e o teto agregado de todas as APIs do EMR on EKS é 200 com 20/s. Um wrapper que pede token por célula, com vinte pessoas online, encontra throttling antes de encontrar escala.

## Anti-padrões

- **Um endpoint para toda a engenharia de dados**: como a autorização é o execution role do endpoint, endpoint compartilhado é permissão compartilhada — e o CloudTrail registra o role, não a pessoa.
- **Tratar Spark Connect como caminho de produção**: sessão interativa é para exploração e desenvolvimento incremental. Pipeline agendado continua sendo `StartJobRun`, com retry, idempotência e observabilidade de job, não uma sessão que alguém esqueceu aberta.
- **Manter o padrão de 60 minutos de ociosidade em ambiente de custo controlado**: é o valor que faz sentido para o serviço, não para o seu teto de gasto.
- **Prometer migração de job RDD**: API baseada em RDD não passa pelo Spark Connect. O inventário vem antes do compromisso com data.
- **Instalar o AWS Load Balancer Controller às pressas para destravar o endpoint**: ele passa a mandar em NLB da sua VPC. Isso é decisão de plataforma, não passo de tutorial.

## Leitura pelos pilares do Well-Architected

- **security**: O endpoint é a fronteira de autorização: sem Lake Formation FGAC e sem Trusted Identity Propagation, o execution role define tudo. Restrinja a política a `arn:aws:emr-containers:...:/virtualclusters/<id>/endpoints/*` e exija `iam:PassedToService` igual a `emr-containers.amazonaws.com` no `iam:PassRole`. O gRPC nunca sai da VPC — NLB interno em sub-rede privada com PrivateLink na frente.
- **reliability**: O primeiro endpoint de cada cluster EKS demora minutos a mais porque provisiona NLB e VPC endpoint; trate isso como passo de bootstrap, não como latência de uso. Token expirado exige `SparkSession` nova, então o cliente precisa de renovação automática antes de ganhar usuário.

> **Nota de curadoria:** Se eu fosse fazer essa migração numa plataforma financeira, começaria por um único domínio de dado — um virtual cluster novo, session-enabled, com execution role que só lê o bucket daquele domínio — e deixaria o caminho Livy de pé em paralelo por um trimestre. Não é medo de tecnologia nova; é que a ausência de Lake Formation FGAC muda o desenho de isolamento, e esse tipo de mudança não se descobre em POC de duas semanas. A lição que eu já paguei: capacidade nova de exploração sempre vira consumo permanente, então eu entrego o endpoint junto com o timeout curto e o painel de gasto por tag no mesmo dia — acrescentar controle depois de o time se acostumar ao conforto é uma conversa muito pior. E manteria produção em `StartJobRun`, sem exceção, porque a sessão interativa é excelente para descobrir a resposta e péssima para repeti-la todos os dias.

## Referências

- [AWS What's New — Run interactive workloads on Amazon EMR on EKS with Spark Connect (24/09/2026)](https://aws.amazon.com/about-aws/whats-new/2026/09/emr-eks-spark-connect-interactive/)
- [Amazon EMR on EKS Development Guide — Run interactive sessions through Spark Connect](https://docs.aws.amazon.com/emr/latest/EMR-on-EKS-DevelopmentGuide/emr-eks-spark-connect.html)
- [AWS Big Data Blog — Announcing Spark Connect on Amazon EMR on EC2 (23/09/2026)](https://aws.amazon.com/blogs/big-data/announcing-spark-connect-on-amazon-emr-on-ec2-interactive-pyspark-anywhere/)
- [Amazon EMR on EKS — service endpoints and service quotas](https://docs.aws.amazon.com/emr/latest/EMR-on-EKS-DevelopmentGuide/service-quotas.html)
- [Amazon EMR pricing — EMR on EKS uplift per vCPU-hour and GB-hour](https://aws.amazon.com/emr/pricing/)
- [Elastic Load Balancing pricing — Network Load Balancer hourly and NLCU rates](https://aws.amazon.com/elasticloadbalancing/pricing/)

## Veredito

Migre — para exploração, com escopo estreito e data marcada de revisão. O Spark Connect no EMR on EKS resolve um problema real e antigo: o desenvolvedor volta a usar o IDE dele, com breakpoint, sobre dado de escala de produção, e o driver continua dentro do cluster que a plataforma já opera e já monitora. Vale o esforço quando três condições estão juntas: o acervo é DataFrame e SQL em PySpark, o controle de acesso por execution role é suficiente para o seu regime regulatório, e existe alguém responsável por apagar endpoint ocioso. Falhando qualquer uma das três, espere: sem FGAC e sem propagação de identidade, um endpoint compartilhado entre domínios de dado é um achado de auditoria esperando a data. E em nenhum cenário isso substitui `StartJobRun` em produção — o ganho aqui é no ciclo de descoberta, não no de execução.

**Rating:** Adotar com escopo controlado
