O host navega pelo túnel e o contêiner ao lado não alcança nada. Publicar uma porta a partir de um contêiner que executa seu próprio cliente VPN é pior: a requisição chega e a resposta nunca sai. Ambas são decisões de roteamento no host, e o Docker é apenas o mensageiro.

Três perguntas decidem qual dos dois casos você está vendo, e levam cerca de um minuto.

Duas falhas que se apresentam da mesma forma

A primeira é um problema de caminho de volta. A porta publicada é traduzida para o contêiner, a requisição chega e a resposta é roteada pela rota padrão do host, que o cliente OpenVPN apontou para tun0. A resposta sai de um endereço que o par remoto não espera e é descartada. A segunda é uma colisão de prefixos: a ponte padrão do Docker possui 172.17.0.0/16 e um túnel corporativo empurra a mesma faixa.

Uma se corrige com uma tabela de roteamento, a outra renumerando uma ponte. Editar antes de saber qual é qual é a forma de quebrar um contêiner que funcionava.

Decida com três perguntas

Pergunta um: a falha desaparece quando você para a VPN? Se tudo funciona com o túnel desligado, suspeite do caminho de volta. Pergunta dois: ip route show table all lista o mesmo prefixo duas vezes, uma numa ponte e outra em tun0? É essa a colisão. Pergunta três: o endereço afetado é um contêiner, um convidado NAT ou um convidado em ponte?

A terceira pergunta importa porque cada um tem uma correção correta diferente, e aplicar a correção do contêiner a um convidado libvirt desperdiça uma noite.

ip route
ip route show table all | grep -E '172\.1[7-9]|10\.8'
docker network inspect bridge --format '{{.IPAM.Config}}'

Caminho de volta: uma tabela para um endereço de origem

Quando o tráfego do contêiner precisa sair pela interface física enquanto o host usa o túnel, o roteamento baseado na origem é a menor mudança. Adicione uma regra que corresponda ao endereço do contêiner e envie-a para uma tabela dedicada. Nada mais no host se move.

ip rule add from 172.22.0.3 lookup 10
ip route add default via 172.22.0.1 table 10

Cada pacote cuja origem é esse endereço consulta primeiro a tabela 10, e a tabela 10 o envia ao gateway da ponte em vez do túnel.

Confirme com ip route get 1.1.1.1 from 172.22.0.3. A resposta deve nomear a interface da ponte, não tun0. Regras adicionadas assim desaparecem na reinicialização, então coloque-as na unidade ou no gancho de rede que possui o contêiner.

O mesmo padrão funciona para um contêiner WireGuard, onde o caminho de resposta também precisa de uma regra explícita.

Colisão de prefixos: renumere a ponte

Uma tabela de roteamento envia um prefixo para um só lugar. Se a VPN empurra 172.17.0.0/16 enquanto a ponte do Docker já está lá, vence a métrica mais baixa: o Docker instala sua rota conectada com métrica 0, e a rota empurrada chega com 50. Então o túnel parece quebrado enquanto o Docker continua funcionando, ou o contrário, conforme a ordem de instalação. Renumere a ponte em vez de lutar com a métrica.

{
  "bip": "10.200.0.1/24",
  "default-address-pools": [{"base": "10.201.0.0/16", "size": 24}]
}

Reinicie o Docker após a mudança e recrie as redes construídas com o pool antigo. Mudar a métrica apenas desloca o conflito para o próximo boot.

As VMs precisam de outra resposta ainda

Um convidado libvirt na rede NAT padrão herda o roteamento do host e deixa de alcançar o exterior quando o túnel do host possui a rota padrão. Mudar o convidado para um dispositivo em ponte ou macvtap dá a ele seu próprio caminho na rede física. No virt-manager, adicione hardware, escolha Network, defina a origem como o dispositivo de host macvtap, mantenha virtio como modelo e depois desative a interface NAT antiga.

Um convidado macvtap normalmente não consegue alcançar seu próprio host. É um comportamento esperado e não uma falha, e pertence à nota que você deixa.

Para um convidado que só precisa da LAN do host, o cliente do fornecedor pode ter o interruptor que falta: com Mullvad, mullvad lan set allow restaura o alcance local sem tocar no libvirt. E quando um contêiner deve ser acessível apenas pelo túnel, vincule a porta publicada ao endereço do túnel, -p 10.8.0.5:8080:8080, em vez de publicá-la em todos os endereços.

Artigos relacionados