O navegador no host mostra o endereço de saída da VPN, o contêiner informa a sua conexão doméstica e alguém chama isso de vazamento. Nada vazou. Um túnel do host é um conjunto de interfaces, rotas e regras que pertencem ao espaço de nomes de rede do host, e um contêiner numa ponte é outro espaço de nomes com a sua própria rota predefinida. Já fiquei num stack Compose em que o cliente VPN estava conectado havia semanas e nem um único pacote de contêiner tinha entrado nele.

Verifique o espaço de nomes antes do ícone da bandeja

Os espaços de nomes são todo o argumento. Quando o Docker inicia um contêiner numa rede de ponte, cria um espaço de nomes de rede, liga uma extremidade de um par veth dentro dele e dá a esse espaço de nomes um endereço e uma rota predefinida. A interface do túnel, chame-se o que se chamar, vive no espaço de nomes do host. O tráfego dentro do contêiner não consegue vê-la, e nenhuma configuração do cliente muda isso de fora.

Dois movimentos suportados tiram você do isolamento. --network host coloca o contêiner dentro do espaço de nomes do host, pelo que ele herda as rotas do host e, portanto, o túnel. --network container:vpn partilha o espaço de nomes de outro contêiner, e é assim que a maioria dos projetos sidecar envia uma carga de trabalho por um contêiner VPN. Ambos são escolhas explícitas; normalmente só uma delas é o que a pessoa que implanta queria dizer.

O modo host não é uma melhoria gratuita. O contêiner deixa de ter o seu próprio endereço, a publicação de portas deixa de se aplicar, e um processo que detenha NET_ADMIN ali pode reescrever o encaminhamento do host. Aceitar isso pode ser a decisão certa. Assumir que já está ligado é como as pessoas passam uma noite a depurar um túnel que nunca esteve no caminho.

Siga o pacote para fora da ponte

Um contêiner na ponte envia o seu pacote para o seu gateway predefinido, que é a interface da ponte no host. O host encaminha então o pacote e, na configuração predefinida, traduz o endereço de origem para o seu antes de o pacote sair. É esse passo de tradução que derrota a política em silêncio.

Quando o pacote chega ao ponto final do túnel, já leva o endereço do host. Qualquer regra, rota de política ou decisão de túnel dividido baseada no endereço original do contêiner deixa de corresponder, e dois contêineres destinados a sair por saídas diferentes não se distinguem apenas pela origem. Se precisa de encaminhamento por contêiner, a decisão tem de acontecer antes da tradução ou dentro de um espaço de nomes que controle.

O Docker mantém estas regras sozinho, através do backend de firewall com que o daemon foi configurado. Regras escritas à mão fora do gancho suportado para tráfego encaminhado, DOCKER-USER, podem ser reordenadas ou descartadas quando o daemon reinicia ou o host é atualizado. A documentação do Docker sobre filtragem de pacotes mostra a ordem das cadeias; o ponto prático é que cada regra precisa de um dono e de um caminho de recarga que você tenha realmente testado.

Teste os dois sistemas em separado

As provas de um espaço de nomes não dizem nada sobre o outro. Um pedido executado dentro do contêiner VPN prova que o túnel funciona para esse contêiner. Não é prova sobre o host, e o mesmo comando executado a partir de um contêiner --network host não é prova sobre a ponte.

# host namespace
ip route get 1.1.1.1
ip -brief addr show

# a fresh container on the same bridge network
docker run --rm --network appnet alpine sh -c 'ip route; cat /etc/resolv.conf; ip -6 route'

Depois repita o teste dentro do contêiner real da aplicação em vez de uma imagem parecida. A aplicação pode trazer uma rota extra, uma variável de ambiente de proxy ou um resolvedor diferente, e cada uma dessas coisas muda a resposta. Verifique a resolução de nomes e a segunda família de endereços sempre: os contêineres em pontes definidas pelo utilizador resolvem através do resolvedor integrado do Docker em 127.0.0.11, e uma rota predefinida IPv6 na ponte pode levar tráfego para fora enquanto está ocupado a testar um túnel só IPv4.

Leia o padrão antes de tocar nas credenciais

Quando o host funciona e o contêiner não, a causa é estrutural quase sempre, e rodar chaves ou reinstalar o cliente desperdiça uma tarde. Ordene primeiro o sintoma e a correção normalmente nomeia-se a si própria.

What you seeUsual causeFirst check
Host exits through the VPN, container shows the ISP addressThe container never entered the tunnelDefault route inside the container
Container works until the daemon restarts, then stopsRules outside the supported hook, or a changed backendDaemon's reported firewall backend and DOCKER-USER
Container loses internal hosts after the tunnel comes upVPN prefix overlaps the Docker bridge subnetip route on the host, then docker network inspect
Small replies arrive, large ones hangTunnel MTU or missing MSS clampingLink MTU on both ends of the tunnel
Container falls back to the ISP address when the tunnel dropsNothing enforces the kill switch for forwarded trafficStop the tunnel with a request in flight

A linha da sobreposição merece a sua própria frase. Um perfil de VPN que empurra uma rota para 172.17.0.0/16, ou para uma 10.0.0.0/8 que por acaso contém o prefixo da sua ponte, faz o túnel reivindicar a sub-rede dos contêineres, e as respostas para endereços traduzidos vão na direção errada ou desaparecem. Renumerar a rede do Docker costuma ser mais limpo do que acumular exceções.

Torne a cobertura explícita e depois quebre-a de propósito

Dois projetos resistem a uma revisão. Partilhe o espaço de nomes do contêiner VPN e cada carga coberta usa um único túnel com uma única fronteira de reinício, o que é simples até um serviço precisar de outra saída ou do seu próprio caminho DNS. Ou encaminhe a rede dos contêineres para um gateway VPN no host: encaminhamento ativado, o prefixo da ponte apontado ao túnel, o tráfego de retorno tratado explicitamente. Isso compra controlo por rede e custa-lhe um conjunto de regras a manter ao longo das atualizações do daemon e do cliente.

De qualquer forma, o teste que importa é o caso de falha. Pare o túnel com um pedido de contêiner em voo e observe para onde vai o pacote. Se voltar ao caminho direto, a cobertura nunca foi imposta, porque um kill switch do cliente governa o tráfego do próprio cliente e não os pacotes encaminhados de uma ponte. Reinicie depois o daemon e o host e confirme o resultado uma segunda vez; é o momento em que as regras escritas à mão desaparecem.

Antes de dar isso por concluído, confirme quatro coisas: a interface do túnel está no mesmo espaço de nomes do tráfego, o teste do contêiner correu dentro do contêiner real, a resolução de nomes e as duas famílias de endereços foram verificadas, e o teste de falha do túnel continua a falhar fechado. Depois anote o backend de firewall, a versão do cliente e o dono de cada regra. Esse registo é o que impede a próxima atualização de deixar uma mistura não documentada de suposições antigas.

Artigos relacionados