Validação arquitetural de carga — Agent Framework OCI / OKE
Este pacote executa validação arquitetural e teste de carga do agent_template_backend em OCI OKE usando persistência compartilhada, OCI Generative AI, Langfuse v3 e um OCI Load Balancer preexistente. O pacote não cria um novo OCI Load Balancer: o acesso externo é feito por NodePort nos workers e por um listener/backend set criado no LB informado em EXISTING_LB_OCID.
Arquitetura do teste
Cliente / k6 externo
|
v
OCI Load Balancer existente :BACKEND_LISTENER_PORT
|
v
backend set agent-framework-loadtest
|
+--> worker-1:BACKEND_NODE_PORT
+--> worker-2:BACKEND_NODE_PORT
+--> worker-N:BACKEND_NODE_PORT
|
v
Kubernetes Service NodePort
|
v
agent-template-backend (HPA)
|
+--> Autonomous Database / wallet
+--> Mongo-compatible endpoint
+--> OCI Generative AI
+--> Langfuse v3
O Service agent-template-backend continua ClusterIP para testes internos. O Service agent-template-backend-lb é NodePort; ele não solicita um novo LB à OCI.
Estrutura principal
deploy/oke/load-test/
.env.loadtest.example
.env.runtime # gerado; não commitar
.env.langfuse # gerado; não commitar
README.md
k8s/
agent-backend.yaml
k6-job.yaml
langfuse/
langfuse-k8s.yaml
loadgen/
loadtest.js
scripts/
prepare_env.sh
configure_kubeconfig.sh
deploy_langfuse.sh
sync_langfuse_client_secret.sh
validate_langfuse_integration.sh
build_push_backend.sh
deploy_backend.sh
configure_existing_lb.sh
validate_dependencies.sh
smoke_test.sh
run_load_test.sh
run_architecture_suite.sh
watch_test.sh
collect_results.sh
1. Preparar .env.runtime
Execute da raiz do repositório:
./deploy/oke/load-test/scripts/prepare_env.sh
O script usa templates/agent_template_backend/.env como configuração principal, completa somente as chaves ausentes com deploy/oke/load-test/.env.loadtest.example e gera:
deploy/oke/load-test/.env.runtime
deploy/oke/load-test/.env.langfuse
Importante sobre Langfuse: o script pode gerar valores de inicialização (
LANGFUSE_INIT_*) para bootstrap headless, mas, para esta validação, o procedimento recomendado é confirmar o ambiente pela UI do Langfuse e criar manualmente o usuário, organização/empresa, projeto e API keys. As chaves criadas na UI devem ser copiadas para os arquivos de configuração antes do deploy do backend.
Preencha no .env.runtime os parâmetros reais de OCI/DB/OCIR e o LB existente. Para o LB:
EXISTING_LB_OCID=ocid1.loadbalancer.oc1.sa-saopaulo-1....
BACKEND_SET_NAME=agent-framework-loadtest
BACKEND_LISTENER_NAME=agent-framework-loadtest
BACKEND_LISTENER_PORT=8000
BACKEND_LISTENER_PROTOCOL=HTTP
BACKEND_HEALTH_PATH=/health
BACKEND_NODE_PORT=32116
LOADTEST_TARGET_MODE=external
Opcionalmente, fixe diretamente a URL externa:
LOADTEST_EXTERNAL_URL=http://<IP_DO_LB>:8000
2. Wallet e acesso ao OKE
Copie a wallet real para:
templates/agent_template_backend/wallet/
Ela será criada como Kubernetes Secret e montada em /app/wallet.
Configure kubeconfig:
./deploy/oke/load-test/scripts/configure_kubeconfig.sh
kubectl get nodes -o wide
kubectl top nodes
kubectl top nodes deve funcionar para o HPA baseado em CPU/memória.
3. Subir o Langfuse v3 e criar manualmente usuário, organização, projeto e API keys
3.1 Subir a infraestrutura do Langfuse
Execute:
./deploy/oke/load-test/scripts/deploy_langfuse.sh
O deploy cria os componentes Kubernetes do Langfuse v3, incluindo web, worker, Postgres, Redis, ClickHouse, MinIO e os Secrets de runtime.
Se a etapa de validação autenticada falhar porque ainda não existem API keys válidas, prossiga com a inicialização manual abaixo. A infraestrutura do Langfuse já pode estar operacional mesmo que a validação das chaves ainda não tenha passado.
Confirme:
kubectl -n langfuse get pods
kubectl -n langfuse get svc langfuse-web
Os pods principais devem estar Running/Ready.
3.2 Abrir a interface do Langfuse
Abra um port-forward em outro terminal:
kubectl -n langfuse port-forward --address 127.0.0.1 svc/langfuse-web 3005:3000
Acesse no navegador:
http://127.0.0.1:3005
3.3 Criar o usuário
Na primeira abertura do Langfuse:
- crie o usuário administrador;
- faça login com esse usuário;
- confirme que a interface principal do Langfuse foi carregada.
Para ambiente de teste, pode ser utilizado um usuário dedicado ao load test. Não use credenciais pessoais de produção no arquivo do projeto.
3.4 Criar a organização/empresa
Dentro do Langfuse, crie ou selecione a organização que será usada pelo teste.
Sugestão de nome:
Agent Framework OCI
A UI do Langfuse pode usar o termo Organization. Neste manual, organização/empresa representam a mesma entidade de agrupamento do projeto.
3.5 Criar o projeto
Dentro dessa organização, crie o projeto que receberá os traces do teste.
Sugestão:
Agent Framework Load Test
Não prossiga para o backend enquanto não conseguir abrir esse projeto na UI.
3.6 Criar as API keys do projeto
No projeto criado, abra a área de configuração/API Keys e crie um novo par de credenciais.
Você receberá duas chaves:
Public Key: pk-lf-...
Secret Key: sk-lf-...
Atenção: copie a
Secret Keyno momento da criação. Dependendo da tela/versão, ela pode não ser exibida novamente.
Essas são as credenciais que o agent_template_backend usará para enviar traces ao Langfuse.
3.7 Copiar as API keys para .env.langfuse
Edite:
deploy/oke/load-test/.env.langfuse
Substitua/ajuste estas quatro linhas com o par criado na UI:
LANGFUSE_PUBLIC_KEY=pk-lf-COLE_A_PUBLIC_KEY_AQUI
LANGFUSE_SECRET_KEY=sk-lf-COLE_A_SECRET_KEY_AQUI
LANGFUSE_INIT_PROJECT_PUBLIC_KEY=pk-lf-COLE_A_MESMA_PUBLIC_KEY_AQUI
LANGFUSE_INIT_PROJECT_SECRET_KEY=sk-lf-COLE_A_MESMA_SECRET_KEY_AQUI
Para um projeto já criado manualmente na UI, os campos LANGFUSE_INIT_PROJECT_* são mantidos com os mesmos valores para que os scripts de sincronização do pacote encontrem um único par de chaves consistente.
Não exiba nem versione a LANGFUSE_SECRET_KEY.
3.8 Copiar as API keys para .env.runtime
Edite também:
deploy/oke/load-test/.env.runtime
Garanta:
ENABLE_LANGFUSE=true
LANGFUSE_HOST=http://langfuse-web.langfuse.svc.cluster.local:3000
LANGFUSE_PUBLIC_KEY=pk-lf-COLE_A_PUBLIC_KEY_AQUI
LANGFUSE_SECRET_KEY=sk-lf-COLE_A_SECRET_KEY_AQUI
As chaves em .env.runtime devem ser exatamente as mesmas criadas no projeto pela UI.
3.9 Atualizar o Secret Kubernetes do Langfuse
Depois de colar as chaves nos arquivos, atualize Secret/langfuse-runtime sem imprimir os valores:
set -a
source deploy/oke/load-test/.env.langfuse
set +a
kubectl -n langfuse create secret generic langfuse-runtime \
--from-env-file=deploy/oke/load-test/.env.langfuse \
--dry-run=client -o yaml | kubectl apply -f -
Para um projeto criado manualmente, não é necessário recriar o banco do Langfuse. O objetivo desta etapa é manter o Secret usado pelos scripts sincronizado com as credenciais reais do projeto.
3.10 Sincronizar as chaves para o namespace do backend
Execute:
LANGFUSE_NAMESPACE=langfuse \
K8S_NAMESPACE=agent-load-test \
./deploy/oke/load-test/scripts/sync_langfuse_client_secret.sh
O script cria/atualiza:
namespace: agent-load-test
Secret: langfuse-client
com:
LANGFUSE_PUBLIC_KEY
LANGFUSE_SECRET_KEY
LANGFUSE_HOST
Confira apenas a existência do Secret:
kubectl -n agent-load-test get secret langfuse-client
Para conferir somente a Public Key:
kubectl -n agent-load-test get secret langfuse-client \
-o jsonpath='{.data.LANGFUSE_PUBLIC_KEY}' | base64 -d
echo
Ela deve começar com:
pk-lf-
3.11 Validar autenticação no Langfuse antes de prosseguir
Execute:
./deploy/oke/load-test/scripts/validate_langfuse_integration.sh
Resultado esperado:
LANGFUSE_AUTH_OK
Esse teste chama o Langfuse pela rede interna do OKE e usa LANGFUSE_PUBLIC_KEY + LANGFUSE_SECRET_KEY. Portanto, LANGFUSE_AUTH_OK comprova que o par de chaves é aceito pelo projeto.
Se receber 401/403, não prossiga para o backend. Revise:
.env.langfuse
.env.runtime
Secret/langfuse-runtime no namespace langfuse
Secret/langfuse-client no namespace agent-load-test
3.12 Ordem obrigatória antes de continuar
A sequência esperada é:
Langfuse Kubernetes operacional
↓
criar usuário
↓
criar/selecionar organização (empresa)
↓
criar projeto
↓
criar Public Key + Secret Key
↓
colar keys em .env.langfuse
↓
colar keys em .env.runtime
↓
atualizar Secret/langfuse-runtime
↓
sync_langfuse_client_secret.sh
↓
validate_langfuse_integration.sh
↓
LANGFUSE_AUTH_OK
↓
somente então fazer deploy do backend
4. Build e push do backend
Garanta que o repositório OCIR já exista e faça login:
docker login gru.ocir.io
./deploy/oke/load-test/scripts/build_push_backend.sh
A imagem utilizada fica registrada em deploy/oke/load-test/.backend-image.
5. Deploy do backend com NodePort
Execute:
./deploy/oke/load-test/scripts/deploy_backend.sh
O deploy cria/atualiza:
agent-backend-runtime;agent-backend-wallet;langfuse-client;- Deployment do backend;
ClusterIPinterno;NodePortexterno (BACKEND_NODE_PORT, default32116);- HPA;
- PDB.
Confira:
kubectl -n agent-load-test get pods -o wide
kubectl -n agent-load-test get svc
kubectl -n agent-load-test get hpa
O Service externo deve aparecer como NodePort, e não LoadBalancer.
6. Reutilizar o OCI Load Balancer existente
Depois que o NodePort existir:
./deploy/oke/load-test/scripts/configure_existing_lb.sh
O script é idempotente. Ele:
- valida
EXISTING_LB_OCID; - descobre
BACKEND_NODE_PORTno Service; - verifica o backend set;
- cria
BACKEND_SET_NAMEse não existir; - aguarda a operação OCI concluir;
- descobre os
InternalIPdos workers OKE; - adiciona os workers ainda não cadastrados como
<worker-ip>:<node-port>; - verifica/cria o listener
BACKEND_LISTENER_NAME; - aponta o listener para o backend set;
- mostra o health do backend set.
Arquitetura resultante:
OCI LB existente
-> listener :8000
-> backend set
-> worker InternalIP:32116
-> Service NodePort
-> pods do backend
As Security Lists/NSGs precisam permitir tráfego do LB para os workers na porta NodePort.
7. Validar dependências antes do smoke/carga
Execute:
./deploy/oke/load-test/scripts/validate_dependencies.sh
Esse teste é executado de dentro do OKE usando a mesma imagem, env e wallet do backend. Ele valida:
- conexão real com Oracle/Autonomous usando
/app/wallet; pingreal no Mongo-compatible endpoint;/api/public/healthdo Langfuse;- presença das API keys Langfuse;
- autenticação real em
/api/public/projectsusandoLANGFUSE_PUBLIC_KEY+LANGFUSE_SECRET_KEY.
Resultado esperado termina com:
dependencies: ALL_DEPENDENCIES_OK
Esse passo valida conectividade e autenticação. Ele não faz uma chamada de negócio ao LLM; isso é responsabilidade do smoke test.
8. Smoke test end-to-end
Externo — caminho real pelo OCI LB existente
./deploy/oke/load-test/scripts/smoke_test.sh external
Caminho validado:
cliente
-> OCI LB existente
-> listener
-> backend set
-> NodePort
-> pod
-> LangGraph/framework
-> RAG/memória conforme configuração
-> OCI Generative AI (quando LLM_PROVIDER=oci_sdk)
-> persistência
-> Langfuse
O smoke executa /health, depois POST /gateway/message. Quando Langfuse está habilitado, ele também consulta a Public API autenticada e aguarda o trace da sessão smoke-*. O sucesso final inclui:
LANGFUSE_TRACE_OK
Assim, um HTTP 200 sozinho não é mais considerado evidência suficiente de observabilidade.
Interno — sem OCI LB
./deploy/oke/load-test/scripts/smoke_test.sh internal
Esse modo usa o ClusterIP e serve para separar problemas do backend/Kubernetes de problemas do LB externo.
Para provar chamadas reais de OCI Generative AI, mantenha:
LLM_PROVIDER=oci_sdk
OCI_AUTH_MODE=oke_workload_identity
Nos logs devem aparecer OCI SDK GenAI client, OnDemandServingMode e eventos llm.* com o modelo configurado.
9. Teste de carga
Interno
./deploy/oke/load-test/scripts/run_load_test.sh internal
Alvo:
http://agent-template-backend.agent-load-test.svc.cluster.local:8000
Externo pelo LB preexistente
./deploy/oke/load-test/scripts/run_load_test.sh external
O script resolve o endereço do LB usando EXISTING_LB_OCID via OCI CLI, ou usa LOADTEST_EXTERNAL_URL se definida.
Acompanhe:
kubectl -n agent-load-test logs -f job/agent-load-generator
./deploy/oke/load-test/scripts/watch_test.sh
Distribuição pelo LB:
./deploy/oke/load-test/scripts/check_load_balancing.sh
10. Suite arquitetural
Externa:
./deploy/oke/load-test/scripts/run_architecture_suite.sh external
Interna:
./deploy/oke/load-test/scripts/run_architecture_suite.sh internal
Cenários padrão:
warmup 5 rps 2 min unique_sessions
baseline 25 rps 5 min unique_sessions
scale 100 rps 10 min unique_sessions
shared-state 50 rps 10 min shared_sessions
unique_sessions estressa criação de estado/checkpoints/DB/Langfuse/LLM. shared_sessions reutiliza sessões entre chamadas e é importante para provar que a aplicação não depende de memória local do pod.
11. Execução completa automatizada
Depois de preencher .env.runtime e colocar a wallet:
./deploy/oke/load-test/scripts/01_deploy_all.sh
Ordem:
Langfuse + API keys
-> build/push backend
-> deploy backend NodePort
-> configurar LB existente
-> validar dependências
-> smoke externo + confirmação do trace Langfuse
Só depois desse fluxo passar execute carga sustentada.
12. Critérios de aprovação
Antes da carga:
kubectl nodes Ready
metrics-server OK
Langfuse AUTH OK
Oracle connection OK
Mongo ping OK
backend rollout OK
OCI LB backend-set healthy
smoke HTTP 200
OCI GenAI real nos logs (perfil end-to-end)
LANGFUSE_TRACE_OK
Durante a carga, procure:
- nenhum
CrashLoopBackOff/OOMKilled; - ausência de deadlock/cross-event-loop errors;
- sessão consistente entre pods;
- checkpoints recuperáveis por qualquer réplica;
- HPA escalando quando as métricas atingirem os targets;
- 5xx próximos de zero;
- 429/timeouts do LLM separados de erros internos;
- traces chegando ao Langfuse sem criar falha em cascata.
O backend é I/O-bound em chamadas de LLM/DB; CPU/memória não são métricas perfeitas de autoscaling. Para produção, considere métricas de aplicação como in_flight_requests, request_queue_depth e p95 de latência via KEDA/Prometheus Adapter.
13. Coletar evidências
./deploy/oke/load-test/scripts/collect_results.sh
Os arquivos ficam em deploy/oke/load-test/results/. Use em conjunto com Langfuse para correlacionar request/session/trace.
14. Resiliência
Com carga ativa:
kubectl -n agent-load-test delete pod <pod>
kubectl -n agent-load-test rollout restart deployment/agent-template-backend
kubectl -n agent-load-test rollout status deployment/agent-template-backend
A perda de uma réplica não deve perder estado compartilhado nem interromper o serviço enquanto houver capacidade saudável.
15. Troubleshooting de credenciais Langfuse em instalação já existente
O bootstrap headless é idempotente e foi desenhado para criar recursos que ainda não existem. Em um ambiente de teste que já possua PVCs do Langfuse inicializados anteriormente com outro projeto ou outro par de API keys, validate_langfuse_integration.sh pode retornar erro de autenticação mesmo que /api/public/health esteja 200.
Primeiro confirme sem revelar a secret key:
kubectl -n langfuse get secret langfuse-runtime \
-o jsonpath='{.data.LANGFUSE_INIT_PROJECT_PUBLIC_KEY}' | base64 -d; echo
kubectl -n agent-load-test get secret langfuse-client \
-o jsonpath='{.data.LANGFUSE_PUBLIC_KEY}' | base64 -d; echo
As public keys precisam ser iguais. Depois execute:
./deploy/oke/load-test/scripts/validate_langfuse_integration.sh
Se as keys estiverem sincronizadas no Kubernetes mas a API autenticada falhar, o banco persistente do Langfuse provavelmente já contém credenciais diferentes. Para um ambiente descartável de load test, a opção mais limpa é recriar a stack/PVCs do Langfuse e executar deploy_langfuse.sh novamente. Não apague PVCs de um Langfuse que contenha dados que precisem ser preservados.
Depois de qualquer alteração de keys, execute novamente:
./deploy/oke/load-test/scripts/deploy_backend.sh
O checksum de runtime força a criação de pods novos, garantindo que as novas credenciais entrem no environment do processo Python.
Precedência das variáveis de ambiente
prepare_env.sh usa o .env real do backend como fonte principal. A ordem é:
templates/agent_template_backend/.env (fonte principal)
↓
.env.loadtest.example (somente defaults ausentes)
↓
.env.loadtest (override explícito opcional)
↓
overrides obrigatórios OKE/container (wallet e Langfuse interno)
↓
.env.runtime
Portanto, ENABLE_MCP_TOOLS, ENABLE_ANALYTICS, endpoints, banco, modelos e demais configurações do agente são preservados por padrão. Para substituir deliberadamente alguma delas no teste, copie .env.loadtest.override.example para .env.loadtest e altere somente as chaves desejadas.
Depois de executar:
./deploy/oke/load-test/scripts/prepare_env.sh
o script informa quantas variáveis do .env do backend foram preservadas e lista apenas as que precisaram mudar por compatibilidade com OKE/container.