Pasei boa parte dunha mañá desta primavera perseguindo un contedor que non podía resolver un só nome interno mentres o navegador de ao lado abría o wiki sen queixarse. O túnel estaba activo, o navegador probábao, e o contedor quedaba en outro espazo de nomes de rede cunha outra táboa de rutas e outro resolvedor. O que segue é a orde que comprobo agora: primeiro as táboas de rutas, despois a resolución, logo o reenvío e por último a plataforma anfitrioa. Paráde na primeira etapa que xa falla, porque engadir regras máis abaixo na pila agocha a fronteira en vez de movela.

Comparade as tres táboas de rutas antes de cambiar unha regra

Un contedor na ponte predeterminada de Docker ten unha única ruta predeterminada que apunta á pasarela docker0 e non ten nin idea de que tun0 existe. O anfitrión ten tun0, as rutas que empurrou a VPN e quizais unha regra de política que envía o tráfico de proba por unha interface distinta da que esperades. WSL engade unha terceira táboa detrás do seu propio adaptador virtual. Imprimídeas as tres antes de editar calquera delas.

ContextCommandWhat a wrong answer looks like
Hostip route get 10.8.0.20Leaves a physical interface instead of tun0
Containerip routeOnly 172.17.0.0/16 via 172.17.0.1
Container DNScat /etc/resolv.confA public resolver, or an upstream the tunnel never pushed
WSLip addr; ip routeOnly the WSL subnet, no Windows VPN adapter

Se a única ruta do contedor é a ponte e tun0 nunca aparece no seu espazo de nomes, nada do que segue axudará: ningún cambio de servidor de nomes crea unha ruta, e ningunha ruta crea a identidade de túnel que o par aceptará. A orde importa porque un fallo de DNS e un fallo de ruta son idénticos desde dentro dunha shell.

Apuntade o resolvedor ao túnel en vez de a un público

No anfitrión, resolvectl status lista os servidores DNS por ligazón, e readlink -f /etc/resolv.conf divos se o ficheiro é o stub de systemd, un ficheiro de NetworkManager ou algo que reescribiu o cliente dun provedor. Dentro dun contedor nunha rede definida polo usuario, /etc/resolv.conf nomea 127.0.0.11, o resolvedor integrado de Docker, que reenvía ao upstream co que se configurou o daemon. Un contedor na ponte predeterminada, en cambio, recibiu unha copia do ficheiro do anfitrión cando se creou, e consérvaa.

Esa copia é a razón pola que un túnel que se levanta despois de arrancar o contedor deixa o contedor consultando o upstream antigo. Ou pasades o resolvedor da VPN explicitamente con docker run --dns 10.8.0.53, ou estabelecedes "dns": ["10.8.0.53"] en /etc/docker/daemon.json e reiniciades o daemon, ou recreades o contedor cando o túnel estea activo. Recrealo adoita ser máis barato que depurar un resolvedor que era correcto hai unha hora.

Cambiar a un resolvedor público é a reparación que mantén o síntoma. Resolve internet e falla en todas as zonas privadas, e pode saltar en silencio o filtrado que o túnel existe para impor. Se intentades escribir dentro do /etc/resolv.conf dun contedor en execución, esperade Device or resource busy: Docker monta ese ficheiro con bind, así que a edición necesita primeiro un desmontaxe. Estabelecer --dns na creación é a secuencia que sobrevive a un reinicio.

Reenviade e traducide cando os contedores toman prestado o túnel

Coa ponte predeterminada, o anfitrión é un encamiñador entre docker0 e tun0, e por defecto non fai ningún dos dous traballos. Activade o reenvío e traducide o enderezo de orixe para que o par vexa un enderezo de túnel do anfitrión en vez dun ao que non ten ruta de volta (substituíde tun0 polo nome que o voso cliente lle dá á interface):

sysctl -w net.ipv4.ip_forward=1
iptables -t nat -A POSTROUTING -o tun0 -j MASQUERADE
iptables -A FORWARD -i docker0 -o tun0 -j ACCEPT
iptables -A FORWARD -i tun0 -o docker0 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

As regras FORWARD importan nos anfitrións cuxa política de reenvío é DROP. Docker insire as súas propias cadeas, así que probade cun paquete en vez de ler iptables -S: desde o contedor, ip route get 10.8.0.20 debería nomear a pasarela da ponte, e nc -vz 10.8.0.20 443 debería conectar ou esgotar o tempo no túnel en vez de no resolvedor.

Sen MASQUERADE o par necesita unha ruta de volta a 172.17.0.0/16, que a maioría das VPN de acceso remoto non empurrarán. Aquí tamén rompe o plan un cliente baseado en políticas: se só captura o tráfico de UID ou cgroups concretos, as vosas regras de reenvío nunca ven o paquete dentro do túnel, e a corrección pertence á política de encamiñamento do cliente e non a iptables. As regras engadidas a man desaparecen ao reiniciar, así que póndeas nunha unidade de systemd ou nunha táboa netfilter-persistent e probade de novo tras un reinicio, xa que un túnel que se levanta tarde pode varrelas.

Pónde o túnel dentro do contedor cando o obxectivo é o illamento

Se un contedor ten que saír por un nodo concreto, executade o cliente nese contedor. Necesita --cap-add NET_ADMIN e --device /dev/net/tun, e entón posúe o seu propio tun0, as súas rutas e o seu cortalumes. Se outros contedores pasan por el, tamén necesita reenvío e unha regra MASQUERADE dentro do contedor, e eses pares necesitan unha ruta ou un proxy explícitos que apunten a el; a ponte predeterminada de Docker non engade esa ruta por vós.

A rede do anfitrión, docker run --network host, é a versión barata: o contedor únese ao espazo de nomes do anfitrión e ve as rutas do túnel directamente. Tamén descarta o illamento de rede, invita a colisións de portos e, na práctica, é unha opción de Linux. Un porto publicado non é un substituto. -p 8080:80 fai que un servizo sexa accesible desde o anfitrión; non fai que os enderezos internos 10.x sexan accesibles desde dentro do contedor, e confundir as dúas cousas é como un problema de encamiñamento se converte nun porto de base de datos exposto.

Distinguide un fallo de nomes dunha subrede solapada

A ponte predeterminada de Docker é 172.17.0.0/16, e moitos rangos de VPN corporativas están dentro de 172.16.0.0/12. Unha vez que o túnel posúe ese rango, o tráfico destinado a un contedor pode encamiñarse cara ao túnel. Os nomes fallan, o erro parece DNS, e o problema son os enderezos. Comprobade o destino, non o resolvedor: ip route get 172.17.0.5 no anfitrión, e despois comparade o prefixo da ponte co rango da VPN e con docker network inspect bridge --format '{{range .IPAM.Config}}{{.Subnet}}{{end}}'.

A reparación é mover un dos rangos: ou un rango de enderezos predeterminado distinto para Docker en daemon.json ou un rango distinto no concentrador. Engadir outro servidor de nomes non fai nada aquí, e tampouco o fai ssh -b: ligar o cliente a unha interface cambia o enderezo de orixe, non unha ruta de destino que apunta cara ao túnel. Reparto rápido do traballo: un nome que se resolve no anfitrión pero non no contedor é un problema de resolvedor, mentres que unha conexión IP directa que se colga no contedor pero funciona no anfitrión é un problema de ruta ou de cadea de reenvío.

WSL e Docker Desktop non seguen as regras de Linux

No seu modo NAT predeterminado, WSL está detrás do seu propio adaptador virtual e non recibe as rutas internas nin os sufixos DNS da VPN de Windows, e por iso o navegador funciona e ping dentro da distribución non. A rede espello, dispoñible en compilacións recentes de Windows 11, comparte en cambio as interfaces do anfitrión, pero hai que activala en .wslconfig e reiniciar a distribución con wsl --shutdown. Confirmade o modo activo con wslinfo --networking-mode antes de aplicar unha corrección, porque a resposta NAT é incorrecta para o modo espello e viceversa.

Docker Desktop engade outra capa. Os contedores Linux en Windows están detrás dunha implementación NAT chamada historicamente vpnkit, e o seu camiño difire do dun anfitrión Linux nativo. Os contedores Windows conéctanse mediante un conmutador virtual de Hyper-V, e un cliente corporativo pode bloquear o tráfico dese conmutador, así que os contedores Linux da mesma máquina poden chegar á rede mentres os contedores Windows non teñen nada. Un conmutador externo ligado ao adaptador físico é a solución habitual, e cambia a identidade de rede do contedor de maneiras que a política pode non permitir.

Antes de escribir outra regra, percorrede as catro capas en orde e parád onde unha delas estea mal:

  • Dentro do contedor: ip route chega ao prefixo privado, e /etc/resolv.conf nomea un upstream que o resolve?
  • No anfitrión: o reenvío está activo, NAT está ligado á interface do túnel, e a cadea de reenvío acepta a ponte cara ao túnel?
  • No par: coñece unha ruta de volta, ou confiades en NAT para agochar a subrede do contedor?
  • Na plataforma: WSL está en modo NAT ou espello, e o contedor é Linux ou Windows?

Executade de novo cada proba nun contedor ou unha shell novos. Un proceso de longa duración cunha resposta na caché ou unha conexión estabelecida seguirá fallando cando a configuración xa é correcta, e ese fallo parece exactamente unha corrección que non funcionou.

Artigos relacionados