Containern når inte API:t som bara finns via VPN? Proxya det på värden
Tunneln lever på värden, så containern har ingen rutt till den privata adressen. Publicera en smal omvänd proxy och anropa den som host.docker.internal.
Din Compose-tjänst får timeout mot ett API som webbläsaren på samma maskin öppnar utan klagomål. Den skillnaden är ledtråden: begäran som fungerar lämnar en värd med VPN-tunnel, och begäran som hänger sig lämnar en container med egen nätverksstack. Ingenting inne i containern känner till tunnelns rutter, så det privata målet förblir onåbart hur namnet än skrivs. Lösningen är ett medvetet hopp genom värden, inte en smartare routingtabell.
Börja med varför de två vägarna skiljer sig, och bestäm sedan var tunneln ska bo.
Varför värden fungerar och containern inte
Att resa tunneln ger värden ett gränssnitt, en uppsättning rutter och vanligtvis en resolver-post som VPN:et levererar. En container ärver ingenting av detta: den startar med ett gränssnitt på motorns bro och en standardrutt som pekar på den bron. Rutter installerade på värden är osynliga för allt som körs inne i det namnutrymmet.
Därför verkar symptomen inkonsekventa och inte bara trasiga. Värden löser det privata namnet och ansluter, eftersom både namnet och rutten finns där. Containern skickar sitt paket till en privat adress som ingenting på brovägen kan nå, och begäran får timeout. Att lägga till namnet i containerns hosts-fil ändrar ingenting, eftersom adressen själv är onåbar från där containern sitter.
Nå värden inifrån containern
En process i containern som ringer localhost ringer containern. Docker Desktop publicerar host.docker.internal som ett namn som pekar tillbaka på maskinen som kör motorn; Linux-motorer lämnar det odefinierat om inte tjänsten ber om det, och det är precis vad mappningen nedan gör. Med det på plats riktar applikationen in sig på ett namn och en port i stället för den privata adressen.
services:
app:
extra_hosts:
- "host.docker.internal:host-gateway"
environment:
INTERNAL_API_HOST: "host.docker.internal:8666"Tunneln stannar på värdsidan av hoppet, och porten i den variabeln är den som proxyn kommer att lyssna på. En container som förlorar tunneln misslyckas nu på ett enda känt hopp i stället för att försöka en rutt den aldrig hade.
Välj var tunneln bor
Tre former är möjliga för en Compose-tjänst som behöver ett privat API, och de skiljer sig i vilken process som äger tunneln. En VPN-klient kan köra inne i containeravbildningen, vilket kräver att en tunnelenhet exponeras och att nätverksadministrationsförmågan som följer med ges. Applikationen kan dela nätverksnamnutrymmet med en separat tunnelcontainer, så att båda processerna ser en stack och en routingtabell. Eller så kan tunneln stanna på värden, med en smal vidarebefordrare från värden in i containern.
De två första drar in profilfiler, återanslutningsbeteende och resolverpolicy i projektet och gör varje tjänst i filen beroende av tunnelns hälsa. Det är mycket koppling för ett enda API-anrop. För en utvecklingsstack som läser en enda intern slutpunkt är vidarebefordraren på värdsidan den minsta ändringen som ändå behåller uppgifterna där plattformsteamet hanterar dem.
Publicera en enda smal väg på värden
Börja med det vidarebefordraren ärver: kör den som kontot som äger tunneln, och dess utgående sockets tar över värdens rutter och värdens resolver. Ett nginx location-block täcker en väg.
server {
listen 8666;
location /search/ {
proxy_pass http://10.20.30.40:8090/;
proxy_set_header Host internal-api.example;
proxy_read_timeout 60s;
}
}Behandla adressen och porten som platshållare och sätt in paret som API:et faktiskt lyssnar på. Varje ytterligare upstream förtjänar sitt eget location-block, och varje block bör bara släppa in de vägar som den här tjänsten anropar, så att proxyn inte blir en allmän dörr in i det privata nätverket. Bind lyssnaren till bro-adressen för klienter som kommer via host-gateway, till loopback bara när klienten delar värdens nätverksnamnutrymme, och aldrig till 0.0.0.0. Välj också en port som fortfarande är ledig: ett nummer som redan är taget lämnar proxyn utan att lyssna medan containern fortsätter att få timeout, vilket inte går att skilja från det nätverksfel du började med.
Portar, namn och TLS-beslutet
Namnuppslag delar sig på samma sätt som routning. Containerns offentliga uppslag går genom motorns resolver, så ett privat namn som löses på värden löses inte inne i containern. Proxyn är komponenten som löser det privata namnet, eftersom den ärver värdens resolver.
TLS är beslutet som skjuts upp och sedan förklarar nästa fel. Om proxyn vidarebefordrar byte orörda ser containern API:ets eget certifikat och behöver den interna CA:n i sitt förtroendelager. Om proxyn terminerar TLS flyttar det förtroendet till värden, och applikationen börjar bygga länkar från host-headern den tar emot. Välj en ordning och tillämpa den på varje resurs, eftersom en omdirigering från den andra pekar på ett värdnamn som containern inte kan lösa.
Verifiera inifrån tjänsten
Skicka begäran från containern, inte från värden: en vanlig curl mot proxyvägen, sedan applikationens egen hälsokontroll. När proxyn svarar men applikationen fortfarande misslyckas, jämför tre saker: bas-URL:en den bygger, vilken proxyvariabel som helst i dess miljö och den CA den litar på. Alla finns i containerns miljö och loggar, och att åtgärda någon av dem lämnar VPN:et i fred.
Skriv den valda ordningen i projektets README medan den är färsk. Annars kommer nästa person som råkar ut för denna timeout att tillbringa samma eftermiddag med att återupptäcka att tunneln bor på värden.