Por qué los contenedores de Docker ignoran el resolutor DNS de la VPN
Un contenedor copia el resolutor del anfitrión al arrancar, así que una VPN que reescribe el DNS más tarde queda invisible dentro. Pasa el resolutor explícitamente.
La VPN está activa, el navegador llega a los sitios internos y el contenedor sigue sin poder resolver los mismos nombres. Una instalación de paquete muere con un error de resolución de nombres como EAI_AGAIN, o una aplicación no encuentra un host de base de datos que la máquina anfitriona resuelve sin queja alguna. El contenedor no usa el resolutor que instaló la VPN. Docker copió la configuración del resolutor del anfitrión cuando se creó el contenedor, y nada la volvió a copiar después.
Dos vistas del resolutor en una misma máquina
En Linux, Docker da a cada contenedor una copia de la configuración del resolutor del anfitrión en el momento de crearlo, filtra las direcciones de loopback y ejecuta un servidor DNS integrado en 127.0.0.11 que reenvía las consultas hacia fuera. Un cliente de VPN que reescriba /etc/resolv.conf después de que el contenedor haya arrancado no cambia nada dentro de él. Reiniciar el contenedor solo ayuda si el resolutor del anfitrión resulta correcto en ese momento.
Docker Desktop en macOS o Windows añade una capa, porque el demonio vive en una máquina virtual. Puede que el resolutor de la VPN del anfitrión nunca sea visible para esa VM, así que reiniciar no cambia absolutamente nada. Compara las dos vistas antes de elegir una solución: docker exec mycontainer cat /etc/resolv.conf junto a la lista de resolutores del anfitrión.
Un contenedor que lista un resolutor público mientras el anfitrión lista uno interno resolverá los nombres públicos y fallará con los internos. Esa división es la firma de este problema.
Opción A: pasar el resolutor del túnel por contenedor
Docker acepta ajustes de DNS por contenedor, que es el cambio más pequeño que funciona. Primero lee las direcciones del resolutor de la VPN: scutil --dns en macOS, resolvectl status o la salida de estado del propio cliente en Linux. Después arranca el contenedor con ellas, por ejemplo docker run --dns 192.168.2.1 --dns 192.168.123.1 myimage. En Compose el mismo ajuste es una lista bajo el servicio, donde vive en el control de versiones en lugar del historial de shell de alguien.
Una matriz dns en /etc/docker/daemon.json se aplica a cada contenedor nuevo, lo que suena más ordenado y no lo es. También se aplica cuando el túnel está caído, y entonces un resolutor accesible solo a través de la VPN rompe las descargas de imágenes normales. Los ajustes por contenedor son más fáciles de razonar y más fáciles de deshacer.
Opción B: dejar que el contenedor comparta la red del anfitrión
La red del anfitrión evita la copia por completo, porque el contenedor usa el resolutor del anfitrión y el túnel del anfitrión. También elimina el aislamiento de red que probablemente querías, y no se comporta igual en Docker Desktop. En Linux es la opción pragmática para una herramienta de un solo uso que debe resolver nombres internos.
Para las compilaciones no se aplica ninguna de las dos opciones, ya que los pasos de compilación no heredan los indicadores de tiempo de ejecución. Compila con la red del anfitrión donde la plataforma lo permita, o mantén la instalación de dependencias en una etapa que no necesite el túnel.
Lo que ninguna de las dos opciones arregla
Una dirección DNS es inútil si el contenedor no tiene ruta hacia ella. El resolutor de la VPN suele estar dentro del espacio de direcciones del túnel, así que el contenedor necesita un camino hacia ese prefijo. El puente predeterminado de Docker normalmente enruta hacia fuera a través del anfitrión, lo que basta cuando el anfitrión tiene la ruta del túnel y el reenvío está activado. Las redes puente personalizadas con sus propios rangos de direcciones pueden chocar con la subred de la VPN, y entonces las consultas van a otro sitio por completo.
Comprueba la subred de la red de Docker contra la subred de la VPN antes de depurar el resolutor en sí. La superposición produce un fallo que parece exactamente un servidor DNS roto.
Verifica dentro del contenedor
Prueba con getent hosts db.internal dentro del contenedor en lugar de con un navegador o un entorno de ejecución de lenguaje, porque esos aplican su propia política de DNS y su propia caché. Si getent resuelve el nombre y la aplicación sigue fallando, el resolutor ya es correcto y el problema restante está en la capa de aplicación. Si no lo resuelve, el paso de DNS no está terminado.
Vuelve a crear el contenedor después de cambiar sus ajustes de DNS. Editar /etc/resolv.conf dentro de un contenedor en marcha desaparece con él y oculta el problema de configuración exactamente durante el tiempo que alguien tarda en reiniciarlo.