Ruch kontenerów Docker omija VPN hosta: jak to sprawdzić
VPN hosta obejmuje tylko przestrzeń nazw sieci hosta. Te kontrole pokażą, czy ruch kontenerów na moście wchodzi do tunelu, czy wychodzi bezpośrednio.
Przeglądarka na hoście pokazuje adres wyjściowy VPN, kontener zgłasza twoje domowe łącze, a ktoś nazywa to wyciekiem. Nic nie wyciekło. Tunel hosta to zestaw interfejsów, tras i reguł należących do przestrzeni nazw sieci hosta, a kontener na moście to inna przestrzeń nazw z własną trasą domyślną. Siedziałem na stosie Compose, w którym klient VPN był połączony od tygodni i ani jeden pakiet kontenera nigdy do niego nie trafił.
Sprawdź przestrzeń nazw przed ikoną w zasobniku
Przestrzenie nazw to cały argument. Gdy Docker uruchamia kontener w sieci mostkowej, tworzy przestrzeń nazw sieci, podłącza do niej jeden koniec pary veth i daje tej przestrzeni adres oraz trasę domyślną. Interfejs tunelu, jakkolwiek się nazywa, żyje w przestrzeni nazw hosta. Ruch wewnątrz kontenera go nie widzi i żadne ustawienie klienta tego z zewnątrz nie zmienia.
Dwa obsługiwane ruchy wyprowadzają cię z izolacji. --network host umieszcza kontener w przestrzeni nazw hosta, więc dziedziczy on trasy hosta, a tym samym tunel. --network container:vpn współdzieli przestrzeń nazw innego kontenera i właśnie tak większość projektów sidecar wysyła obciążenie przez kontener VPN. Oba są świadomymi wyborami; zwykle tylko jeden z nich jest tym, co miał na myśli wdrażający.
Tryb hosta nie jest darmowym ulepszeniem. Kontener przestaje mieć własny adres, publikowanie portów przestaje obowiązywać, a proces trzymający tam NET_ADMIN może przepisać routing hosta. Zaakceptowanie tego może być właściwą decyzją. Zakładanie, że jest już włączone, to sposób, w jaki ludzie spędzają wieczór na debugowaniu tunelu, którego nigdy nie było na ścieżce.
Śledź pakiet od mostu
Kontener na moście wysyła swój pakiet do swojej bramy domyślnej, czyli interfejsu mostu na hoście. Host przekazuje pakiet dalej i w domyślnej konfiguracji tłumaczy adres źródłowy na swój, zanim pakiet opuści maszynę. Właśnie ten krok tłumaczenia po cichu obala politykę.
Zanim pakiet dotrze do punktu końcowego tunelu, niesie adres hosta. Każda reguła, trasa polityki lub decyzja o tunelu dzielonym oparta na pierwotnym adresie kontenera przestaje pasować, a dwóch kontenerów mających wychodzić różnymi wyjściami nie da się odróżnić wyłącznie po źródle. Jeśli potrzebujesz routingu na kontener, decyzja musi zapaść przed tłumaczeniem albo w przestrzeni nazw, którą kontrolujesz.
Docker sam utrzymuje te reguły, przez ten backend zapory, z którym skonfigurowano demona. Reguły napisane ręcznie poza obsługiwanym hakiem dla ruchu przekazywanego, DOCKER-USER, mogą zostać przestawione lub usunięte, gdy demon się restartuje lub host jest aktualizowany. Dokumentacja Dockera dotycząca filtrowania pakietów pokazuje kolejność łańcuchów; praktyczny punkt jest taki, że każda reguła potrzebuje właściciela i ścieżki przeładowania, którą naprawdę przetestowałeś.
Testuj oba systemy osobno
Dowody z jednej przestrzeni nazw nic nie mówią o drugiej. Żądanie uruchomione wewnątrz kontenera VPN dowodzi, że tunel działa dla tego kontenera. To nie jest dowód o hoście, a to samo polecenie uruchomione z kontenera --network host nie jest dowodem o moście.
# host namespace
ip route get 1.1.1.1
ip -brief addr show
# a fresh container on the same bridge network
docker run --rm --network appnet alpine sh -c 'ip route; cat /etc/resolv.conf; ip -6 route'
Potem powtórz test wewnątrz rzeczywistego kontenera aplikacji, a nie podobnego obrazu. Aplikacja może nieść dodatkową trasę, zmienną środowiskową proxy lub inny resolver, a każde z tych zmienia odpowiedź. Za każdym razem sprawdzaj rozwiązywanie nazw i drugą rodzinę adresów: kontenery na mostach zdefiniowanych przez użytkownika rozwiązują się przez wbudowany resolver Dockera pod 127.0.0.11, a domyślna trasa IPv6 na moście może wynieść ruch na zewnątrz, podczas gdy ty jesteś zajęty testowaniem tunelu tylko IPv4.
Przeczytaj wzorzec, zanim dotkniesz danych logowania
Gdy host działa, a kontener nie, przyczyna jest prawie zawsze strukturalna, a rotacja kluczy lub ponowna instalacja klienta marnuje popołudnie. Najpierw uporządkuj objaw, a poprawka zwykle sama się nazywa.
| What you see | Usual cause | First check |
|---|---|---|
| Host exits through the VPN, container shows the ISP address | The container never entered the tunnel | Default route inside the container |
| Container works until the daemon restarts, then stops | Rules outside the supported hook, or a changed backend | Daemon's reported firewall backend and DOCKER-USER |
| Container loses internal hosts after the tunnel comes up | VPN prefix overlaps the Docker bridge subnet | ip route on the host, then docker network inspect |
| Small replies arrive, large ones hang | Tunnel MTU or missing MSS clamping | Link MTU on both ends of the tunnel |
| Container falls back to the ISP address when the tunnel drops | Nothing enforces the kill switch for forwarded traffic | Stop the tunnel with a request in flight |
Wiersz o nakładaniu zasługuje na własne zdanie. Profil VPN, który wpycha trasę dla 172.17.0.0/16 lub dla 10.0.0.0/8, który przypadkiem zawiera prefiks twojego mostu, sprawia, że tunel rości sobie prawo do podsieci kontenerów, a odpowiedzi do przetłumaczonych adresów pójdą w złą stronę lub znikną. Przenumerowanie sieci Dockera jest zwykle czystsze niż gromadzenie wyjątków.
Uczyń pokrycie jawnym, a potem zepsuj je celowo
Dwa projekty wytrzymują przegląd. Współdziel przestrzeń nazw kontenera VPN, a każde objęte obciążenie używa jednego tunelu z jedną granicą restartu, co jest proste, dopóki jedna usługa nie potrzebuje innego wyjścia lub własnej ścieżki DNS. Albo skieruj sieć kontenerów do bramy VPN na hoście: przekazywanie włączone, prefiks mostu skierowany na tunel, ruch powrotny obsłużony jawnie. To kupuje kontrolę na sieć i kosztuje cię zestaw reguł do utrzymania przez aktualizacje demona i klienta.
Tak czy inaczej, testem, który się liczy, jest przypadek awarii. Zatrzymaj tunel, gdy żądanie kontenera jest w locie, i zobacz, dokąd idzie pakiet. Jeśli spada z powrotem na ścieżkę bezpośrednią, pokrycie nigdy nie było wymuszone, bo kill switch klienta rządzi ruchem samego klienta, a nie pakietami przekazywanymi z mostu. Potem zrestartuj demona i hosta i potwierdź wynik po raz drugi; to moment, w którym ręcznie pisane reguły znikają.
Zanim uznasz to za skończone, potwierdź cztery rzeczy: interfejs tunelu jest w tej samej przestrzeni nazw co ruch, test kontenera odbył się w prawdziwym kontenerze, sprawdzono rozwiązywanie nazw i obie rodziny adresów, a test awarii tunelu nadal kończy się zamknięciem. Potem zapisz backend zapory, wersję klienta i właściciela każdej reguły. Ten zapis właśnie powstrzymuje następną aktualizację przed pozostawieniem nieudokumentowanej mieszanki starych założeń.