Un contenedor con dos redes elige la puerta de enlace equivocada
Dos conexiones, una ruta predeterminada y la red equivocada gana siempre. Fije la salida con Compose gw_priority y confírmelo desde dentro del contenedor.
Su contenedor sigue respondiendo en su puente de control, pero cada paquete saliente sale por la macvlan de oficina. Nada ha fallado. Dos conexiones aportan cada una una puerta de enlace, y la única ruta predeterminada fue a la red que no pretendía, así que el servicio sigue funcionando mientras su tráfico toma un camino más largo. Cuando alguien lo nota, la evidencia es una tabla de enrutamiento y no un mensaje de error.
La explicación habitual es que Docker eligió la red por accidente. En la práctica, la decisión antigua seguía el orden alfabético de los nombres de las redes conectadas, lo que convertía el enrutamiento en un efecto secundario de una etiqueta. gw_priority lo sustituye por un número que usted elige a propósito, y adoptarlo lleva aproximadamente un minuto una vez escrito el esquema.
Por qué la ruta predeterminada aterriza en la red equivocada
Cada red a la que se une un servicio puede ofrecer su propia puerta de enlace, y el contenedor acaba igualmente con exactamente una ruta predeterminada. Antes de Compose 2.33.1 el empate se resolvía ordenando los nombres de las redes, así que una etiqueta como control que va antes que office decidía hacia dónde iba el tráfico. Nada dentro del contenedor registra que la decisión fue arbitraria, y por eso sobrevive a la revisión de código y aparece más tarde como una ruta extraña. Poner una política en el archivo compose es la única forma de hacer la elección inspeccionable.
Dos cosas cambian de verdad qué red gana: los valores de gw_priority que asigna y qué redes están conectadas. Añada una tercera red y el conjunto de candidatas crece; quite la macvlan y no queda nada que compita con el puente. Ninguno de los dos movimientos aparece en los registros de la aplicación, porque una ruta predeterminada equivocada rara vez rompe la conexión del todo. Solo hace que las respuestas lleguen desde una dirección que la otra parte quizá no espera.
Fije la puerta de enlace con gw_priority
Compose expone gw_priority en cada conexión servicio-red desde la versión 2.33.1, y gana el número más alto. No hay una clave de puerta de enlace por servicio, así que el valor va dentro del bloque networks del servicio. El ejemplo de abajo entrega la ruta predeterminada a control mientras office sigue accesible para su LAN directamente conectada.
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
Lea el bloque como dos controles distintos: gw_priority decide la ruta predeterminada y la sección ipam decide el direccionamiento. Cambiar solo la subnet deja intacta la elección de salida, y esa es la forma más habitual de que esta corrección se aplique a medias. Mantenga las prioridades junto a la red que gobiernan para que el siguiente lector no tenga que buscar la decisión.
No confunda gw_priority con la propiedad priority simple que tiene al lado. Esa ordena la creación de conexiones y no dice nada sobre enrutamiento, así que no puede elegir una puerta de enlace predeterminada ni arregla los nombres de las interfaces. Si alguien recomienda subir priority para dirigir el tráfico, la recomendación es errónea aunque el orden resultante parezca correcto por casualidad.
Verifique qué red transporta realmente la ruta predeterminada
Compruébelo dentro del contenedor en ejecución, porque la tabla de enrutamiento del host describe el host y no el espacio de nombres que usa el servicio. Ejecute primero la comprobación de configuración para que una errata falle antes de un reinicio, y después lea la ruta que el contenedor instaló de verdad.
docker compose config --quiet
docker exec vpn ip -4 route show default
docker exec vpn cat /proc/net/route
Un resultado correcto nombra el dispositivo puente y 172.30.50.1; uno equivocado nombra 192.168.120.1 y el dispositivo macvlan. Si la imagen no incluye el paquete iproute2, el archivo /proc sigue informando de la ruta predeterminada, con destino 00000000 y los bytes de la puerta de enlace invertidos. Compare la columna de interfaz con docker inspect cuando los nombres de los dispositivos no estén claros.
Macvlan es un puerto físico, no un clon del puente
Macvlan da al contenedor una segunda identidad en el cable, y eso es justo lo que hace funcionar el acceso a los dispositivos locales. También significa que el puerto del conmutador y el hipervisor deben aceptar una dirección MAC extra, y muchas redes de nube lo rechazan en silencio. Pruebe un contenedor antes de planificar una flota, porque una MAC rechazada suele aparecer como un enlace que está levantado y no pasa nada.
El ajuste macvlan_mode: bridge es un modo del controlador macvlan, no el puente de software de Docker, y passthru es un modo especializado aparte y no un valor por defecto. Linux también impide que un contenedor macvlan alcance su propio host a través del mismo padre, y esa es la razón de mantener el puente de control en lugar de esperar que una sola conexión haga las dos tareas.
Nombre el padre VLAN antes de que Compose lo vea
Docker trata un padre con punto como eno1.120 como una subinterfaz 802.1Q y crea él mismo el dispositivo VLAN. Esa comodidad tiene límites: el nombre derivado depende del nombre de la interfaz física, y los nombres largos pueden empujar el resultado más allá de lo que esperan las herramientas del entorno. Crear una interfaz VLAN con nombre en la configuración de red del host y apuntar parent a ella mantiene ambos extremos predecibles.
Recuerde que la clave bajo networks es un nombre de Compose, no un dispositivo Linux. Buscar en el host una interfaz llamada office fallará, porque el núcleo solo ve la interfaz padre y el par veth detrás del contenedor.
Haga sitio para la VPN encima
Un cliente VPN se conecta después de que existan estas redes, así que puede añadir rutas más específicas, reglas de política y filtros con independencia de gw_priority. Planifique los prefijos remotos contra las dos subredes locales, incluidas las respuestas que necesita el camino de control. Cuando un prefijo remoto se solape con la LAN de oficina, corrija el plan de direcciones en lugar de arrancar todo un rango privado del túnel.
Vuelva a comprobar direcciones, rutas y el camino del servicio después de que arranque la VPN y otra vez después de que se reconecte, porque es en una reconexión donde desaparece una ruta añadida a mano. Escriba la tabla esperada antes de la primera prueba para que la comparación posterior sea un diff y no un ejercicio de memoria. Mantenga la propiedad persistente de la red en Compose y deje que la configuración de la VPN posea solo su propia política.