Votre conteneur répond toujours sur son pont de contrôle, mais chaque paquet sortant part par le macvlan du bureau. Rien n'a échoué. Deux attachements fournissent chacun une passerelle, et l'unique route par défaut est allée vers le réseau que vous ne visiez pas, si bien que le service continue de fonctionner pendant que son trafic emprunte un chemin plus long. Quand quelqu'un le remarque, la preuve est une table de routage et non un message d'erreur.

L'explication habituelle est que Docker a choisi le réseau par accident. En pratique, l'ancienne décision suivait l'ordre alphabétique des noms des réseaux attachés, ce qui faisait du routage un effet secondaire d'une étiquette. gw_priority remplace cela par un nombre que vous choisissez exprès, et l'adopter prend environ une minute une fois la disposition écrite.

Pourquoi la route par défaut atterrit sur le mauvais réseau

Chaque réseau qu'un service rejoint peut proposer sa propre passerelle, et le conteneur finit malgré tout avec exactement une route par défaut. Avant Compose 2.33.1, l'égalité était tranchée en triant les noms des réseaux, si bien qu'une étiquette comme control venant avant office décidait où allait le trafic. Rien dans le conteneur n'enregistre que la décision était arbitraire, ce qui explique qu'elle survive à la revue de code et resurgisse plus tard comme un chemin bizarre. Mettre une politique dans le fichier compose est le seul moyen de rendre le choix inspectable.

Deux choses changent réellement quel réseau gagne : les valeurs gw_priority que vous attribuez, et quels réseaux sont attachés. Ajoutez un troisième réseau et l'ensemble des candidats grandit ; retirez le macvlan et il ne reste rien pour concurrencer le pont. Aucun des deux mouvements n'apparaît dans les journaux de l'application, car une mauvaise route par défaut casse rarement la connexion franchement. Elle fait seulement arriver les réponses depuis une adresse que l'autre côté n'attend peut-être pas.

Épinglez la passerelle avec gw_priority

Compose expose gw_priority sur chaque attachement service-réseau depuis la version 2.33.1, et le nombre le plus élevé l'emporte. Il n'existe pas de clé de passerelle par service, la valeur appartient donc au bloc networks du service. L'exemple ci-dessous confie la route par défaut à control tout en laissant office joignable pour son LAN directement connecté.

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

Lisez le bloc comme deux commandes distinctes : gw_priority décide de la route par défaut, et la section ipam décide de l'adressage. Changer seulement le subnet laisse le choix de sortie intact, et c'est la façon la plus courante d'appliquer ce correctif à moitié. Gardez les priorités à côté du réseau qu'elles gouvernent pour que le prochain lecteur n'ait pas à traquer la décision.

Ne confondez pas gw_priority avec la propriété priority simple juste à côté. Celle-ci ordonne la création des connexions et ne dit rien du routage, elle ne peut donc pas choisir de passerelle par défaut et ne corrige pas le nom des interfaces. Si quelqu'un recommande d'augmenter priority pour piloter le trafic, la recommandation est fausse même quand l'ordre obtenu semble correct par hasard.

Vérifiez quel réseau porte réellement la route par défaut

Vérifiez à l'intérieur du conteneur en cours d'exécution, car la table de routage de l'hôte décrit l'hôte et non l'espace de noms utilisé par le service. Lancez d'abord la vérification de configuration pour qu'une faute de frappe échoue avant un redémarrage, puis lisez la route que le conteneur a réellement installée.

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

Un résultat correct nomme le périphérique du pont et 172.30.50.1 ; un résultat erroné nomme 192.168.120.1 et le périphérique macvlan. Si l'image ne contient pas le paquet iproute2, le fichier /proc indique quand même la route par défaut, avec une destination 00000000 et les octets de la passerelle inversés. Comparez la colonne d'interface avec docker inspect quand les noms de périphériques ne sont pas clairs.

Macvlan est un port physique, pas un clone de pont

Macvlan donne au conteneur une seconde identité sur le câble, et c'est précisément ce qui fait fonctionner l'accès aux périphériques locaux. Cela signifie aussi que le port du commutateur et l'hyperviseur doivent accepter une adresse MAC supplémentaire, et beaucoup de réseaux cloud le refusent silencieusement. Testez un conteneur avant de planifier une flotte, car une MAC refusée se manifeste généralement comme un lien actif qui ne laisse rien passer.

Le réglage macvlan_mode: bridge est un mode du pilote macvlan, pas le pont logiciel de Docker, et passthru est un mode spécialisé distinct et non une valeur par défaut. Linux empêche aussi un conteneur macvlan d'atteindre son propre hôte à travers le même parent, et c'est la raison de conserver le pont de contrôle plutôt que d'attendre qu'un seul attachement fasse les deux tâches.

Nommez le parent VLAN avant que Compose ne le voie

Docker traite un parent pointé comme eno1.120 comme une sous-interface 802.1Q et crée lui-même le périphérique VLAN. Cette commodité a des limites : le nom dérivé dépend du nom de l'interface physique, et les noms longs peuvent pousser le résultat au-delà de ce que l'outillage environnant attend. Créer une interface VLAN nommée dans la configuration réseau de l'hôte et pointer parent dessus garde les deux extrémités prévisibles.

Rappelez-vous que la clé sous networks est un nom Compose, pas un périphérique Linux. Chercher sur l'hôte une interface nommée office échouera, car le noyau ne voit que l'interface parent et la paire veth derrière le conteneur.

Faites de la place pour le VPN par-dessus

Un client VPN s'attache après que ces réseaux existent, il peut donc ajouter des routes plus spécifiques, des règles de politique et des filtres indépendamment de gw_priority. Planifiez les préfixes distants par rapport aux deux subnets locaux, y compris les réponses dont le chemin de contrôle a besoin. Quand un préfixe distant chevauche le LAN du bureau, corrigez le plan d'adressage au lieu d'arracher toute une plage privée au tunnel.

Revérifiez les adresses, les routes et le chemin du service après le démarrage du VPN puis après sa reconnexion, car c'est lors d'une reconnexion que disparaît une route ajoutée à la main. Écrivez la table attendue avant le premier test pour que la comparaison ensuite soit un diff et non un exercice de mémoire. Gardez la propriété persistante du réseau dans Compose et laissez la configuration VPN ne posséder que sa propre politique.

Articles similaires