Compose-tenesta di går i tidsavbrot mot eit API som nettlesaren på same maskin opnar utan klage. Den skilnaden er leietråden: førespurnaden som verkar, forlèt ein vert med VPN-tunnel, og førespurnaden som heng, forlèt ein container med sin eigen nettverksstabel. Ingenting inne i containeren kjenner rutene til tunnelen, så den private destinasjonen blir verande utilgjengeleg uansett korleis namnet blir skrive. Løysinga er eit medvite hopp gjennom verten, ikkje ein smartare rutetabell.

Byrja med kvifor dei to vegane er ulike, og avgjer deretter kvar tunnelen skal bu.

Kvifor verten verkar og containeren ikkje

Å reise tunnelen gir verten eit grensesnitt, eit sett ruter og vanlegvis ein resolver-oppføring som VPN-et leverer. Ein container arvar ingenting av dette: han startar med eitt grensesnitt på brua til motoren og ei standardrute som peikar på den brua. Ruter installerte på verten er usynlege for alt som køyrer inne i det namnerommet.

Difor verkar symptoma inkonsistente og ikkje berre øydelagde. Verten løyser det private namnet og koplar til, fordi både namnet og ruta finst der. Containeren sender pakken sin til ei privat adresse som ingenting på bruvegen kan nå, og førespurnaden går i tidsavbrot. Å leggje namnet til i hosts-fila til containeren endrar ingenting, fordi adressa sjølv er utilgjengeleg frå der containeren sit.

Nå verten frå innsida av containeren

Ein prosess i containeren som ringjer localhost, ringjer containeren. Docker Desktop publiserer host.docker.internal som eit namn som peikar tilbake på maskina som køyrer motoren; Linux-motorar lèt det vere udefinert med mindre tenesta ber om det, og det er nettopp det mapperinga nedanfor gjer. Med det på plass rettar applikasjonen seg mot eit namn og ein port i staden for den private adressa.

services:
  app:
    extra_hosts:
      - "host.docker.internal:host-gateway"
    environment:
      INTERNAL_API_HOST: "host.docker.internal:8666"

Tunnelen blir på vertssida av hoppet, og porten i den variabelen er den proxyen vil lytte på. Ein container som misser tunnelen, feilar no på eitt kjent hopp i staden for å prøve ei rute han aldri hadde.

Vel kvar tunnelen bur

Tre former er mogelege for ei Compose-teneste som treng eit privat API, og dei skil seg i kva prosess som eig tunnelen. Ein VPN-klient kan køyre inne i containerbiletet, noko som krev at ein tunneleining blir eksponert og at nettverksadministrasjonsevna som følgjer med, blir gitt. Applikasjonen kan dele nettverksnamnerommet til ein separat tunnelcontainer, slik at båe prosessane ser éin stabel og éin rutetabell. Eller tunnelen kan bli på verten, med ein smal videresendar frå verten inn i containeren.

Dei to første dreg profilfiler, attoppkoplingåtferd og resolver-politikk inn i prosjektet, og gjer kvar teneste i fila avhengig av helsa til tunnelen. Det er mykje kopling for eitt API-kall. For ein utviklingsstabel som les eitt internt endepunkt, er videresendaren på vertssida den minste endringa som framleis held legitimasjonen der plattformteamet administrerer dei.

Publiser éin smal veg på verten

Byrja med det videresendaren arvar: køyr han som kontoen som eig tunnelen, og dei utgåande sokkane hans tek over rutene til verten og resolveren til verten. Éin nginx location-blokk dekkjer éin veg.

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 adressa og porten som plasshaldarar og set inn paret som API-et faktisk lyttar på. Kvar vidare upstream fortener si eiga location-blokk, og kvar blokk bør berre sleppe inn vegane denne tenesta kallar, slik at proxyen ikkje blir ei generell dør inn i det private nettverket. Bind lyttaren til bruadressa for klientar som kjem via host-gateway, til loopback berre når klienten deler nettverksnamnerommet til verten, og aldri til 0.0.0.0. Vel òg ein port som framleis er ledig: eit nummer som alt er teke, lèt proxyen stå utan å lytte medan containeren held fram med å gå i tidsavbrot, noko som ikkje kan skiljast frå nettverksfeilen du byrja med.

Portar, namn og TLS-avgjerda

Namneoppslag deler seg på same måte som ruting. Dei offentlege oppslaga til containeren går gjennom resolveren til motoren, så eit privat namn som blir løyst på verten, blir ikkje løyst inne i containeren. Proxyen er komponenten som løyser det private namnet, fordi han arvar resolveren til verten.

TLS er avgjerda som blir utsett og deretter forklarer den neste feilen. Viss proxyen videresendar bytes urørte, ser containeren API-et sitt eige sertifikat og treng den interne CA-en i tillitslageret sitt. Viss proxyen terminerer TLS, flyttar den tillita til verten, og applikasjonen byrjar å byggje lenkjer frå host-headeren han tek imot. Vel éi ordning og bruk ho på kvar ressurs, fordi ei omdirigering frå den andre peikar på eit vertsnamn containeren ikkje kan løyse.

Stadfest frå innsida av tenesta

Send førespurnaden frå containeren, ikkje frå verten: ein vanleg curl mot proxyvegen, deretter helsesjekken til applikasjonen sjølv. Når proxyen svarar men applikasjonen framleis feilar, samanlikn tre ting: basis-URL-en han byggjer, kva som helst proxyvariabel i miljøet hans og CA-en han stolar på. Alle ligg i miljøet og loggane til containeren, og å rette éin av dei lèt VPN-et vere i fred.

Skriv den valde ordninga i README til prosjektet medan ho er fersk. Elles vil neste person som treff denne tidsavbrotet bruke same ettermiddag på å oppdage på nytt at tunnelen bur på verten.

Relaterte artiklar