Communitygithub.com

bilgihankose/k8s-debug-bridge

Depure um serviço Kubernetes ativo diretamente do seu laptop. Cinco scripts bash + uma Skill do Agent — sem agente, sem operador, sem instalação.

O que é k8s-debug-bridge?

Esta skill cria uma ponte de depuração temporária entre um cluster Kubernetes/OpenShift e a máquina local, utilizando apenas `kubectl`/`oc exec`, `/dev/tcp` do bash e o `nc` dentro de um pod bridge. Ela redireciona temporariamente o seletor do serviço alvo para o pod bridge, que então cria um túnel reverso para a porta local. O processo é composto por cinco scripts bash que gerenciam a criação do pod, o redirecionamento, o túnel, a limpeza e a verificação do ambiente. A skill é independente de linguagem e framework, servindo apenas como transporte de tráfego — exemplos de integração incluem VS Code + Air + Delve para Go, mas qualquer watcher/depurador pode ser usado. O principal risco é esquecer de reverter o seletor do serviço, causando uma interrupção permanente no cluster; por isso, cada etapa exige aprovação explícita do usuário e um plano de rollback é incorporado nos scripts.

Funciona com~Claude Code~Codex CLI~Cursor
npx skills add bilgihankose/k8s-debug-bridge

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

K8s Debug Bridge

Cria um túnel de tráfego ativo de um Serviço Kubernetes/OpenShift para uma máquina local para depuração usando apenas kubectl/oc exec padrão, o /dev/tcp embutido do bash e o nc dentro do pod bridge — sem necessidade de CLI ou agente extra para instalar. Mecanismo: um "pod bridge" temporário é criado, o spec.selector do Serviço alvo é temporariamente alterado para o label deste pod, e um túnel reverso conecta o pod e a porta local. Funciona em qualquer distribuição Kubernetes (vanilla K8s, OpenShift, EKS/GKE/AKS) — usa oc se disponível, senão kubectl (veja scripts/lib-kube-cli.sh). O README.md aborda a lógica e as desvantagens em relação a ferramentas como Telepresence e mirrord.

Isto não está vinculado a uma única linguagem/framework: a ponte apenas transporta tráfego. VS Code + Air + Delve (Go) é apenas um exemplo de integração — se você trabalha em outra linguagem, conecte seu próprio watcher/depurador (Node: nodemon+ inspector, Python: watchdog+debugpy, etc.) através do mesmo túnel. Se o lado local do usuário ainda não estiver configurado — sem recarregador, sem depurador anexado, ou se eles quiserem adaptá-lo ao seu próprio projeto — leia docs/local-debug-setup.md nesse ponto e siga-o. Não reproduza seu conteúdo de memória e não o leia quando o aplicativo local já estiver em execução e escutando.

Esta skill cria um recurso real em seu cluster e modifica um recurso real: ela cria um Pod e altera temporariamente o spec.selector de um Serviço. Estas não são simulações — este é um estado real do cluster. Deve haver um plano de rollback em cada etapa — nunca altere o seletor e esqueça dele.

Pré-requisitos — verifique antes de perguntar ao usuário

Não pergunte ao usuário o namespace/nome do serviço e passe cegamente para bridge-up.sh — um nome digitado incorretamente falhará no meio do script. Execute primeiro scripts/check-env.sh [namespace] (somente leitura, não altera nada):

  • Executar sem argumentos: lista o status de login e namespaces acessíveis. Se não estiver logado, pare aqui e diga ao usuário para executar oc login/kubectl config use-context.
  • Executar com um namespace: verifica se o namespace existe e lista os Serviços dentro dele (nome + porta + porta alvo, incluindo aqueles já com bridge).

Mostre esta saída ao usuário e deixe-o escolher o Serviço alvo da lista — não o faça adivinhar. Em seguida:

  • A imagem do pod bridge — sempre pergunte, nunca presuma. Não escolha um padrão e execute com ele: pergunte diretamente ao usuário "qual imagem o pod bridge deve usar?" e aguarde uma resposta. A imagem precisa ser aprovada e acessível por aquele cluster específico, e apenas eles sabem qual é — muitos clusters puxam apenas de um registro interno aprovado, portanto uma imagem adivinhada pode falhar ao puxar com o Serviço já redirecionado. nicolaka/netshoot é um exemplo a oferecer, não um substituto para usar silenciosamente. O que quer que escolham precisa ter o nc: o lado do pod usa nc em vez de socat porque imagens reduzidas frequentemente removem socat enquanto mantêm o nc do Nmap. tunnel.sh verifica a presença de nc antes de abrir o túnel e para com um erro claro se a imagem não o tiver.
  • Manifesto do pod: o pod bridge é renderizado a partir de assets/bridge-pod.yaml. Se o cluster exigir imagePullSecrets, um securityContext, nodeSelector/tolerations ou limites de recursos diferentes, edite esse arquivo — não contorne isso nos scripts. Mantenha o label debug: "__BRIDGE_NAME__" e o nome do contêiner debug-bridge; os outros scripts se referem ao pod através deles.
  • A porta: use o targetPort numérico do Serviço da saída de check-env.sh, NÃO uma porta livre arbitrária. Se o Serviço usar um targetPort nomeado (ex.: http), resolva-o para sua porta de contêiner numérica. O kube-proxy encaminha o tráfego para o targetPort do pod assim que o seletor é redirecionado — se você escolher um número diferente, o tráfego nunca alcançará o pod bridge.
  • Dependências de saída: esta ponte lida apenas com tráfego de entrada (Cluster → Local). Se o código local precisar chamar outros serviços do cluster (.svc.cluster.local), use Routes/Ingress externos ou port-forwards locais.
  • Segredos e ambiente: nunca execute oc exec ... env, printenv, set ou um comando similar contra um pod de aplicação. Valores podem ser credenciais multilinha e vazarão para a saída do terminal/ferramenta mesmo quando um comando parecer selecionar apenas nomes. Nunca copie valores de ambiente de um pod para um comando local, histórico do shell ou .env. Exija um fluxo de trabalho de gerenciamento de segredos local pré-existente ou peça ao usuário para fornecer o arquivo de ambiente local necessário fora da banda. Verifique apenas se o aplicativo local inicia; não imprima seu ambiente.

O aplicativo local já deve estar em execução antes de você tocar no Serviço. Esta é uma pré-condição, não uma etapa posterior: o túnel entrega tráfego para 127.0.0.1:<porta>, portanto se nada estiver escutando lá quando o seletor for alterado, cada requisição interceptada falhará com conexão-recusada/502 enquanto os pods reais já estão fora de rotação. Peça ao usuário para iniciar seu aplicativo (com um arquivo de ambiente local provisionado com segurança — nunca um lido de um pod do cluster) e confirme o listener imediatamente antes da etapa 2:

lsof -nP -iTCP:<porta> -sTCP:LISTEN

Fluxo

  1. Configurar a bridge: Antes de executar qualquer coisa, informe claramente ao usuário: "Criarei um Pod real chamado <bridge-pod> no namespace <namespace> (imagem: <imagem>) — ele consumirá recursos do cluster e será excluído quando terminar." Após obter aprovação, execute scripts/bridge-up.sh <namespace> <serviço> <bridge-pod> <imagem> [porta] — isso cria o pod bridge e salva o seletor original tanto no estado local quanto como uma anotação k8s-debug-bridge/owner no Serviço (sem necessidade de python3/jq, bash puro). Não pule esta etapa — nunca redirecione sem ter o seletor original salvo, ou não haverá como voltar. Se o serviço já estiver com bridge criada por outra pessoa, este script falha e para (verificação de anotação) — nesse caso mostre ao usuário o proprietário da mensagem de erro, não tente novamente.

  2. Redirecionar o serviço: Antes de alterar o seletor do Serviço alvo para o label do pod bridge, informe claramente ao usuário e obtenha aprovação real: "A partir deste momento, TODO o tráfego para <serviço> irá para seu pod bridge — os pods reais pararão de receber tráfego." Após aprovação, execute scripts/redirect-service.sh <namespace> <serviço> --yes — --yes pula o prompt interativo read do próprio script (já que você obteve aprovação no chat); sem --yes o script aguarda em stdin e pode travar. O script substitui o mapa completo do seletor por apenas debug=<bridge-pod>; ele não deve mesclar este label no seletor original, porque o pod bridge não carrega os labels originais da aplicação.

  3. Iniciar o túnel: scripts/tunnel.sh <namespace> <serviço> <bridge-pod> <porta> — este script bloqueia, portanto deve ser executado em seu próprio terminal ou em um processo em segundo plano. Ele se auto-limpa: trap captura EXIT/INT/TERM, então Ctrl+C ou qualquer outra terminação chama automaticamente cleanup.sh. Se você o iniciou em segundo plano, não há Ctrl+C para pressionar — pare-o com kill -TERM <pid>, que o trap também trata; anote o PID ao iniciá-lo e informe ao usuário qual é. Executar cleanup.sh manualmente só é necessário se o processo for morto de forma não capturável (kill -9). Ele carrega uma conexão por vez e cria automaticamente um novo listener no lado do pod após cada conexão ser fechada, portanto mantenha o mesmo túnel em execução entre requisições de depuração sequenciais. Se o túnel registrar repetidamente WARNING: could not carry a connection, nada está escutando em 127.0.0.1:<porta> — o aplicativo local está parado, ainda compilando, ou um recarregamento a quente liberou a porta. Corrija isso em vez de reiniciar o túnel.

  4. Depuração local: a porta que você faz a bridge é a porta na qual o aplicativo serve (o targetPort do Serviço), nunca a porta em que seu depurador escuta. Se o usuário disser "meu depurador está na 2345, faça a bridge disso", ele está confundindo as duas coisas: corrija-o, pergunte em qual porta o aplicativo em si serve, e faça a bridge dessa. O tráfego enviado para uma porta de depurador retorna como 502s que parecem um túnel quebrado. O aplicativo local já está em execução e verificado (veja a pré-condição acima); é ele quem recebe o tráfego do túnel. O depurador de sua linguagem (ex.: Delve, um inspetor Node) se anexa a esse aplicativo em execução separadamente, geralmente em uma porta diferente — ex.: em Go, Air + Delve na porta 2345 enquanto o aplicativo em si escuta na <porta> do túnel. Um recarregamento a quente pode remover brevemente o listener; enquanto ele estiver ausente, a bridge retorna falhas de conexão/502s. Se o aplicativo local não se recuperar rapidamente, pare o túnel e limpe o Serviço em vez de deixar todo o tráfego apontado para uma bridge com falha. A bridge transporta o caminho HTTP inalterado: configure o prefixo base do aplicativo local para corresponder ao caminho entregue ao Serviço; ela não reproduz uma reescrita de Ingress. O tráfego pode vir de qualquer chamador dentro do cluster do Serviço (por exemplo, um proxy Nginx de dashboard); uma Route/Ingress pública não é necessária. Se a execução estiver pausada além do tempo limite do chamador, retome-a e dispare uma nova requisição. Após um recarregamento a quente reiniciar o Delve, a IDE pode precisar se anexar novamente. Quando o Delve foi iniciado com --accept-multiclient, o agente também pode anexar um cliente Delve de terminal à porta 2345 junto com o VS Code para inspecionar a linha de origem atual, pilha e variáveis. Relate observações ao usuário; obtenha aprovação explícita antes de continuar a execução ou alterar o estado do depurador.

  5. Quando terminar: Ctrl+C no terminal do túnel, ou kill -TERM <pid> se você o iniciou em segundo plano — o seletor do serviço e o pod bridge revertem automaticamente, incluindo a restauração do mapa completo do seletor original. Se o trap não disparou (ex.: kill -9), scripts/cleanup.sh <namespace> <serviço> deve ser executado manualmente; lembre o usuário disso antes de ele sair da sessão.

Nota de segurança

Este método não instala nenhum componente permanente no cluster (sem webhook de mutação, injetor de sidecar ou RBAC em todo o cluster) — apenas um pod temporário claramente marcado por seu nome/label (debug=<bridge-pod-name>) e permissões padrão de exec. Mesmo assim, existem dois riscos reais: avise o usuário sobre eles:

  1. Esquecer de reverter o seletor do serviço — uma indisponibilidade permanente em prod/staging.
  2. A permissão exec pode ser abusada via RBAC — esta skill deve ser executada apenas em seu próprio namespace, em seu próprio pod bridge, e nunca deve precisar de cluster-admin.

Para etapas detalhadas e solução de problemas, veja README.md.

Antes de encerrar a sessão, verifique se alguma bridge não limpa permanece. O estado reside ao lado de scripts/, na própria pasta desta skill — não no diretório de projeto do usuário. Resolva-o relativo aos scripts que você está executando, ex.:

find "$(dirname <caminho-para>/scripts)/.state" -name '*.env'

Executar um find .state simples a partir do diretório do usuário não encontrará nada e relatará um estado limpo mesmo quando uma bridge ainda estiver ativa. Se um arquivo .env existir lá, informe ao usuário qual namespace/serviço ele nomeia e sugira scripts/cleanup.sh <namespace> <serviço>. Isso é um lembrete, não uma porta determinística — tome cuidado para não esquecê-lo.

Habilidades Relacionadas