Docker: skieruj jeden kontener przez VPN, a drugi zostaw bezpośrednio
Daj tunelowi własny kontener, pozwól tylko usługom, które go potrzebują, współdzielić tę przestrzeń nazw, a potem uwzględnij to, co idzie za właścicielem: porty, localhost, DNS.
Jeden host, dwa obciążenia i wymaganie, które je rozdziela: klient pobierania, który musi wychodzić przez komercyjny VPN, oraz interfejs zarządzania, który musi nadal korzystać z połączenia hosta. Zainstalowanie klienta VPN na hoście od razu łamie wymaganie, ponieważ oba obciążenia dzielą wtedy jedno wyjście. Wzorzec, który naprawdę działa, polega na przeniesieniu tunelu do własnego kontenera i pozwoleniu tylko tym obciążeniom, które go potrzebują, dołączyć do przestrzeni nazw sieci tego kontenera. Wszystko inne zachowuje zwykłą ścieżkę Dockera, a szczegóły, które następują, są konsekwencją tego, kto posiada przestrzeń nazw.
Dlaczego współdzielona przestrzeń nazw zmienia zasady
Kontener, który dołącza do przestrzeni nazw innego, nie dostaje własnego stosu sieciowego. Widzi te same interfejsy, tę samą tablicę routingu i ten sam loopback co kontener, do którego dołączył, i właśnie dlatego wzorzec jest użyteczny: obciążenie rozwiązuje i łączy się normalnie, a tunel pod nim przechwytuje ruch, nie wiedząc o tym aplikacji. Kosztem jest to, że każde ustawienie sieciowe ma teraz jednego właściciela, a dołączający kontener nim nie jest.
Ta zasada własności odpowiada na większość pytań konfiguracyjnych, zanim zostaną zadane. Jeśli ustawienie żyje w stosie sieciowym, należy do kontenera pomocniczego. Jeśli opisuje proces, zostaje przy obciążeniu.
Loopback to ta część, która zaskakuje ludzi. Wewnątrz dołączającego kontenera localhost rozwiązuje się na loopback kontenera pomocniczego, a nie na własny prywatny, więc usługa, która wiąże się z 127.0.0.1, oczekując izolacji, dzieli teraz ten adres z kontenerem tunelu.
Publikuj porty na kontenerze, który posiada przestrzeń nazw
Mapowanie portów należy do właściciela przestrzeni nazw, nawet gdy proces nasłuchujący działa w drugim kontenerze. Zadeklaruj mapowanie na kontenerze pomocniczym, a obciążenie niech zachowa własną konfigurację procesu nietkniętą. Mapowanie na dołączającej usłudze nie może wejść w życie, niezależnie od tego, czy silnik je odrzuci, czy po cichu zignoruje w zależności od tego, jak uruchomiony jest kontener, i dlatego interfejs, który był osiągalny chwilę temu, znika, gdy tylko wzorzec zostanie zastosowany.
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"]Czytaj ten blok jako trzy decyzje, a nie trzy usługi. Kontener pomocniczy posiada tunel i opublikowany port; dołączający klient nie deklaruje żadnej sieci; klient bezpośredni zachowuje własne mapowanie w sieci domyślnej. Zdolność NET_ADMIN jest tym, co pozwala kontenerowi pomocniczemu tworzyć interfejsy i zmieniać trasy, i to jest powód, dla którego ten kontener potrzebuje więcej uprawnień niż obsługiwane przez niego obciążenia.
Usługa, która pozostaje bezpośrednia, zachowuje własną sieć
Obciążenie, które nie może przechodzić przez tunel, zachowuje domyślny most lub własną sieć zdefiniowaną przez użytkownika, z własnym opublikowanym portem i własnym wyjściem. Kusi, by podłączyć je do sieci kontenera pomocniczego, aby dwa kontenery mogły rozmawiać po nazwie, ale ten jeden krok po cichu przenosi jego ruch do tunelu. Jeśli muszą się nawzajem osiągać, zbuduj osobną sieć zdefiniowaną przez użytkownika, podłącz oba do niej i pozostaw kontener pomocniczy jedyną drogą na zewnątrz.
Trzymaj te dwa pytania osobno: które kontenery mogą się nawzajem osiągać i który dokąd wychodzi. Ich połączenie jest najczęstszym sposobem, w jaki ten projekt znów staje się VPN dla całego hosta.
Macierz awarii na pierwszą godzinę
Większość pierwszych prób kończy się niepowodzeniem na jeden z czterech sposobów, a każdy ma inną przyczynę. Sprawdzaj je w tej kolejności, bo pierwsze dwa wyjaśniają niemal każde zgłoszenie.
| Symptom | Likely cause |
|---|---|
| Web UI unreachable after the change | Port mapping declared on the joining container instead of the sidecar |
| Both containers show the provider's exit address | The direct service was attached to the sidecar network |
| Internal names stop resolving | Resolver settings live on the host, not in the shared namespace |
| Health check fails but the app works | The check probes localhost, which now means the sidecar |
Czwarty wiersz to ten, który ludzie błędnie diagnozują jako błąd aplikacji. Sonda napisana przeciwko własnemu loopbackowi obciążenia testuje teraz kontener tunelu, więc albo zawodzi, albo zgłasza całkowicie niewłaściwą usługę.
Gdy jedno imię hosta potrzebuje tunelu
Czasami pełny tunel to za dużo: jedna nazwa wewnętrzna musi przechodzić przez firmowy VPN, podczas gdy lokalny socket lub połączenie ekranu nadal działa. Pełny tunel w kontenerze psuje tę ścieżkę i wszystko adresowane do hosta, więc kieruj tylko prefiks, który tego potrzebuje. Otoczka z podzielonym routingiem wokół klienta robi to, wysyłając wskazany host przez tunel i pozostawiając poprzednią trasę nietkniętą dla wszystkiego innego.
Wybierz to, gdy musisz osiągnąć tylko jedną usługę i nie próbujesz przenieść całego ruchu kontenera. To inne narzędzie niż kontener pomocniczy i odpowiada na inne pytanie.
Zweryfikuj, a potem zrób to odporne na restart
Zapytaj każdy kontener, z jakiego adresu wygląda na to, że przychodzi. Ten w tunelu powinien wypisać adres dostawcy, a bezpośredni — wyjście hosta. Identyczne odpowiedzi oznaczają, że bezpośrednia usługa odziedziczyła niewłaściwą przestrzeń nazw albo VPN na poziomie hosta nadal przechwytuje wszystko, a te dwie poprawki są różne. Uruchom sprawdzenie ponownie po każdej zmianie w compose, bo jeden skopiowany blok usługi wystarczy, by przywrócić problem.
Trzy rzeczy zwykle psują się później. DNS podąża za właścicielem przestrzeni nazw, więc ustawienia resolvera i domeny wyszukiwania należą do kontenera pomocniczego, a nie do hosta. VPN z przekierowaniem portów zmienia swój port nasłuchu przy ponownym połączeniu, więc przekierowany port dostawcy i port nasłuchu po stronie kontenera trzeba zapisać z powrotem w konfiguracji klienta lub w mapowaniu portów, zwykle przez mały aktualizator, który czyta API dostawcy. I każda sonda napisana przeciwko localhost pyta teraz kontener tunelu, a nie obciążenie.
Zapisz wzorzec, w tym który kontener posiada przestrzeń nazw i które porty do niego należą. Następna osoba doda usługę, skopiuje niewłaściwy blok i odtworzy pierwszą awarię z tego artykułu.