Zašto Docker kontejneri ignoriraju VPN-ov DNS resolver
Kontejner kopira hostov resolver pri pokretanju, pa VPN koji kasnije prepiše DNS ostaje nevidljiv unutar njega. Prenesite resolver eksplicitno.
VPN radi, preglednik dolazi do internih stranica, a kontejner i dalje ne može razriješiti ista imena. Instalacija paketa pada s pogreškom razrješavanja imena kao što je EAI_AGAIN, ili aplikacija ne može pronaći host baze podataka koji host mašina razrješava bez ikakve žalbe. Kontejner ne koristi resolver koji je VPN instalirao. Docker je kopirao konfiguraciju hostovog resolvera kada je kontejner stvoren, i ništa je nakon toga nije ponovno kopiralo.
Dva pogleda na resolver na istom stroju
Na Linuxu Docker svakom kontejneru daje kopiju konfiguracije hostovog resolvera u trenutku stvaranja, filtrira loopback adrese i pokreće ugrađeni DNS poslužitelj na 127.0.0.11 koji prosljeđuje upite prema van. VPN klijent koji prepiše /etc/resolv.conf nakon što je kontejner pokrenut ne mijenja ništa unutar njega. Ponovno pokretanje kontejnera pomaže samo ako je hostov resolver u tom trenutku slučajno ispravan.
Docker Desktop na macOS-u ili Windowsu dodaje sloj, jer daemon živi u virtualnom stroju. Hostov VPN resolver možda nikada neće biti vidljiv tom VM-u, pa ponovno pokretanje ne mijenja baš ništa. Usporedite dva pogleda prije nego što odaberete rješenje: docker exec mycontainer cat /etc/resolv.conf pokraj hostovog popisa resolvera.
Kontejner koji navodi javni resolver dok host navodi interni razrješavat će javna imena i padati na internima. Ta je podjela potpis ovog problema.
Opcija A: prenijeti resolver tunela po kontejneru
Docker prihvaća DNS postavke po kontejneru, što je najmanja promjena koja funkcionira. Prvo pročitajte adrese VPN resolvera: scutil --dns na macOS-u, resolvectl status ili vlastiti statusni izlaz klijenta na Linuxu. Zatim pokrenite kontejner s njima, na primjer docker run --dns 192.168.2.1 --dns 192.168.123.1 myimage. U Compose-u je ista postavka popis ispod servisa, gdje živi u kontroli verzija umjesto u nečijoj povijesti naredbi.
Niz dns u /etc/docker/daemon.json primjenjuje se na svaki novi kontejner, što zvuči urednije nego što jest. Primjenjuje se i kada je tunel pao, a resolver dostupan samo kroz VPN tada kvari obično povlačenje slika. Postavke po kontejneru lakše je obrazložiti i lakše poništiti.
Opcija B: neka kontejner dijeli hostovu mrežu
Hostovo umrežavanje u potpunosti zaobilazi kopiju, jer kontejner koristi hostov resolver i hostov tunel. Ono uklanja i mrežnu izolaciju koju ste vjerojatno htjeli, i ne ponaša se isto pod Docker Desktopom. Na Linuxu je to pragmatičan izbor za jednokratni alat koji mora razrješavati interna imena.
Za buildove ne vrijedi nijedna opcija, jer koraci builda ne nasljeđuju zastavice vremena izvršavanja. Gradite s hostovim umrežavanjem gdje platforma to dopušta, ili držite instalaciju zavisnosti u fazi kojoj tunel nije potreban.
Što nijedna opcija ne popravlja
DNS adresa je beskorisna ako kontejner nema rutu do nje. VPN resolver obično sjedi unutar adresnog prostora tunela, pa kontejneru treba put do tog prefiksa. Dockerov zadani most obično usmjerava prema van kroz host, što je dovoljno kada host ima rutu tunela i kada je prosljeđivanje omogućeno. Prilagođene mostovne mreže s vlastitim bazenima adresa mogu se sudariti s VPN podmrežom, a tada upiti odlaze sasvim negdje drugdje.
Provjerite podmrežu Docker mreže prema VPN podmreži prije nego što otklanjate pogreške u samom resolveru. Preklapanje proizvodi kvar koji izgleda točno kao pokvaren DNS poslužitelj.
Provjerite unutar kontejnera
Testirajte s getent hosts db.internal unutar kontejnera, a ne preglednikom ili jezičnim runtimeom, jer oni primjenjuju vlastitu DNS politiku i vlastito keširanje. Ako getent razriješi ime a aplikacija i dalje pada, resolver je sada ispravan i preostali problem je na razini aplikacije. Ako ga ne razriješi, DNS korak nije dovršen.
Ponovno kreirajte kontejner nakon promjene njegovih DNS postavki. Uređivanje /etc/resolv.conf unutar pokrenutog kontejnera nestaje s njim i skriva problem konfiguracije točno onoliko koliko nekome treba da ga ponovno pokrene.