Varför Docker-containrar ignorerar VPN:ets DNS-resolver
En container kopierar värdens resolver när den startar, så en VPN som skriver om DNS senare förblir osynlig inuti den. Skicka resolvern uttryckligen.
VPN:et är uppe, webbläsaren når interna webbplatser, och containern kan fortfarande inte slå upp samma namn. En paketinstallation dör med ett namnmatchningfel som EAI_AGAIN, eller ett program hittar ingen databassvärd som värddatorn slår upp utan klagomål. Containern använder inte resolvern som VPN:et installerade. Docker kopierade värdens resolverkonfiguration när containern skapades, och ingenting kopierade den igen efteråt.
Två resolver-vyer på en maskin
På Linux ger Docker varje container en kopia av värdens resolverkonfiguration vid skapandet, filtrerar bort loopback-adresser och kör en inbyggd DNS-server på 127.0.0.11 som vidarebefordrar frågor utåt. En VPN-klient som skriver om /etc/resolv.conf efter att containern startat ändrar ingenting inuti den. Att starta om containern hjälper bara om värdens resolver råkar vara korrekt i det ögonblicket.
Docker Desktop på macOS eller Windows lägger till ett lager, eftersom daemonen bor i en virtuell maskin. Värdens VPN-resolver är kanske aldrig synlig för den VM:en, så en omstart ändrar ingenting alls. Jämför de två vyerna innan du väljer en lösning: docker exec mycontainer cat /etc/resolv.conf bredvid värdens resolverlista.
En container som listar en offentlig resolver medan värden listar en intern löser offentliga namn och misslyckas med interna. Den delningen är signaturen för det här problemet.
Alternativ A: skicka tunnelresolvern per container
Docker accepterar DNS-inställningar per container, och det är den minsta ändringen som fungerar. Läs först VPN:ets resolveradresser: scutil --dns på macOS, resolvectl status eller klientens egen statusutskrift på Linux. Starta sedan containern med dem, till exempel docker run --dns 192.168.2.1 --dns 192.168.123.1 myimage. I Compose är samma inställning en lista under tjänsten, där den bor i versionskontroll i stället för i någons shellhistorik.
En dns-array i /etc/docker/daemon.json gäller för varje ny container, vilket låter snyggare än det är. Den gäller också när tunneln ligger nere, och en resolver som bara nås via VPN:et förstör då vanliga image-hämtningar. Inställningar per container är lättare att motivera och lättare att ångra.
Alternativ B: låt containern dela värdens nätverk
Värdnätverk kringgår kopian helt, eftersom containern använder värdens resolver och värdens tunnel. Det tar också bort den nätverksisolering du förmodligen ville ha, och det beter sig inte likadant under Docker Desktop. På Linux är det det pragmatiska valet för ett engångsverktyg som måste slå upp interna namn.
För byggen gäller inget av alternativen, eftersom byggsteg inte ärver körtidsflaggor. Bygg med värdnätverk där plattformen tillåter det, eller håll beroendeinstallationen i ett steg som inte behöver tunneln.
Vad inget av alternativen åtgärdar
En DNS-adress är värdelös om containern inte har någon rutt dit. VPN:ets resolver sitter oftast inne i tunnelns adressutrymme, så containern behöver en väg till det prefixet. Dockers standardbrygga dirigerar normalt ut genom värden, och det räcker när värden har tunnelrutten och vidarebefordran är aktiverad. Anpassade bryggnätverk med egna adresspooler kan kollidera med VPN:ets subnät, och då går frågorna någon helt annanstans.
Kontrollera Docker-nätverkets subnät mot VPN:ets subnät innan du felsöker själva resolvern. Överlapp ger ett fel som ser exakt ut som en trasig DNS-server.
Verifiera inuti containern
Testa med getent hosts db.internal inuti containern i stället för med en webbläsare eller en språkkörtid, eftersom de tillämpar sin egen DNS-policy och sin egen cache. Om getent slår upp namnet och programmet fortfarande misslyckas är resolvern nu korrekt och det återstående problemet ligger på programnivå. Om den inte slår upp det är DNS-steget inte klart.
Skapa containern på nytt efter att du ändrat dess DNS-inställningar. Redigering av /etc/resolv.conf i en körande container försvinner med den och döljer konfigurationsproblemet exakt så länge som någon behöver för att starta om den.