O seu contentor continua a responder na sua ponte de controlo, mas cada pacote de saída sai pela macvlan do escritório. Nada falhou. Duas ligações fornecem cada uma um gateway, e a única rota predefinida foi para a rede que não pretendia, pelo que o serviço continua a funcionar enquanto o seu tráfego segue um caminho mais longo. Quando alguém repara nisso, a prova é uma tabela de encaminhamento e não uma mensagem de erro.

A explicação habitual é que o Docker escolheu a rede por acidente. Na prática, a decisão antiga seguia a ordem alfabética dos nomes das redes ligadas, o que transformava o encaminhamento num efeito secundário de uma etiqueta. O gw_priority substitui isso por um número que escolhe de propósito, e adotá-lo leva cerca de um minuto depois de o esquema estar escrito.

Porque é que a rota predefinida cai na rede errada

Cada rede a que um serviço se junta pode oferecer o seu próprio gateway, e o contentor fica na mesma com exatamente uma rota predefinida. Antes do Compose 2.33.1 o empate era resolvido ordenando os nomes das redes, por isso uma etiqueta como control que vem antes de office decidia para onde ia o tráfego. Nada dentro do contentor registra que a decisão foi arbitrária, e é por isso que sobrevive à revisão de código e aparece mais tarde como um caminho estranho. Pôr uma política no ficheiro compose é a única forma de tornar a escolha inspecionável.

Duas coisas mudam de facto qual rede ganha: os valores de gw_priority que atribui e quais redes estão ligadas. Acrescente uma terceira rede e o conjunto de candidatas cresce; retire a macvlan e não fica nada para competir com a ponte. Nenhum dos movimentos aparece nos registos da aplicação, porque uma rota predefinida errada raramente quebra a ligação por completo. Apenas faz com que as respostas cheguem de um endereço que a outra parte talvez não espere.

Fixe o gateway com gw_priority

O Compose expõe gw_priority em cada ligação serviço-rede desde a versão 2.33.1, e ganha o número mais alto. Não existe uma chave de gateway por serviço, por isso o valor pertence ao bloco networks do serviço. O exemplo abaixo entrega a rota predefinida a control enquanto office continua acessível para a sua LAN diretamente ligada.

services:
  vpn:
    networks:
      control:
        gw_priority: 1
      office:
        gw_priority: 0

networks:
  control:
    driver: bridge
    ipam:
      config:
        - subnet: 172.30.50.0/24
  office:
    driver: macvlan
    driver_opts:
      parent: eno1.120
      macvlan_mode: bridge
    ipam:
      config:
        - subnet: 192.168.120.0/24
          ip_range: 192.168.120.192/27
          gateway: 192.168.120.1

Leia o bloco como dois controlos separados: gw_priority decide a rota predefinida e a secção ipam decide o endereçamento. Mudar apenas a subnet deixa a escolha da saída intacta, e é a forma mais comum de esta correção ficar aplicada a metade. Mantenha as prioridades ao lado da rede que governam, para que o leitor seguinte não tenha de procurar a decisão.

Não confunda gw_priority com a propriedade priority simples ao lado. Essa ordena a criação de ligações e não diz nada sobre encaminhamento, por isso não pode escolher um gateway predefinido nem corrige os nomes das interfaces. Se alguém recomendar subir priority para orientar o tráfego, a recomendação está errada mesmo quando a ordem resultante parece correta por acaso.

Verifique qual rede transporta realmente a rota predefinida

Verifique dentro do contentor em execução, porque a tabela de encaminhamento do anfitrião descreve o anfitrião e não o espaço de nomes usado pelo serviço. Execute primeiro a verificação da configuração para que um erro de escrita falhe antes de um reinício, e depois leia a rota que o contentor instalou de facto.

docker compose config --quiet
docker exec vpn ip -4 route show default
docker exec vpn cat /proc/net/route

Um resultado correto nomeia o dispositivo de ponte e 172.30.50.1; um errado nomeia 192.168.120.1 e o dispositivo macvlan. Se a imagem não incluir o pacote iproute2, o ficheiro /proc continua a reportar a rota predefinida, com destino 00000000 e os bytes do gateway invertidos. Compare a coluna da interface com docker inspect quando os nomes dos dispositivos não estiverem claros.

A macvlan é uma porta física, não um clone da ponte

A macvlan dá ao contentor uma segunda identidade no cabo, e é exatamente isso que faz funcionar o acesso a dispositivos locais. Também significa que a porta do comutador e o hipervisor têm de aceitar um endereço MAC adicional, e muitas redes de nuvem recusam isso em silêncio. Teste um contentor antes de planear uma frota, porque um MAC recusado aparece normalmente como uma ligação ativa que não deixa passar nada.

A definição macvlan_mode: bridge é um modo do controlador macvlan, não a ponte de software do Docker, e passthru é um modo especializado separado e não um valor predefinido. O Linux também impede que um contentor macvlan alcance o seu próprio anfitrião através do mesmo pai, e é essa a razão para manter a ponte de controlo em vez de esperar que uma só ligação faça as duas tarefas.

Nomeie o pai VLAN antes de o Compose o ver

O Docker trata um pai com ponto como eno1.120 como uma subinterface 802.1Q e cria ele próprio o dispositivo VLAN. Essa comodidade tem limites: o nome derivado depende do nome da interface física, e nomes longos podem empurrar o resultado para além do que as ferramentas em volta esperam. Criar uma interface VLAN com nome na configuração de rede do anfitrião e apontar parent para ela mantém as duas pontas previsíveis.

Lembre-se de que a chave em networks é um nome de Compose, não um dispositivo Linux. Procurar no anfitrião uma interface chamada office vai falhar, porque o núcleo só vê a interface pai e o par veth atrás do contentor.

Abra espaço para a VPN por cima

Um cliente VPN liga-se depois de estas redes existirem, por isso pode acrescentar rotas mais específicas, regras de política e filtros independentemente do gw_priority. Planeie os prefixos remotos contra as duas sub-redes locais, incluindo as respostas de que o caminho de controlo precisa. Quando um prefixo remoto se sobrepõe à LAN do escritório, corrija o plano de endereços em vez de arrancar toda uma gama privada do túnel.

Volte a verificar endereços, rotas e o caminho do serviço depois de a VPN arrancar e outra vez depois de ela se voltar a ligar, porque é numa religação que desaparece uma rota acrescentada à mão. Escreva a tabela esperada antes do primeiro teste para que a comparação seguinte seja um diff e não um exercício de memória. Mantenha a propriedade persistente da rede no Compose e deixe a configuração da VPN possuir apenas a sua própria política.

Artigos relacionados