Containere svarer på kontorets LAN og holder så op med at svare i det øjeblik, virksomhedens VPN kobler til. Intet i containeren er ændret: ingen genstart, ingen imageopdatering, ingen konfigurationsændring. Det, der er ændret, er værtens routingtabel, hvor en rute, som tunnelen tilføjede, nu dækker den adresse, Docker uddelte. Før du redigerer et undernet eller beder om en VPN-undtagelse, skal du stille de to adresseplaner side om side, fordi reparationerne koster meget forskellige mængder tid.

Læs ruten, før du ændrer konfigurationen

Start med det netværk, Docker faktisk byggede. IPAM-blokken er adresseplanen, og undernettet er den linje, der betyder noget:

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

Compose tildeler som standard et /16 til hvert nyt projekt, så to tjenester kan ligge inden for et område på 65,536 adresser. Netop den bredde er grunden til, at overlapninger er almindelige: et tilfældigt valgt /16 er stort nok til at sluge et sted, du når gennem tunnelen, og ingen opdager det, før tunnelen kommer op.

Sammenlign derefter rutevalget for én containeradresse, én gang med tunnelen nede og én gang med den oppe:

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

To former for svar fører til forskellige steder. Hvis outputtet nævner tun0, wg0 eller en anden tunneleenhed, er et VPN-præfiks mindst lige så specifikt som bro-ruten, og pakken når aldrig containeren. Hvis det stadig nævner broen, kan værten nå containeren, og din fejl er filtrering, DNS eller en returvej, der kun fejler i én retning.

Hvorfor en /16-kollision er let at ramme

Docker trækker bro-netværk fra de private pools, og standardpuljen kommer fra blokken 172.16.0.0/12 i /16-skiver. Virksomhedsnetværk bruger ofte samme private rum, og en fjernadgangs-VPN skubber disse præfikser til hver klient, der kobler til. Når begge sider mener, de ejer 172.18.0.0/16, holder én routingtabel to modstridende krav.

Præfiksets længde afgør vinderen, ikke den rækkefølge, ruterne vises i. En tunnel, der skubber 10.0.0.0/8 slår ikke en bro-rute 172.18.0.0/16, fordi /8 er mindre specifik. En tunnel, der skubber 172.18.0.0/16, eller 172.18.5.0/24 inde i den, gør. Derfor virker én bærbar på kontorets netværk og fejler på hotel-Wi-Fi med samme VPN: klienten modtager forskellige præfikser.

Den samme tabel styrer den anden retning. En container, der har brug for en intern vært på 10.8.4.20 sender pakken til sin bro-gateway, og værten ruter den derefter ind i tunnelen. Den vej virker normalt, fordi værten udfører NAT, men den fejler, når virksomhedssiden kun accepterer den bærbares VPN-adresse, eller når reverse-path-filtrering dropper det asymmetriske svar.

Sammenlign de tre reparationer

Der er kun tre veje ud, og de adskiller sig i, hvem der skal godkende dem, og hvad der går i stykker, mens du anvender en.

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

Omnummerering er den eneste reparation, du kan afslutte uden en sag, og derfor stopper de fleste skriverier der. Den er billig på et ungt projekt og dyr, når et migreringsværktøj eller en gemt forbindelsesstreng peger på en bogstavelig adresse. Tæl de referencer, før du redigerer YAML, ikke efter.

En undtagelse fra tunnelen er det reneste svar, når overlapningen ligger i et område, som din virksomhed reelt ejer. Den er også den langsomste, og den er ubrugelig for en underleverandør, der ikke kan ændre klientprofilen. En publiceret port eller en lille reverse proxy undgår diskussionen: klienten taler med en adresse, som tunnelen allerede ruter korrekt, og kun den port skal være tilgængelig.

Fastlås et område med vilje

For et enkelt projekt skal du deklarere undernettet i compose-filen, så projektet holder op med at trække fra den fælles pulje:

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

Tag det område fra et register, som dit team fører, ikke fra et eksempel, du fandt under søgning. Kontroller det mod de præfikser, VPN'en skubber, de hjemme-LAN, folk arbejder fra, og de andre containernetværk på samme vært. Planlæg derefter genskabelsen, fordi et eksisterende netværk beholder sit gamle undernet: docker compose down, derefter up -d. docker network rm afviser, mens endepunkter er tilsluttet, og enhver ipv4_address post i filen skal ligge inden for det nye område.

For netværk, som Docker opretter selv, skal du sætte en daemon-pulje i /etc/docker/daemon.json:

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

Puljen gælder for netværk, der oprettes, efter daemonen genstarter, og broer, der allerede findes, beholder deres adresser. Det er bekvemt og let at glemme, så behandl et gammelt projekt som stadig overlappende, indtil nogen genskaber dets netværk. Dockers netværksdokumentation for motoren beskriver tildelingsreglerne, hvis du skal forsvare puljen i en gennemgang.

Linux-bro og Docker Desktop fejler forskelligt

På en Linux-vært sidder containere på broer i værtens navnerum. Én tabel afgør alt, så sammenligningen ovenfor er hele historien: læs bro-ruten, læs tunnelruten, og se, hvilken der vinder for en rigtig containeradresse.

Docker Desktop placerer containere bag en VM med sin egen NAT. Værten har slet ingen rute til containeradressen; den når tjenesten gennem en publiceret port, normalt bundet til 127.0.0.1. En VPN-klient kan derfor ødelægge tjenesten uden nogen undernets-overlapning, enten ved at installere en rute til VM'ens interne område eller ved at blokere loopback-trafik, mens tunnelen er tilsluttet. Hvis ip route get på værten rapporterer ingen rute til containeradressen, er det forventet og ikke fejlen.

Den praktiske konsekvens er, hvor du kigger først. På Linux starter du ved routingtabellen. På Desktop starter du ved den publicerede port og VPN-klientens firewallregler og tjekker derefter, om VM'ens interne undernet kolliderer med noget, tunnelen skubber.

Bekræft med tunnelen oppe

Genopkobl VPN'en to gange, før du kalder det løst, fordi en profil, der skubber ruter ved forbindelse og trækker dem tilbage ved afbrydelse, kan se korrekt ud efter første forsøg. Kør derefter de kontroller, klienten faktisk kører:

  1. ip route get fra værten med containerens rigtige adresse.
  2. En anmodning fra en anden container for at bevise, at tjenesten selv er sund.
  3. curl -sv http://127.0.0.1:8080/ fra klienten med tunnelen oppe, derefter traceroute -n til containeradressen fra en maskine på LAN'et.
  4. sysctl net.ipv4.conf.all.rp_filter hvis anmodningen når værten, men svaret forsvinder.

Skriv til sidst det valgte område ind i det samme register, du brugte til at vælge det, med datoen og det projekt, der ejer det. Den næste overlapning kommer fra et projekt, ingen dokumenterede, og det eneste forsvar er, at området blev reserveret med vilje i stedet for trukket tilfældigt.

Relaterede artikler