Eén host, twee workloads en een vereiste die ze scheidt: een downloadclient die via een commerciële VPN naar buiten moet, en een beheerinterface die de verbinding van de host moet blijven gebruiken. De VPN-client op de host installeren voldoet meteen niet aan de vereiste, omdat beide workloads dan één uitgang delen. Het patroon dat wél werkt, is de tunnel in zijn eigen container onderbrengen en alleen de workloads die hem nodig hebben lid te laten worden van de netwerknaamruimte van die container. Al het andere houdt het gewone Docker-pad, en de details die volgen zijn gevolgen van wie de naamruimte bezit.

Waarom een gedeelde naamruimte de regels verandert

Een container die lid wordt van de naamruimte van een andere, krijgt geen eigen netwerkstack. Hij ziet dezelfde interfaces, dezelfde routetabel en dezelfde loopback als de container waarbij hij zich voegde, en precies daarom is het patroon nuttig: de workload lost op en verbindt normaal, en de tunnel eronder vangt het verkeer op zonder dat de toepassing het weet. De prijs is dat elke netwerkinstelling nu één eigenaar heeft, en de toetredende container is dat niet.

Die eigendomsregel beantwoordt de meeste configuratievragen voordat ze gesteld worden. Als een instelling in de netwerkstack leeft, hoort hij bij de sidecar. Als hij het proces beschrijft, blijft hij bij de workload.

Loopback is het deel dat mensen verrast. Binnen de toetredende container wordt localhost opgelost naar de loopback van de sidecar, niet naar een eigen privé-adres, dus een dienst die zich aan 127.0.0.1 bindt en isolatie verwacht, deelt dat adres nu met de tunnelcontainer.

Publiceer poorten op de container die de naamruimte bezit

De poorttoewijzing hoort bij de eigenaar van de naamruimte, ook wanneer het luisterende proces in de andere container draait. Declareer de toewijzing op de sidecar, en laat de workload zijn eigen procesconfiguratie ongemoeid. Een toewijzing op de toetredende dienst kan niet van kracht worden, of de engine hem nu weigert of stil negeert afhankelijk van hoe de container wordt gestart, en daarom verdwijnt een interface die een moment geleden bereikbaar was zodra het patroon wordt toegepast.

services:
  gluetun:
    image: qmcgaw/gluetun
    cap_add: [NET_ADMIN]
    ports: ["8080:8080"]
  client-vpn:
    image: example/client
    network_mode: "service:gluetun"
  client-direct:
    image: example/client
    ports: ["8081:8080"]

Lees dat blok als drie beslissingen in plaats van drie diensten. De sidecar bezit de tunnel en de gepubliceerde poort; de toetredende client declareert helemaal geen netwerk; de directe client houdt een eigen toewijzing op het standaardnetwerk. Het vermogen NET_ADMIN is wat de sidecar in staat stelt interfaces te maken en routes te wijzigen, en dat is de reden dat deze container meer rechten nodig heeft dan de workloads die hij bedient.

De dienst die direct blijft, houdt zijn eigen netwerk

De workload die niet door de tunnel mag, houdt de standaardbrug of een eigen door de gebruiker gedefinieerd netwerk, met zijn eigen gepubliceerde poort en zijn eigen uitgang. Het is verleidelijk hem aan het netwerk van de sidecar te koppelen zodat de twee containers op naam kunnen praten, maar die ene stap verplaatst zijn verkeer stil de tunnel in. Als ze elkaar moeten bereiken, bouw dan een apart door de gebruiker gedefinieerd netwerk, koppel beide eraan en laat de sidecar de enige weg naar buiten zijn.

Houd de twee vragen gescheiden: welke containers elkaar kunnen bereiken, en welke waar naar buiten gaat. Ze samenvoegen is de meest voorkomende manier waarop dit ontwerp weer een VPN voor de hele host wordt.

Een foutmatrix voor het eerste uur

De meeste eerste pogingen mislukken op een van vier manieren, en elk heeft een andere oorzaak. Controleer ze in deze volgorde, want de eerste twee verklaren bijna elk rapport.

SymptomLikely cause
Web UI unreachable after the changePort mapping declared on the joining container instead of the sidecar
Both containers show the provider's exit addressThe direct service was attached to the sidecar network
Internal names stop resolvingResolver settings live on the host, not in the shared namespace
Health check fails but the app worksThe check probes localhost, which now means the sidecar

De vierde rij is degene die mensen ten onrechte als een applicatiefout diagnosticeren. Een controle die tegen de eigen loopback van de workload is geschreven, test nu de tunnelcontainer, dus hij mislukt of meldt een volledig verkeerde dienst.

Wanneer één hostnaam de tunnel nodig heeft

Soms is een volledige tunnel te veel: één interne naam moet via een bedrijfs-VPN, terwijl een lokale socket of weergaveverbinding blijft werken. Een volledige tunnel in de container breekt dat pad en alles wat aan de host is geadresseerd, dus routeer alleen het prefix dat het nodig heeft. Een split-routing-wrapper rond de client doet dat, stuurt de genoemde host door de tunnel en laat de vorige route voor al het andere ongemoeid.

Kies dit wanneer je maar één dienst hoeft te bereiken en niet probeert al het verkeer van de container te verplaatsen. Het is een ander gereedschap dan de sidecar en het beantwoordt een andere vraag.

Verifieer, en maak het dan bestand tegen een herstart

Vraag elke container van welk adres hij lijkt te komen. De getunnelde zou het adres van de provider moeten afdrukken en de directe de uitgang van de host. Identieke antwoorden betekenen dat de directe dienst de verkeerde naamruimte heeft geërfd of dat een VPN op hostniveau nog steeds alles opvangt, en die twee correcties zijn verschillend. Voer de controle opnieuw uit na elke compose-wijziging, want één gekopieerd dienstblok is genoeg om het probleem terug te brengen.

Drie dingen gaan later vaak stuk. DNS volgt de eigenaar van de naamruimte, dus instellingen voor resolver en zoekdomein horen bij de sidecar en niet bij de host. Een VPN met port forwarding verandert zijn luisterpoort bij opnieuw verbinden, dus de doorgestuurde poort van de provider en de luisterpoort aan de containerkant moeten terug worden geschreven in de clientconfiguratie of de poorttoewijzing, meestal door een kleine updater die de API van de provider leest. En elke controle die tegen localhost is geschreven, vraagt nu de tunnelcontainer in plaats van de workload.

Schrijf het patroon op, inclusief welke container de naamruimte bezit en welke poorten erbij horen. De volgende persoon voegt een dienst toe, kopieert het verkeerde blok en reproduceert de eerste fout uit dit artikel.

Gerelateerde artikelen