Kontejneri odgovaraju na kancelarijskom LAN-u, a zatim prestanu odgovarati u trenutku kada se poveže korporativni VPN. Ništa u kontejneru nije promijenjeno: nema restarta, nema ažuriranja slike, nema izmjene konfiguracije. Promijenila se tabela rutiranja hosta, gdje ruta koju je tunel dodao sada pokriva adresu koju je Docker dodijelio. Prije nego što uredite podmrežu ili zatražite izuzetak od VPN-a, stavite oba plana adresa jedan uz drugi, jer popravke koštaju vrlo različito vrijeme.

Pročitajte rutu prije nego što promijenite konfiguraciju

Počnite s mrežom koju je Docker zaista napravio. IPAM blok je plan adresa, a podmreža je red koji je važan:

docker network inspect project_default --format '{{json .IPAM.Config}}'
# [{"Subnet":"172.18.0.0/16","Gateway":"172.18.0.1"}]

Compose po defaultu dodjeljuje /16 svakom novom projektu, pa dvije usluge mogu stati unutar raspona od 65,536 adresa. Ta širina je razlog zašto su preklapanja česta: slučajno odabran /16 dovoljno je velik da proguta stranicu do koje dolazite kroz tunel, i niko to ne primijeti dok se tunel ne podigne.

Zatim uporedite odabir rute za jednu adresu kontejnera, jednom s isključenim tunelom i jednom s uključenim:

ip route get 172.18.0.7
# 172.18.0.7 dev br-3f2a9c src 172.18.0.1

Dva oblika odgovora vode na različita mjesta. Ako izlaz navodi tun0, wg0 ili drugi tunelski uređaj, VPN prefiks je barem jednako specifičan kao ruta mosta i paket nikada ne stiže do kontejnera. Ako se i dalje navodi most, host može doći do kontejnera, a vaša greška je filtriranje, DNS ili povratna putanja koja pada samo u jednom smjeru.

Zašto je sudar /16 lako pogoditi

Docker uzima mreže mosta iz privatnih bazena, a zadani bazen dolazi iz bloka 172.16.0.0/12 u isječcima od /16. Korporativne mreže često koriste isti privatni prostor, a VPN za daljinski pristup gura te prefikse na svakog klijenta koji se poveže. Kada obje strane vjeruju da posjeduju 172.18.0.0/16, jedna tabela rutiranja drži dvije proturječne tvrdnje.

Dužina prefiksa odlučuje pobjednika, a ne redoslijed kojim se rute pojavljuju. Tunel koji gura 10.0.0.0/8 ne pobjeđuje rutu mosta 172.18.0.0/16, jer je /8 manje specifičan. Tunel koji gura 172.18.0.0/16, ili 172.18.5.0/24 unutar njega, pobjeđuje. Zato jedan laptop radi na kancelarijskoj mreži, a pada na hotelskom Wi-Fi-ju s istim VPN-om: klijent prima različite prefikse.

Ista tabela upravlja i suprotnim smjerom. Kontejner koji treba interni host na 10.8.4.20 šalje paket na svoj gateway mosta, a host ga zatim rutira u tunel. Ta putanja obično radi jer host obavlja NAT, ali pada kada korporativna strana prihvaća samo VPN adresu laptopa ili kada filtriranje povratne putanje odbaci asimetrični odgovor.

Uporedite tri popravke

Postoje samo tri izlaza, i razlikuju se po tome ko ih mora odobriti i šta se kvari dok primjenjujete jedan od njih.

RepairWho owns itWhat it costs
Renumber the container networkYouRecreates the network, restarts services, invalidates literal addresses in configs and scripts
Exclude your range from the tunnelNetwork teamChanges what every laptop sees, needs a change request and a client profile update
Reach the service through a published portYou and the clientOne port only, no direct container-to-container routing across the tunnel

Prenumeracija je jedina popravka koju možete završiti bez tiketa, zato se većina tekstova tu zaustavlja. Jeftina je na mladom projektu i skupa kada alat za migraciju ili sačuvani string veze pokaže na doslovnu adresu. Prebrojite te reference prije nego što uredite YAML, ne poslije.

Izuzetak od tunela najčišći je odgovor kada se preklapanje nalazi u rasponu koji vaša kompanija zaista posjeduje. Ujedno je i najsporiji, i beskorisan je za izvođača koji ne može promijeniti profil klijenta. Objavljeni port ili mali obrnuti proxy izbjegava raspravu: klijent razgovara s adresom koju tunel već ispravno rutira, i samo taj port mora biti dostupan.

Pričvrstite raspon namjerno

Za jedan projekt deklarišite podmrežu u compose datoteci da projekt prestane crpiti iz zajedničkog bazena:

networks:
  default:
    ipam:
      config:
        - subnet: 10.201.7.0/24

Uzmite taj raspon iz registra koji vaš tim vodi, a ne iz primjera koji ste našli pretražujući. Provjerite ga prema prefiksima koje VPN gura, kućnim LAN-ovima s kojih ljudi rade i drugim kontejnerskim mrežama na istom hostu. Zatim planirajte ponovno stvaranje, jer postojeća mreža zadržava staru podmrežu: docker compose down, zatim up -d. docker network rm odbija dok su krajnje točke priključene, i svaki ipv4_address unos u datoteci mora pasti unutar novog raspona.

Za mreže koje Docker stvara sam, postavite bazen daemona u /etc/docker/daemon.json:

{
  "default-address-pools": [
    { "base": "10.201.0.0/16", "size": 24 },
    { "base": "10.202.0.0/16", "size": 24 }
  ]
}

Bazen se primjenjuje na mreže stvorene nakon ponovnog pokretanja daemona, a mostovi koji već postoje zadržavaju svoje adrese. To je zgodno i lako se zaboravlja, pa tretirajte stari projekt kao da se još preklapa dok neko ne ponovno stvori njegovu mrežu. Dockerova dokumentacija o umrežavanju mehanizma opisuje pravila dodjele ako trebate braniti bazen na pregledu.

Linux most i Docker Desktop padaju različito

Na Linux hostu kontejneri sjede na mostovima u imenskom prostoru hosta. Jedna tabela odlučuje o svemu, pa je gore navedeno poređenje cijela priča: pročitajte rutu mosta, pročitajte rutu tunela i vidite koja pobjeđuje za stvarnu adresu kontejnera.

Docker Desktop stavlja kontejnere iza VM-a s vlastitim NAT-om. Host uopće nema rutu do adrese kontejnera; do usluge dolazi kroz objavljeni port, obično vezan na 127.0.0.1. VPN klijent zato može pokvariti uslugu bez ikakvog preklapanja podmreža, bilo instaliranjem rute za interni raspon VM-a, bilo blokiranjem loopback prometa dok je tunel povezan. Ako ip route get na hostu prijavi da nema rute do adrese kontejnera, to je očekivano, a ne greška.

Praktična posljedica je gdje prvo gledate. Na Linuxu počnite od tabele rutiranja. Na Desktopu počnite od objavljenog porta i pravila firewall-a VPN klijenta, pa provjerite sudara li se interna podmreža VM-a s nečim što tunel gura.

Provjerite s uključenim tunelom

Ponovno povežite VPN dvaput prije nego što to proglasite popravljenim, jer profil koji gura rute pri povezivanju i povlači ih pri odspajanju može izgledati ispravno nakon prvog pokušaja. Zatim pokrenite provjere koje klijent zaista izvodi:

  1. ip route get s hosta, koristeći stvarnu adresu kontejnera.
  2. Zahtjev iz drugog kontejnera, da dokažete da je sama usluga zdrava.
  3. curl -sv http://127.0.0.1:8080/ s klijenta s uključenim tunelom, zatim traceroute -n do adrese kontejnera s mašine na LAN-u.
  4. sysctl net.ipv4.conf.all.rp_filter ako zahtjev stigne do hosta ali odgovor nestane.

Na kraju, upišite odabrani raspon u isti registar iz kojeg ste ga uzeli, s datumom i projektom koji ga posjeduje. Sljedeće preklapanje doći će iz projekta koji niko nije dokumentovao, a jedina odbrana je da je raspon rezervisan namjerno, a ne izvučen slučajno.

Povezani članci