Trafic Docker et VM derrière OpenVPN : router ou renuméroter ?
Les conteneurs et les invités d'un hôte équipé d'un client OpenVPN perdent soit le chemin de retour, soit entrent en collision avec le préfixe du tunnel. Trois questions choisissent la correction.
L'hôte navigue à travers le tunnel et le conteneur à côté n'atteint rien. Publier un port depuis un conteneur qui exécute son propre client VPN est pire : la requête arrive et la réponse ne part jamais. Les deux sont des décisions de routage sur l'hôte, et Docker n'est que le messager.
Trois questions déterminent lequel des deux cas vous regardez, et elles prennent environ une minute.
Deux pannes qui se présentent de la même façon
La première est un problème de chemin de retour. Le port publié est traduit vers le conteneur, la requête arrive, et la réponse est routée par la route par défaut de l'hôte, que le client OpenVPN a pointée vers tun0. La réponse part d'une adresse que le pair distant n'attend pas, et elle est rejetée. La seconde est une collision de préfixes : le pont par défaut de Docker possède 172.17.0.0/16 et un tunnel d'entreprise pousse la même plage.
L'une se corrige avec une table de routage, l'autre en renumérotant un pont. Modifier avant de savoir laquelle est laquelle, c'est ainsi qu'on casse un conteneur qui fonctionnait.
Décidez avec trois questions
Première question : la panne disparaît-elle quand vous arrêtez le VPN ? Si tout fonctionne tunnel coupé, soupçonnez le chemin de retour. Deuxième question : ip route show table all liste-t-il le même préfixe deux fois, une fois sur un pont et une fois sur tun0 ? C'est la collision. Troisième question : l'adresse touchée est-elle un conteneur, un invité NAT ou un invité en pont ?
La troisième question compte parce que chacune a une correction correcte différente, et appliquer la correction du conteneur à un invité libvirt gâche une soirée.
ip route
ip route show table all | grep -E '172\.1[7-9]|10\.8'
docker network inspect bridge --format '{{.IPAM.Config}}'Chemin de retour : une table pour une adresse source
Quand le trafic du conteneur doit sortir par l'interface physique alors que l'hôte lui-même utilise le tunnel, le routage basé sur la source est le plus petit changement. Ajoutez une règle correspondant à l'adresse du conteneur et envoyez-la vers une table dédiée. Rien d'autre sur l'hôte ne bouge.
ip rule add from 172.22.0.3 lookup 10
ip route add default via 172.22.0.1 table 10Chaque paquet dont la source est cette adresse consulte d'abord la table 10, et la table 10 l'envoie vers la passerelle du pont au lieu du tunnel.
Vérifiez avec ip route get 1.1.1.1 from 172.22.0.3. La réponse doit nommer l'interface du pont, pas tun0. Les règles ajoutées ainsi disparaissent au redémarrage, alors placez-les dans l'unité ou le hook réseau qui possède le conteneur.
Le même schéma fonctionne pour un conteneur WireGuard, où le chemin de retour a lui aussi besoin d'une règle explicite.
Collision de préfixes : renumérotez le pont
Une table de routage envoie un préfixe à un seul endroit. Si le VPN pousse 172.17.0.0/16 alors que le pont de Docker est déjà là, la métrique la plus basse l'emporte : Docker installe sa route connectée à la métrique 0, et la route poussée arrive à 50. Le tunnel semble alors cassé pendant que Docker continue de fonctionner, ou l'inverse, selon l'ordre d'installation. Renumérotez le pont plutôt que de lutter contre la métrique.
{
"bip": "10.200.0.1/24",
"default-address-pools": [{"base": "10.201.0.0/16", "size": 24}]
}Redémarrez Docker après le changement et recréez les réseaux construits avec l'ancien pool. Changer la métrique ne fait que déplacer le conflit au prochain démarrage.
Les VM ont encore besoin d'une autre réponse
Un invité libvirt sur le réseau NAT par défaut hérite du routage de l'hôte et cesse d'atteindre l'extérieur dès que le tunnel de l'hôte possède la route par défaut. Passer l'invité à un périphérique en pont ou macvtap lui donne son propre chemin sur le réseau physique. Dans virt-manager, ajoutez du matériel, choisissez Network, mettez la source sur le périphérique hôte macvtap, gardez virtio comme modèle, puis désactivez l'ancienne interface NAT.
Un invité macvtap ne peut généralement pas atteindre son propre hôte. C'est un comportement attendu et non une panne, et cela appartient à la note que vous laissez.
Pour un invité qui n'a besoin que du LAN de l'hôte, le client du fournisseur a peut-être l'interrupteur manquant : avec Mullvad, mullvad lan set allow rétablit l'accès local sans toucher à libvirt. Et quand un conteneur doit être joignable uniquement par le tunnel, attachez le port publié à l'adresse du tunnel, -p 10.8.0.5:8080:8080, au lieu de le publier sur toutes les adresses.