De ce containerele Docker ignoră resolverul DNS al VPN-ului
Un container copiază resolverul gazdei la pornire, așa că un VPN care rescrie DNS mai târziu rămâne invizibil în interiorul lui. Transmite resolverul explicit.
VPN-ul este pornit, browserul ajunge la site-uri interne, iar containerul tot nu poate rezolva aceleași nume. Instalarea unui pachet moare cu o eroare de rezolvare a numelor precum EAI_AGAIN, sau o aplicație nu găsește un host de baze de date pe care mașina gazdă îl rezolvă fără nicio plângere. Containerul nu folosește resolverul instalat de VPN. Docker a copiat configurația resolverului gazdei când a fost creat containerul, iar după aceea nimic nu a mai copiat-o din nou.
Două vederi ale resolverului pe aceeași mașină
Pe Linux, Docker oferă fiecărui container o copie a configurației resolverului gazdei în momentul creării, filtrează adresele de loopback și rulează un server DNS încorporat la 127.0.0.11 care redirecționează interogările spre exterior. Un client VPN care rescrie /etc/resolv.conf după pornirea containerului nu schimbă nimic în interiorul lui. Repornirea containerului ajută doar dacă resolverul gazdei este corect în acel moment din întâmplare.
Docker Desktop pe macOS sau Windows adaugă un strat, pentru că daemonul trăiește într-o mașină virtuală. Resolverul VPN al gazdei poate să nu fie niciodată vizibil pentru acea VM, așa că repornirea nu schimbă absolut nimic. Comparați cele două vederi înainte de a alege o soluție: docker exec mycontainer cat /etc/resolv.conf lângă lista de resolveri a gazdei.
Un container care listează un resolver public în timp ce gazda listează unul intern va rezolva numele publice și va eșua la cele interne. Această divizare este semnătura acestei probleme.
Opțiunea A: transmiterea resolverului tunelului pentru fiecare container
Docker acceptă setări DNS pentru fiecare container, iar aceasta este cea mai mică modificare care funcționează. Citiți mai întâi adresele resolverului VPN: scutil --dns pe macOS, resolvectl status sau ieșirea de stare a clientului însuși pe Linux. Apoi porniți containerul cu ele, de exemplu docker run --dns 192.168.2.1 --dns 192.168.123.1 myimage. În Compose aceeași setare este o listă sub serviciu, unde trăiește în controlul versiunilor în locul istoricului de shell al cuiva.
Un tablou dns în /etc/docker/daemon.json se aplică fiecărui container nou, ceea ce sună mai ordonat decât este. Se aplică și când tunelul este căzut, iar un resolver accesibil doar prin VPN strică atunci descărcările obișnuite de imagini. Setările pe container sunt mai ușor de justificat și mai ușor de anulat.
Opțiunea B: lăsați containerul să partajeze rețeaua gazdei
Rețeaua gazdei ocolește complet copia, pentru că containerul folosește resolverul gazdei și tunelul gazdei. Elimină însă și izolarea de rețea pe care probabil o doreați, și nu se comportă la fel sub Docker Desktop. Pe Linux este alegerea pragmatică pentru un instrument de unică folosință care trebuie să rezolve nume interne.
Pentru build-uri nu se aplică niciuna dintre opțiuni, deoarece pașii de build nu moștenesc steaguri de rulare. Construiți cu rețeaua gazdei acolo unde platforma permite, sau păstrați instalarea dependențelor într-o etapă care nu are nevoie de tunel.
Ce nu repară niciuna dintre opțiuni
O adresă DNS este inutilă dacă containerul nu are o rută către ea. Resolverul VPN stă de obicei în spațiul de adrese al tunelului, așa că containerul are nevoie de o cale către acel prefix. Puntea implicită a Docker rutează de obicei spre exterior prin gazdă, și asta este suficient când gazda are ruta tunelului și redirecționarea este activată. Rețelele punte personalizate cu propriile pool-uri de adrese pot intra în conflict cu subrețeaua VPN, iar atunci interogările ajung cu totul altundeva.
Verificați subrețeaua rețelei Docker față de subrețeaua VPN înainte de a depana resolverul în sine. Suprapunerea produce o defecțiune care arată exact ca un server DNS stricat.
Verificați în interiorul containerului
Testați cu getent hosts db.internal în interiorul containerului, nu cu un browser sau un runtime de limbaj, pentru că acelea aplică propria politică DNS și propria memorie cache. Dacă getent rezolvă numele și aplicația tot eșuează, resolverul este acum corect, iar problema rămasă este la nivel de aplicație. Dacă nu îl rezolvă, pasul DNS nu este încheiat.
Recreeați containerul după ce îi modificați setările DNS. Editarea /etc/resolv.conf într-un container care rulează dispare odată cu el și ascunde problema de configurație exact atât timp cât are nevoie cineva să îl repornească.