Tráfego de Docker e VM atrás do OpenVPN: rotear ou renumerar?
Contêineres e convidados num host com cliente OpenVPN perdem o caminho de volta ou colidem com o prefixo do túnel. Três perguntas escolhem a correção.
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 10Cada 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.