Kan containeren ikke nå API’et, der kun er tilgængeligt via VPN? Proxy det på værten
Tunnelen lever på værten, så containeren har ingen rute til den private adresse. Udgiv en smal omvendt proxy, og kald den som host.docker.internal.
Din Compose-tjeneste timer ud mod et API, som browseren på samme maskine åbner uden klage. Den forskel er selve sporet: den anmodning, der virker, forlader en vært med en VPN-tunnel, og den anmodning, der hænger, forlader en container med sin egen netværksstak. Intet inde i containeren kender tunnelens ruter, så den private destination forbliver utilgængelig, uanset hvordan navnet staves. Løsningen er et bevidst hop gennem værten, ikke en smartere rutetabel.
Begynd med hvorfor de to veje er forskellige, og beslut derefter, hvor tunnelen skal bo.
Hvorfor værten virker, og containeren ikke gør
Når tunnelen rejses, får værten et interface, et sæt ruter og som regel en resolver-post fra VPN’en. En container arver intet af det: den starter med ét interface på motorens bro og en standardrute, der peger på den bro. Ruter installeret på værten er usynlige for alt, der kører inde i det navnerum.
Derfor virker symptomerne inkonsistente snarere end bare i stykker. Værten opløser det private navn og forbinder, fordi både navnet og ruten findes der. Containeren sender sin pakke til en privat adresse, som intet på brovejen kan nå, og anmodningen timer ud. At tilføje navnet til containerens hosts-fil ændrer intet, fordi adressen selv er utilgængelig fra der, hvor containeren sidder.
Nå værten inde fra containeren
En proces i containeren, der ringer til localhost, ringer til containeren. Docker Desktop udgiver host.docker.internal som et navn, der peger tilbage på maskinen, som kører motoren; Linux-motorer lader det være udefineret, medmindre tjenesten beder om det, og det er hvad mappingen nedenfor gør. Med det på plads rammer applikationen et navn og en port i stedet for den private adresse.
services:
app:
extra_hosts:
- "host.docker.internal:host-gateway"
environment:
INTERNAL_API_HOST: "host.docker.internal:8666"Tunnelen bliver på værtsiden af hoppet, og porten i den variabel er den, som proxyen vil lytte på. En container, der mister tunnelen, fejler nu på et enkelt kendt hop i stedet for at forsøge en rute, den aldrig havde.
Vælg, hvor tunnelen skal bo
Tre former er mulige for en Compose-tjeneste, der har brug for et privat API, og de adskiller sig ved, hvilken proces der ejer tunnelen. En VPN-klient kan køre inde i container-imaget, hvilket kræver, at en tunnel-enhed eksponeres, og at den netværksadministrationskompetence, der følger med, tildeles. Applikationen kan dele netværksnavnerum med en separat tunnel-container, så begge processer ser én stak og én rutetabel. Eller tunnelen kan blive på værten med en smal videresender fra værten ind i containeren.
De to første trækker profilfiler, genopkoblingsadfærd og resolverpolitik ind i projektet og gør hver tjeneste i filen afhængig af tunnelens helbred. Det er meget kobling for et enkelt API-kald. For en udviklingsstak, der læser ét internt endepunkt, er videresenderen på værten den mindste ændring, der stadig holder legitimationsoplysninger der, hvor platformsteamet administrerer dem.
Udgiv én smal vej på værten
Begynd med det, videresenderen arver: kør den som den konto, der ejer tunnelen, og dens udgående sockets overtager værtens ruter og værtens resolver. Én nginx location-blok dækker én vej.
server {
listen 8666;
location /search/ {
proxy_pass http://10.20.30.40:8090/;
proxy_set_header Host internal-api.example;
proxy_read_timeout 60s;
}
}Behandl adressen og porten som pladsholdere og indsæt det par, som API’et faktisk lytter på. Hver yderligere upstream fortjener sin egen location-blok, og hver blok bør kun tillade de veje, som denne tjeneste kalder, så proxyen ikke bliver en generel dør ind i det private netværk. Bind lytteren til bro-adressen for klienter, der kommer via host-gateway, til loopback kun når klienten deler værtens netværksnavnerum, og aldrig til 0.0.0.0. Vælg også en port, der stadig er fri: et nummer, der allerede er taget, efterlader proxyen uden at lytte, mens containeren fortsætter med at time ud, hvilket ikke kan skelnes fra den netværksfejl, du startede med.
Porte, navne og TLS-beslutningen
Navneopløsning deler sig på samme måde som routing. Containerens offentlige opslag går gennem motorens resolver, så et privat navn, der opløses på værten, opløses ikke inde i containeren. Proxyen er den komponent, der opløser det private navn, fordi den arver værtens resolver.
TLS er den beslutning, der udskydes og derefter forklarer den næste fejl. Hvis proxyen videresender bytes urørt, ser containeren API’ets eget certifikat og har brug for den interne CA i sit tillidslager. Hvis proxyen terminerer TLS, flytter den tillid til værten, og applikationen begynder at bygge links ud fra det host-header, den modtager. Vælg én ordning og anvend den på hver ressource, fordi en omdirigering udstedt af den anden peger på et værtsnavn, som containeren ikke kan opløse.
Verificér inde fra tjenesten
Send anmodningen fra containeren, ikke fra værten: en almindelig curl mod proxy-vejen, derefter applikationens eget sundhedstjek. Når proxyen svarer, men applikationen stadig fejler, sammenlign tre ting: den basis-URL, den bygger, enhver proxy-variabel i dens miljø og den CA, den stoler på. Alle ligger i containerens miljø og logfiler, og at rette en af dem lader VPN’en være i fred.
Skriv den valgte ordning i projektets README, mens den er frisk. Ellers vil den næste person, der rammer denne timeout, bruge den samme eftermiddag på at genopdage, at tunnelen bor på værten.