Arquitetura

Como o laboratório é montado. O site é estático, na Cloudflare, e a API, em Go, roda em duas máquinas da Oracle Cloud em São Paulo, atrás de um balanceador de carga.

Do cliente à API

O cliente faz dois pedidos independentes. O primeiro vai ao Cloudflare Workers, que serve a interface web, uma SPA em React com HTML, JS e CSS estáticos. O segundo é feito pela própria interface, já no cliente: o JavaScript dela chama a API em api.probekit.cc, em outra origem e com CORS. Esse pedido passa pelo proxy da Cloudflare, chega ao NLB da Oracle Cloud e cai em uma das duas máquinas, onde o binário em Go termina o TLS. O Workers não fica no caminho da API.

Antes de qualquer pacote sair, a API confere o destino e recusa endereços privados, de loopback e de link-local. O ping usa ICMP de verdade, então a latência mostrada é a da máquina até o alvo. O limite é de 50 requisições a cada 5 minutos por visitante. Como o pedido chega pela Cloudflare, a API lê o endereço do visitante no cabeçalho CF-Connecting-IP, mas só quando a conexão vem de uma faixa de endereços da Cloudflare; quem acessar o balanceador direto não consegue forjá-lo. A contagem fica na memória de cada servidor.

Fluxo de uma requisição

Arquitetura do site e da API: o cliente faz dois pedidos independentes. O primeiro vai ao Cloudflare Workers, na borda da Cloudflare (frontend), que entrega a interface web; ela roda no navegador. O segundo, feito pela interface, vai a api.probekit.cc: passa pelo proxy da Cloudflare, também na borda, e pelo NLB da OCI em sa-saopaulo-1 até uma das duas VMs com a API em Go. A resposta volta pelo mesmo caminho.

  1. 01O cliente carrega a interfaceWorkers

    O cliente acessa probekit.cc. O Cloudflare Workers, na borda da Cloudflare, entrega a interface web (HTML, JS e CSS estáticos), que passa a rodar no navegador. O Worker só serve arquivos.

  2. 02A interface chama a APIapi.probekit.cc

    O JavaScript da interface, já no navegador, faz fetch para api.probekit.cc, outra origem, com CORS. O pedido passa pelo proxy da Cloudflare, também na borda, e o Worker não participa.

  3. 03O NLB escolhe uma VMTCP 443

    O Network Load Balancer da OCI, em L4 na porta TCP 443, repassa a conexão para uma das duas VMs.

  4. 04A API valida o destino

    A API em Go termina o TLS no próprio binário e recusa endereços privados, de loopback e de link-local.

  5. 05A ferramenta executa

    O ping envia ICMP. O DNS usa o resolvedor do sistema da VM, não os servidores autoritativos do domínio.

  6. 06A resposta volta em JSONJSON

    A resposta segue o mesmo caminho de volta até o cliente, com os cabeçalhos CORS.

Pipeline

Do pull request à produção, o pipeline tem quatro fases: pull request e CI, build e release, deploy e recuperação. A API e o site seguem trilhas diferentes no build e no deploy, porque o gatilho, o release e o deploy de cada um são diferentes. O diagrama no fim da seção mostra as fases na ordem.

01 · Pull request e CI
Toda mudança entra por um pull request que aponta para a main, e o CI roda nele, antes do merge, com três jobs: Go (testes e linters), NPM (lint, verificação de formato, testes e build) e Terraform (fmt, init sem backend e validate, nunca um plan). O ruleset da main só deixa o merge acontecer com esses três checks verdes (Go, Terraform e NPM), e só aceita merge commit. O merge na main é o que dispara a fase seguinte.
02 · Build e release
As trilhas se separam. Uma mudança em backend/** dispara o release da API: testes, cálculo da versão e, só se as mensagens de commit pedirem (feat, fix, perf ou uma quebra de compatibilidade, com BREAKING CHANGE: ou !:), o binário Linux com checksum e a release no GitHub. Uma mudança em frontend/** dispara o build do site: lint, formato, testes, build e uma checagem de que a URL da API entrou no build.
03 · Deploy
O deploy da API é manual: um job plan gera o plano do Terraform, cifrado, e o job deploy, no ambiente production, aplica o plano, atualiza a VM 1, depois a VM 2, e verifica a API pública. O deploy do site é automático na main, depois do build, mas espera a aprovação do ambiente production; publica com wrangler e verifica o site e se a API aceita a origem dele. A API chega à Oracle Cloud; o site, à Cloudflare.
04 · Recuperação
Cada produto tem um workflow de rollback, manual e também no ambiente production, fora do caminho normal. O do site volta o Worker para uma versão anterior ou para a informada; o da API marca uma release anterior como a mais recente. Os dois conferem o alvo antes e verificam no fim que o rollback valeu.
O caminho de uma mudança no pipeline

Pipeline do Probekit em quatro fases: pull request e CI (a mudança é validada em três jobs, Go, NPM e Terraform, antes do merge na main), build e release (release da API e build do site, em trilhas separadas, disparados pelo merge), deploy (API manual e site automático, ambos com aprovação do ambiente production, na Oracle Cloud e na Cloudflare) e recuperação (rollbacks manuais da API e do site).

  1. 01O pull request roda o CICI

    Toda mudança entra por um pull request que aponta para a main, e o CI roda nele, antes do merge: Go (testes e linters), NPM (lint, verificação de formato, testes e build) e Terraform (fmt, init sem backend e validate). A main só aceita o merge com os três verdes.

  2. 02O merge na main dispara o build e o releaserelease

    Uma mudança em backend/** roda os testes, calcula a versão e só se as mensagens de commit pedirem (feat, fix, perf ou quebra de compatibilidade) gera o binário e a release. Uma mudança em frontend/** roda o build do site.

  3. 03Deploy, com aprovação do ambiente productionproduction

    O deploy da API é manual: plan, aprovação, apply e as duas VMs, uma depois da outra. O deploy do site é automático na main, mas espera a aprovação; publica com wrangler e verifica o site.

  4. 04Recuperação, sob demandarollback

    Cada produto tem um rollback manual, também no ambiente production. O do site volta a versão do Worker; o da API marca uma release anterior como a mais recente.

Infraestrutura

O Terraform cria a rede, as duas máquinas e o balanceador de carga na Oracle Cloud, e o registro DNS da API na Cloudflare. O estado fica num bucket da Oracle Cloud.

O Worker do site não é criado pelo Terraform: quem o publica é o pipeline.

A infraestrutura criada pelo Terraform

A infraestrutura do Probekit em Terraform: o código em arquivos .tf passa por plan e apply, que criam na Oracle Cloud a rede, as duas VMs e o balanceador de carga e, na Cloudflare, o registro DNS da API. O estado fica num bucket remoto da Oracle Cloud. O Worker do site é publicado pelo pipeline, não pelo Terraform.

  1. 01Escrever o código*.tf

    A infraestrutura é descrita em arquivos do Terraform, na pasta infra/terraform do repositório.

  2. 02Plan e applyplan → apply

    O plan e o apply rodam no workflow Deploy API, que é disparado à mão. O plan fica salvo, e o apply só segue depois da aprovação do ambiente production e aplica exatamente esse plano.

  3. 03Criar a rede, as duas VMs e o balanceador na OCI

    Na Oracle Cloud o Terraform cria a rede, as duas máquinas virtuais da API e o balanceador de carga que fica na frente delas.

  4. 04Criar o registro DNS da API na Cloudflare

    Na Cloudflare o Terraform cria o registro DNS api, com proxy, apontando para o balanceador.

  5. 05Guardar o estado num bucket remoto

    O estado do Terraform fica num bucket da Oracle Cloud, e não na máquina de quem roda. É por isso que o CI consegue rodar o plan e o apply. O Worker do site não faz parte: quem o publica é o pipeline.

Princípios

Roda de verdade
Em produção o resultado vem da API, nunca de uma simulação, e a página diz de onde o teste saiu.
Fica registrado
As escolhas difíceis viram ADRs: notas curtas sobre o que foi decidido e por quê.
Código aberto
O código é MIT e está inteiro no repositório, com o Terraform e os workflows.