Debug remoto Java no Kind¶
Conecte a IDE à JVM de um Pod do ambiente local experimental, usando o suporte existente de global.devMode e um port-forward. O exemplo usa o BFF na release totvs-gateway-server. Não é um procedimento para DEV, STAGING ou PROD; esses ambientes são administrados pelo TOTVS Apps.
Como o mecanismo funciona¶
O Helmfile NGINX carrega install/NGiNX/environments/<perfil>/totvs-gateway.yaml e passa esse arquivo à release totvs-gateway-server, cujo chart é helm-releases/totvs-gateway-server. Os valores global ficam disponíveis aos subcharts. A release pertence ao namespace Helm default, mas os Deployments usam global.namespace, cujo default é totvs-gateway.
global.devMode: true está declarado nos perfis NGINX local-win e local-ubuntu, e no perfil Istio local-win. O fluxo abaixo utiliza NGINX; Istio continua sendo um experimento.
| Chart / container | Suporte condicionado a global.devMode |
|---|---|
totvs-gateway-bff |
templates/deploy.yaml: variáveis Java e porta 5005 |
totvs-gateway-core |
templates/deployment.yaml: apenas o container Core; não o sidecar |
totvs-gateway-scheduler |
templates/deployment.yaml: variáveis Java e porta 5005 |
totvs-gateway-object-storage |
templates/deployment.yaml: variáveis Java e porta 5005 |
Esses são os quatro charts com esse mecanismo nos templates analisados. Os demais não ganham JDWP automaticamente com o flag, inclusive o JSON Handler usado no Primeiro deploy local. Serviços Go não são alvos do debugger Java.
Nos quatro casos, o Deployment recebe:
env:
- name: JAVA_DEBUG
value: "true"
- name: JAVA_DEBUG_PORT
value: "5005"
ports:
- name: remote-debug
containerPort: 5005
O chart não escreve diretamente um argumento java. A imagem JVM precisa interpretar essas variáveis. O Dockerfile JVM existente do BFF usa a base UBI OpenJDK 21 e o entrypoint run-java.sh. No BFF validado, o script debug-options produziu:
-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005
A JVM escuta conexões (server=y) e inicia sem esperar pela IDE (suspend=n). containerPort descreve a porta; não inicia o agente. Os Services desses charts continuam expondo HTTP em 8080, portanto o tutorial encaminha a porta do Pod, sem criar Service, Ingress ou NodePort de debug.
1. Preparar o serviço e habilitar o flag¶
Use o ambiente de desenvolvimento e o procedimento Kind. O cluster e as dependências da plataforma devem estar instalados; este tutorial não faz bootstrap. Confira que a imagem escolhida é JVM, que corresponde ao código aberto na IDE e que está acessível nos nós. Preserve a política de imagens definida para sua release.
Execute os comandos PowerShell na raiz de totvs-gateway-infra-local:
kubectl config get-contexts
helm list --kube-context kind-totvs-gateway -n default
helmfile --file install/NGiNX/helmfile.yaml --environment local-win --selector name=totvs-gateway-server list
No arquivo já utilizado pelo seu perfil, install/NGiNX/environments/local-win/totvs-gateway.yaml, mantenha as demais configurações e ajuste:
global:
devMode: true
Não substitua todo o arquivo por esse fragmento. Para Linux, o perfil e o diretório são local-ubuntu. Os perfis já declaram true; se estiver habilitado, confira a JVM antes de aplicar novamente.
2. Aplicar pelo fluxo existente¶
Release gerenciada pelo Helmfile¶
Com o cluster e as releases dependentes já disponíveis, confira o diff e aplique somente a release do servidor:
helmfile --kube-context kind-totvs-gateway --file install/NGiNX/helmfile.yaml --environment local-win --selector name=totvs-gateway-server diff
helmfile --kube-context kind-totvs-gateway --file install/NGiNX/helmfile.yaml --environment local-win --selector name=totvs-gateway-server apply
diff/apply requerem o plugin Helm diff e acesso às dependências dos charts. O seletor limita a release, mas não limita a mudança ao BFF: os demais subcharts habilitados também são reconciliados. Ele não instala automaticamente as releases em needs; para uma instalação inicial, siga o guia Kind.
Alternativa para quem gerencia a release diretamente com Helm¶
Use o mesmo chart e o mesmo conjunto de values/overrides que já administra sua release. Para a composição local declarada no perfil Windows:
helm dependency build helm-releases/totvs-gateway-server
helm upgrade --install totvs-gateway-server helm-releases/totvs-gateway-server --kube-context kind-totvs-gateway --namespace default -f install/NGiNX/environments/local-win/totvs-gateway.yaml --set global.devMode=true --wait --timeout 6000s
O primeiro comando prepara as dependências locais do agregador. Preserve outros arquivos -f e overrides necessários à sua instalação, incluindo imagens e configurações de acesso; não use esse exemplo para sobrescrever uma release com composição diferente. Se usa Helmfile, continue com ele para evitar divergência entre o arquivo de values e a próxima aplicação. --set global.devMode é valor do chart; --state-values-set do Helmfile não é um substituto automático para ele.
Alcance de devMode
No agregador, o flag também condiciona templates/ingress-services.yaml e templates/route-services.yaml. Revise o diff: habilitar/desabilitar o modo pode criar/remover rotas HTTP locais conforme o controller escolhido. Esses recursos não transportam JDWP.
3. Conferir rollout, Pod e JVM¶
$namespace = 'totvs-gateway'
$deployment = 'totvs-gateway-bff'
kubectl --context kind-totvs-gateway -n $namespace rollout status deployment/$deployment --timeout=180s
kubectl --context kind-totvs-gateway -n $namespace get pods -l app=totvs-gateway-bff -o wide
kubectl --context kind-totvs-gateway -n $namespace get deployment $deployment -o jsonpath='{.spec.template.spec.containers[0].env} {.spec.template.spec.containers[0].ports}'
Escolha um Pod Running/Ready da revisão atual, sem deletionTimestamp, e copie seu nome. Não escolha automaticamente o primeiro item durante um rollout:
$pod = Read-Host 'Nome do Pod BFF selecionado'
kubectl --context kind-totvs-gateway -n $namespace logs pod/$pod -c totvs-gateway-bff --tail=200 | Select-String 'Listening for transport dt_socket'
kubectl --context kind-totvs-gateway -n $namespace exec pod/$pod -c totvs-gateway-bff -- sh -c 'tr "\000" " " < /proc/1/cmdline'
Confira JAVA_DEBUG=true, JAVA_DEBUG_PORT=5005, remote-debug:5005 e -agentlib:jdwp na JVM. A mensagem de startup pode ter saído da janela dos logs; a linha do processo confirma o argumento no BFF. Um processo ./application indica uma imagem native neste contexto e não será convertido em JVM por devMode.
4. Encaminhar debug e HTTP do mesmo Pod¶
Mantenha este terminal aberto:
kubectl --context kind-totvs-gateway -n $namespace port-forward pod/$pod 5005:5005 18083:8080 --address 127.0.0.1
O bind fica restrito ao host local. Se 5005 estiver ocupada, use 15005:5005 e configure a IDE para 15005. Não abra a porta JDWP via Ingress ou endereço público.
Em outro terminal, confira HTTP:
Invoke-RestMethod http://127.0.0.1:18083/gateway/q/health/ready
No BFF, quarkus.http.root-path=/ e quarkus.http.non-application-root-path=/gateway/q: o health está em /gateway/q/health/ready. A raiz / não torna esse caminho incompatível com as probes.
Encaminhar também HTTP para o mesmo Pod evita que uma requisição enviada ao Service seja atendida por outra réplica. Ao trocar o Pod, encerre e refaça o port-forward e a conexão da IDE.
5. Conectar o IntelliJ IDEA¶
- Abra o projeto BFF correspondente à imagem e importe seu
pom.xml, com JDK 21. - Em Run → Edit Configurations → + → Remote JVM Debug, crie uma configuração para o BFF local.
- Selecione Attach to remote JVM, transporte Socket, host
127.0.0.1e porta5005(ou15005, conforme o encaminhamento). - Selecione o módulo do BFF para localizar os fontes e inicie Debug.
Não copie os argumentos sugeridos pela IDE para Dockerfiles ou Deployments: o mecanismo Helm existente já habilita o agente. Referência: debug remoto no IntelliJ IDEA.
6. Conectar o VS Code¶
Abra a pasta do BFF com o suporte a Java e a extensão Debugger for Java instalados. No seu workspace de desenvolvimento, use esta configuração em .vscode/launch.json:
{
"version": "0.2.0",
"configurations": [
{
"type": "java",
"name": "BFF — Kind local",
"request": "attach",
"hostName": "127.0.0.1",
"port": 5005
}
]
}
Em Run and Debug, selecione essa configuração e conecte. Em workspaces com vários projetos Java, selecione o projeto correto; configure projectName se houver ambiguidade, usando o nome reconhecido pelo Java Projects. Referência: configuração do debugger Java no VS Code.
Use apenas um debugger conectado a essa porta por vez. A IDE se conecta à JVM existente; não inicia uma segunda aplicação local.
7. Atingir um breakpoint com uma requisição¶
No BFF, coloque um breakpoint na linha executável de JsonHandlerResource.jsonToJsonSchema, em src/main/java/app/totvs/gateway/bff/integration/jsonhandler/resource/v1/JsonHandlerResource.java. Prefira suspender somente a thread da requisição, quando a IDE permitir, e retome rapidamente para não comprometer probes e timeouts.
Com o port-forward ativo, envie o corpo JSON diretamente ao endpoint do BFF. O resource recebe uma string de corpo bruto, e JsonHandlerService cria o SchemaRequest para o serviço downstream; não envie o envelope input do tutorial do JSON Handler diretamente ao BFF.
$token = Read-Host 'Token Bearer válido para o ambiente local'
$headers = @{ Authorization = "Bearer $token" }
Invoke-RestMethod -Method Post -Uri http://127.0.0.1:18083/gateway/api/v1/json-handler/json-to-schema -Headers $headers -ContentType application/json -Body '{"name":"John","age":30}'
Use identidade e contexto de tenant válidos para a configuração local, conforme a documentação do BFF. Não desabilite autenticação para testar debug. A operação completa também precisa do JSON Handler acessível pelo client do BFF.
Ao pausar, inspecione json, execute um passo e retome. Verifique a resposta no terminal. Um health UP ou uma conexão JDWP não comprova que o breakpoint foi atingido: confirme a pausa na linha e no Pod esperado.
8. Desabilitar e restaurar¶
Desconecte a IDE. No mesmo arquivo de values, altere apenas:
global:
devMode: false
Execute novamente o diff e o apply do passo 2. Se administra diretamente por Helm, repita o mesmo upgrade com --set global.devMode=false, preservando todos os demais valores. Confira o impacto sobre as rotas HTTP locais antes de aplicar.
Aguarde o rollout, selecione o novo Pod e repita as verificações do passo 3. Nos charts, false remove as entradas JAVA_DEBUG, JAVA_DEBUG_PORT e a porta remote-debug; não injeta JAVA_DEBUG="false". Confirme que a nova JVM não tem -agentlib:jdwp, pois configurações adicionais da imagem também podem habilitar o agente. Encerre o port-forward com Ctrl+C e confira novamente a saúde HTTP do novo Pod, com um novo encaminhamento se necessário.
Troubleshooting¶
| Sintoma | O que verificar |
|---|---|
| JVM sem JDWP | O chart está entre os quatro suportados? A imagem é JVM? O entrypoint interpreta JAVA_DEBUG? Confira /proc/1/cmdline e os logs; não acrescente um segundo agente manualmente. |
| Flag não chegou ao Deployment | Confira perfil, arquivo de values, overrides e namespace. A release é totvs-gateway-server em default; o Pod usa global.namespace. Aguarde o rollout e selecione a revisão nova. |
helm template informa dependências ausentes |
Prepare as dependências locais do agregador com helm dependency build; Helmfile faz a preparação em seu fluxo normal. |
| Porta inacessível | Encaminhe pod/<nome>, não o Service HTTP; confira o processo JDWP e o Pod escolhido. containerPort sozinho não abre um socket. |
| IDE recebe connection refused | Port-forward deve estar ativo; confira host/porta local, conflito com outro processo e logs do encaminhamento. |
| IDE conecta e desconecta | Verifique restart, rollout, timeout de probes e outro debugger conectado. Refaça o encaminhamento para o Pod atual. |
| Breakpoint não atinge | A chamada passou por essa linha? Auth ou validação podem rejeitá-la antes. Encaminhe HTTP e debug para o mesmo Pod; health não passa pelo resource de negócio. |
| Breakpoint não vinculado / linha diferente | Compare fontes, revisão/tag/digest e classes da imagem. Recompile e publique a versão correta pelo fluxo Kind, sem assumir que salvar um arquivo local atualiza o Pod. |
| Múltiplas réplicas | A sessão depura somente a JVM do Pod selecionado. Requisições por Service/Ingress podem chegar a outro Pod. |
Processo ./application |
A imagem native não usa o JDWP da JVM. Escolha o Dockerfile JVM já existente e siga Imagens Docker; o flag não converte o artefato. |
| Pod reinicia durante pausa | Suspender todas as threads pode bloquear probes. Use pausas curtas/thread da requisição; não altere probes como parte deste tutorial. |
Validação e referências¶
Veja o registro de debug remoto para separar renderização Helm, conexão JDWP executada e passos de IDE não executados.
Implementação consultada
-
totvs-gateway-infra-local — install/NGiNX/environments/local-win/totvs-gateway.yaml
-
totvs-gateway-infra-local — install/NGiNX/environments/local-ubuntu/totvs-gateway.yaml
-
totvs-gateway-infra-local — install/istio/environments/local-win/totvs-gateway.yaml
-
totvs-gateway-infra-local — helm-releases/totvs-gateway-server/Chart.yaml
-
totvs-gateway-infra-local — helm-releases/totvs-gateway-server/values.yaml
-
totvs-gateway-infra-local — helm-releases/totvs-gateway-server/templates/ingress-services.yaml
-
totvs-gateway-infra-local — helm-releases/totvs-gateway-server/templates/route-services.yaml
-
totvs-gateway-infra-local — helm-releases/totvs-gateway-apps/totvs-gateway-bff/templates/deploy.yaml
-
totvs-gateway-bff — src/main/resources/application.properties
-
totvs-gateway-bff — src/main/java/app/totvs/gateway/bff/shared/http/ApiPaths.java