Containeren når ikke API-et som bare finnes via VPN? Proxy det på verten
Tunnelen lever på verten, så containeren har ingen rute til den private adressen. Publiser en smal omvendt proxy og kall den som host.docker.internal.
Compose-tjenesten din timer ut mot et API som nettleseren på samme maskin åpner uten klage. Den forskjellen er ledetråden: forespørselen som virker, forlater en vert med VPN-tunnel, og forespørselen som henger, forlater en container med sin egen nettverksstakk. Ingenting inne i containeren kjenner tunnelens ruter, så den private destinasjonen forblir utilgjengelig uansett hvordan navnet skrives. Løsningen er et bevisst hopp gjennom verten, ikke en smartere rutetabell.
Start med hvorfor de to veiene er forskjellige, og bestem deretter hvor tunnelen skal bo.
Hvorfor verten virker og containeren ikke
Å reise tunnelen gir verten et grensesnitt, et sett ruter og vanligvis en resolver-oppføring som VPN-et leverer. En container arver ingenting av dette: den starter med ett grensesnitt på motorens bro og en standardrute som peker på den broen. Ruter installert på verten er usynlige for alt som kjører inne i det navnerommet.
Derfor virker symptomene inkonsistente og ikke bare ødelagte. Verten løser det private navnet og kobler til, fordi både navnet og ruten finnes der. Containeren sender pakken sin til en privat adresse som ingenting på broveien kan nå, og forespørselen timer ut. Å legge navnet til i containerens hosts-fil endrer ingenting, fordi adressen selv er utilgjengelig fra der containeren sitter.
Nå verten fra innsiden av containeren
En prosess i containeren som ringer localhost, ringer containeren. Docker Desktop publiserer host.docker.internal som et navn som peker tilbake på maskinen som kjører motoren; Linux-motorer lar det være udefinert med mindre tjenesten ber om det, og det er nettopp det mappingen nedenfor gjør. Med det på plass retter applikasjonen seg mot et navn og en port i stedet for den private adressen.
services:
app:
extra_hosts:
- "host.docker.internal:host-gateway"
environment:
INTERNAL_API_HOST: "host.docker.internal:8666"Tunnelen blir på vertssiden av hoppet, og porten i den variabelen er den proxyen vil lytte på. En container som mister tunnelen, feiler nå på ett kjent hopp i stedet for å prøve en rute den aldri hadde.
Velg hvor tunnelen bor
Tre former er mulige for en Compose-tjeneste som trenger et privat API, og de skiller seg i hvilken prosess som eier tunnelen. En VPN-klient kan kjøre inne i containerbildet, noe som krever at en tunnel-enhet eksponeres og at nettverksadministrasjonsevnen som følger med, gis. Applikasjonen kan dele nettverksnavnerommet til en separat tunnelcontainer, slik at begge prosessene ser én stakk og én rutetabell. Eller tunnelen kan bli på verten, med en smal videresender fra verten inn i containeren.
De to første drar profilfiler, gjenoppkoblingsadferd og resolver-policy inn i prosjektet, og gjør hver tjeneste i filen avhengig av tunnelens helse. Det er mye kobling for ett API-kall. For en utviklingsstakk som leser ett internt endepunkt, er videresenderen på vertssiden den minste endringen som fortsatt holder legitimasjonen der plattformteamet administrerer dem.
Publiser én smal vei på verten
Begynn med det videresenderen arver: kjør den som kontoen som eier tunnelen, og dens utgående sokler tar over vertens ruter og vertens resolver. Én nginx location-blokk dekker én vei.
server {
listen 8666;
location /search/ {
proxy_pass http://10.20.30.40:8090/;
proxy_set_header Host internal-api.example;
proxy_read_timeout 60s;
}
}Behandle adressen og porten som plassholdere og sett inn paret som API-et faktisk lytter på. Hver videre upstream fortjener sin egen location-blokk, og hver blokk bør bare slippe inn veiene denne tjenesten kaller, slik at proxyen ikke blir en generell dør inn i det private nettverket. Bind lytteren til broadressen for klienter som kommer via host-gateway, til loopback bare når klienten deler vertens nettverksnavnerom, og aldri til 0.0.0.0. Velg også en port som fortsatt er ledig: et nummer som allerede er tatt, lar proxyen stå uten å lytte mens containeren fortsetter å time ut, noe som ikke kan skilles fra nettverksfeilen du startet med.
Porter, navn og TLS-beslutningen
Navneoppslag deler seg på samme måte som ruting. Containerens offentlige oppslag går gjennom motorens resolver, så et privat navn som løses på verten, vil ikke løses inne i containeren. Proxyen er komponenten som løser det private navnet, fordi den arver vertens resolver.
TLS er beslutningen som utsettes og deretter forklarer den neste feilen. Hvis proxyen videresender bytes urørt, ser containeren API-ets eget sertifikat og trenger den interne CA-en i sitt tillitslager. Hvis proxyen terminerer TLS, flytter den tilliten til verten, og applikasjonen begynner å bygge lenker fra host-headeren den mottar. Velg én ordning og bruk den på hver ressurs, fordi en omdirigering fra den andre peker på et vertsnavn containeren ikke kan løse.
Verifiser fra innsiden av tjenesten
Send forespørselen fra containeren, ikke fra verten: en vanlig curl mot proxy-veien, deretter applikasjonens egen helsesjekk. Når proxyen svarer men applikasjonen fortsatt feiler, sammenlign tre ting: basis-URL-en den bygger, enhver proxyvariabel i miljøet og CA-en den stoler på. Alle ligger i containerens miljø og logger, og å rette en av dem lar VPN-et være i fred.
Skriv den valgte ordningen i prosjektets README mens den er fersk. Ellers vil neste person som treffer denne tidsavbruddet bruke samme ettermiddag på å gjenoppdage at tunnelen bor på verten.