Un Dev Container n’atteint pas un hôte accessible uniquement par VPN : où chercher
Le navigateur et le conteneur ont des contextes de résolution, de proxy et de routage différents. Déterminez lequel utilise le processus qui échoue avant de modifier le moindre réglage VPN.
L’API privée s’ouvre dans votre navigateur de bureau et échoue dans le conteneur de développement. Ce n’est pas une contradiction, et c’est rarement le VPN lui-même. La requête du navigateur et la requête qui échoue ont été émises par des processus différents, avec des résolveurs, des proxys et des routes différents, et souvent depuis des espaces de noms réseau totalement distincts. « Sur mon portable » peut désigner l’hôte Windows, une distribution WSL, la machine virtuelle Docker Desktop et un conteneur à l’intérieur de cette VM : quatre contextes qui peuvent chacun répondre différemment au même nom d’hôte. Déterminez lequel utilise le processus qui échoue avant de toucher au moindre réglage.
Localisez le processus avant de changer un réglage
Commencez par le moteur de conteneurs, pas par le client VPN. Demandez à quel contexte parle la ligne de commande et sur quel système d’exploitation ce moteur tourne, car un conteneur Linux géré par une VM de bureau suit un chemin différent de celui géré par un démon local :
docker context ls
docker info --format '{{.OperatingSystem}} / {{.Name}}'
docker run --rm alpine ip route
Sous Windows, wsl -l -v vous indique si la distribution tourne sous WSL 2, ce qui la place derrière son propre commutateur virtuel. Ce détail décide si le conteneur partage la table de routage de l’hôte ou se trouve derrière un NAT qui a besoin d’un port redirigé ou d’un nom d’hôte pour atteindre l’hôte.
Gardez une requête constante et comparez
Choisissez un point de terminaison inoffensif sur l’hôte privé et utilisez-le pour chaque comparaison : depuis le navigateur, depuis un terminal de l’hôte, depuis la distribution WSL et depuis l’intérieur du conteneur. Notez quatre choses pour chaque tentative : l’adresse résolue, si un proxy a été utilisé, la classe d’échec et le temps écoulé. La résolution de nom, l’établissement de la connexion, la validation TLS et un statut HTTP sont quatre problèmes différents, et les mélanger dans « ça ne marche pas » fait perdre une matinée.
Exécutez la comparaison à l’intérieur du conteneur qui échoue, avec un délai d’expiration pour qu’un pare-feu silencieux ne bloque pas le terminal pendant des minutes. Un conteneur neuf reproduit le contexte réseau du moteur, mais pas l’espace de noms, les variables de proxy ni le résolveur du conteneur applicatif, donc docker exec dans le vrai conteneur est le test qui fait foi, et un conteneur annexe n’est qu’un moyen d’isoler si la différence vient du moteur ou du conteneur :
docker exec -it app /bin/sh -c "getent hosts api.internal; curl -v --max-time 8 https://api.internal/ 2>&1 | tail -20"
docker run --rm --network container:app curlimages/curl:latest -sv --max-time 8 https://api.internal/ 2>&1 | tail -20
L’image de base alpine embarque busybox et pas curl, et c’est exactement le genre de détail qui fait échouer un bloc de diagnostic copié : prenez une image avec le client, ou ajoutez-le dans la même exécution. Une comparaison avec des sites publics sans rapport n’isole rien. Si https://example.com fonctionne depuis le conteneur, vous avez appris que le conteneur a un accès Internet et rien sur sa capacité à atteindre une adresse privée par le tunnel. De même, ouvrir un nouveau terminal prouve seulement que le nouveau terminal fonctionne, pas qu’il partage un environnement d’exécution avec l’application qui a échoué.
Docker Desktop peut très bien fonctionner avec un VPN
La documentation de Docker sur les VPN et la connectivité à l’hôte décrit cela comme une configuration prise en charge, et le résumé honnête est que cela fonctionne plutôt que d’être cassé par défaut. Ne supposez pas que la VM de bureau contourne le tunnel de l’hôte par conception ; dans de nombreuses configurations, le trafic suit correctement le tunnel de l’hôte, et c’est pourquoi la légende « Docker ignore le VPN » produit des conseils assurés et faux.
Ce qui compte encore, c’est le backend utilisé, la politique de tunnel divisé du client et la configuration du résolveur reçue par la VM. Un client VPN qui installe des routes mais pas de DNS, ou qui pousse un serveur DNS que la VM ne peut pas joindre, produit un échec de résolution de nom dans le conteneur tandis que l’hôte fonctionne parce qu’il dispose d’un résolveur supplémentaire ou d’une réponse en cache. C’est un problème de résolveur déguisé en conteneur. Il survit à chaque reconnexion VPN que vous tentez, car le tunnel transporte déjà le trafic que vous lui avez demandé.
Les chevauchements d’adresses et la MTU sont des pannes différentes
Deux pannes méritent leur propre diagnostic car on les confond souvent avec une politique d’accès. La première est un chevauchement d’adresses : si le VPN pousse une plage qui entre en collision avec le sous-réseau du pont par défaut d’un réseau de conteneurs, la route du conteneur pour cette plage pointe vers le pont local et n’atteint jamais le tunnel. Inspectez les sous-réseaux réels au lieu de deviner :
docker network inspect bridge --format '{{range .IPAM.Config}}{{.Subnet}}{{end}}'
ip route get 10.20.30.40
La seconde est un problème de MTU. Si la connexion s’établit et que TLS se termine mais que les réponses plus grosses se bloquent, vous avez un problème de taille de paquet, pas d’autorisation, et remplacer des enregistrements DNS n’y changera jamais rien. Testez avec une petite requête et une grosse avant de modifier quoi que ce soit, et notez les deux résultats.
La solution à un chevauchement est un autre sous-réseau de conteneur ou une route restreinte, choisie par celui qui possède le plan d’adressage. La solution à un blocage MTU est de fixer ou de réduire la MTU du tunnel ou de l’interface à une valeur qui survit au chemin, appliquée à la couche que vous contrôlez.
La configuration du proxy est par processus, pas par machine
À l’intérieur d’un conteneur, localhost désigne le contexte réseau propre à ce conteneur, donc un proxy exécuté sur l’hôte n’y est pas joignable sous ce nom. Docker Desktop fournit host.docker.internal pour accéder à l’hôte, et sous Linux vous l’ajoutez explicitement avec --add-host=host.docker.internal:host-gateway. Dans les deux cas, ce nom vous donne une route vers l’hôte ; il ne crée pas de service proxy et ne vous autorise pas à en utiliser un.
Utilisez l’adresse et le port du proxy fournis pour l’environnement réel, et vérifiez qui les lit. Les variables exportées dans un shell interactif ne configurent pas automatiquement chaque extension d’éditeur, serveur de langage, outil de build et démon en arrière-plan. Celui qui compte est le processus qui a émis la requête en échec, donc inspectez son environnement plutôt que celui de votre terminal.
Enfin, faites en sorte que la correction s’explique d’elle-même. Une résolution utile nomme la frontière qui était fausse, le réglage qui l’a changée et l’ensemble des processus qu’elle affecte désormais. Redémarrer le VPN, l’éditeur et le moteur dans l’ordre peut modifier le symptôme, mais ne laisse rien que la personne suivante puisse utiliser.