Konteineris nepasiekia tik per VPN pasiekiamo API? Proksuokite jį hoste
Tunelis gyvena hoste, todėl konteineris neturi maršruto į privatų adresą. Paskelbkite siaurą atvirkštinį proksį ir kvieskite jį kaip host.docker.internal.
Jūsų Compose paslauga pasiekia laiko limitą API, kurį tos pačios mašinos naršyklė atidaro be jokių nusiskundimų. Šis skirtumas ir yra užuomina: veikianti užklausa išeina iš hosto su VPN tuneliu, o stringanti užklausa – iš konteinerio su savo tinklo steku. Niekas konteinerio viduje nežino tunelio maršrutų, todėl privatus tikslas lieka nepasiekiamas, kad ir kaip būtų rašomas pavadinimas. Sprendimas – sąmoningas šuolis per hostą, o ne protingesnė maršrutų lentelė.
Pradėkite nuo to, kodėl du keliai skiriasi, tada nuspręskite, kur tunelis turėtų gyventi.
Kodėl hostas veikia, o konteineris ne
Tunelio įkėlimas suteikia hostui sąsają, maršrutų rinkinį ir paprastai VPN tiekiamą resolverio įrašą. Konteineris nieko iš to nepaveldi: jis pradedamas su viena sąsaja ant variklio tilto ir numatytuoju maršrutu, kuris rodo į tą tiltą. Hoste įdiegti maršrutai yra nematomi viskam, kas veikia toje vardų erdvėje.
Todėl simptomai atrodo nenuoseklūs, o ne tiesiog sulūžę. Hostas išsprendžia privatų vardą ir prisijungia, nes ten yra ir vardas, ir maršrutas. Konteineris siunčia savo paketą į privatų adresą, kurio niekas tilto kelyje negali pasiekti, ir užklausa pasiekia laiko limitą. Vardo įtraukimas į konteinerio hosts failą nieko nekeičia, nes pats adresas nepasiekiamas iš ten, kur yra konteineris.
Pasiekite hostą iš konteinerio vidaus
Procesas konteineryje, kuris skambina localhost, skambina konteineriui. Docker Desktop skelbia host.docker.internal kaip vardą, kuris rodo atgal į mašiną, vykdančią variklį; Linux varikliai palieka jį neapibrėžtą, nebent paslauga paprašo, ir būtent tai daro žemiau esantis susiejimas. Su tuo programa taikosi į vardą ir prievadą, o ne į privatų adresą.
services:
app:
extra_hosts:
- "host.docker.internal:host-gateway"
environment:
INTERNAL_API_HOST: "host.docker.internal:8666"Tunelis lieka hosto pusėje šio šuolio, o to kintamojo prievadas yra tas, kuriame klausysis proksis. Konteineris, kuris praranda tunelį, dabar nepavyksta viename žinomame šuolyje, o ne bando maršrutą, kurio niekada neturėjo.
Pasirinkite, kur gyvena tunelis
Compose paslaugai, kuriai reikia privataus API, galimi trys pavidalai, ir jie skiriasi tuo, kuris procesas valdo tunelį. VPN klientas gali veikti konteinerio atvaizde, o tam reikia atidengti tunelio įrenginį ir suteikti su tuo susijusį tinklo administravimo gebėjimą. Programa gali dalytis atskiro tunelio konteinerio tinklo vardų erdve, todėl abu procesai mato vieną steką ir vieną maršrutų lentelę. Arba tunelis gali likti hoste, su siauru peradresuotoju iš hosto į konteinerį.
Pirmieji du įtraukia profilio failus, prisijungimo iš naujo elgseną ir resolverio politiką į projektą bei padaro kiekvieną failo paslaugą priklausomą nuo tunelio būklės. Tai per daug susiejimo vienam API kvietimui. Kūrimo stekui, kuris skaito vieną vidinį galinį tašką, hosto pusės peradresuotojas yra mažiausias pakeitimas, kuris vis tiek laiko kredencialus ten, kur juos valdo platformos komanda.
Paskelbkite vieną siaurą kelią hoste
Pradėkite nuo to, ką paveldi peradresuotojas: paleiskite jį su paskyra, kuri valdo tunelį, ir jo išeinantys lizdai perims hosto maršrutus bei hosto resolverį. Vienas nginx location blokas apima vieną kelią.
server {
listen 8666;
location /search/ {
proxy_pass http://10.20.30.40:8090/;
proxy_set_header Host internal-api.example;
proxy_read_timeout 60s;
}
}Traktuokite adresą ir prievadą kaip pakaitinius ir įrašykite porą, kurioje API iš tikrųjų klausosi. Kiekvienas tolesnis upstream nusipelno savo location bloko, o kiekvienas blokas turėtų įleisti tik tuos kelius, kuriuos kviečia ši paslauga, kad proksis netaptų bendromis durimis į privatų tinklą. Pririškite klausytoją prie tilto adreso klientams, ateinantiems per host-gateway, prie loopback tik kai klientas dalijasi hosto tinklo vardų erdve, ir niekada prie 0.0.0.0. Pasirinkite ir prievadą, kuris dar laisvas: jau užimtas numeris palieka proksį neklausantį, kol konteineris toliau stringa, ko negalima atskirti nuo tinklo gedimo, su kuriuo pradėjote.
Prievadai, vardai ir TLS sprendimas
Vardų sprendimas skyla taip pat kaip maršrutizavimas. Konteinerio viešos paieškos eina per variklio resolverį, todėl privatus vardas, kuris išsprendžiamas hoste, nebus išspręstas konteinerio viduje. Proksis yra komponentas, kuris išsprendžia privatų vardą, nes paveldi hosto resolverį.
TLS yra sprendimas, kuris atidedamas ir tada paaiškina kitą gedimą. Jei proksis persiunčia baitus nepaliestus, konteineris mato paties API sertifikatą ir jam reikia vidinės CA savo pasitikėjimo saugykloje. Jei proksis užbaigia TLS, tas pasitikėjimas persikelia į hostą ir programa pradeda kurti nuorodas iš gaunamos host antraštės. Pasirinkite vieną išdėstymą ir taikykite jį kiekvienam ištekliui, nes kito išduotas peradresavimas rodo į hosto vardą, kurio konteineris negali išspręsti.
Patikrinkite iš paslaugos vidaus
Siųskite užklausą iš konteinerio, o ne iš hosto: paprastas curl į proksio kelią, tada pačios programos būklės patikra. Kai proksis atsako, bet programa vis tiek nepavyksta, palyginkite tris dalykus: bazinį URL, kurį ji kuria, bet kurį proksio kintamąjį jos aplinkoje ir CA, kuria ji pasitiki. Visi jie yra konteinerio aplinkoje ir žurnaluose, o bet kurio sutaisymas palieka VPN ramybėje.
Įrašykite pasirinktą išdėstymą į projekto README, kol jis dar šviežias. Priešingu atveju kitas žmogus, susidursiantis su šiuo laiko limitu, praleis tą patį popietį iš naujo atrasdamas, kad tunelis gyvena hoste.