Trasowanie z kontenerów dokowanych przy użyciu innego fizycznego interfejsu sieciowego i domyślnej bramy


13

Informacje podstawowe

Mam serwer z dwoma interfejsami sieciowymi, na którym działa Docker. Docker, podobnie jak niektóre narzędzia do wirtualizacji, tworzy interfejs mostu linuksowego o nazwie docker0. Interfejs ten jest domyślnie skonfigurowany z 172.17.42.1adresem IP i wszystkie kontenery Docker komunikują się z tym interfejsem jako bramą i mają przypisane adresy IP z tego samego /16zakresu. Jak rozumiem, cały ruch sieciowy do / z kontenerów przechodzi przez NAT, więc wydaje się, że przychodzi z 172.17.42.1, a przychodzące są wysyłane 172.17.42.1.

Moja konfiguracja wygląda następująco:

                                          +------------+        /
                                          |            |       |
                            +-------------+ Gateway 1  +-------
                            |             | 10.1.1.1   |     /
                     +------+-------+     +------------+    |
                     |     eth0     |                      /
                     |   10.1.1.2   |                      |
                     |              |                      |
                     | DOCKER HOST  |                      |
                     |              |                      | Internet
                     |   docker0    |                      |
                     |   (bridge)   |                      |
                     |  172.17.42.1 |                      |
                     |              |                      |
                     |     eth1     |                      |
                     |  192.168.1.2 |                      \
                     +------+-------+     +------------+    |
                            |             |            |     \
                            +-------------+ Gateway 2  +-------
                                          | 192.168.1.1|       |
                                          +------------+            

Problem

Chcę skierować cały ruch z / do dowolnych kontenerów Docker z drugiego eth1 192.168.1.2interfejsu do domyślnej bramy 192.168.1.1, podczas gdy cały ruch z / do hosta wychodzi z eth0 10.1.1.2interfejsu do domyślnej bramy 10.1.1.1. Do tej pory próbowałem różnych rzeczy, ale bezskutecznie, ale jedyną rzeczą, którą uważam za najbliższą do poprawienia, jest użycie iproute2 w następujący sposób:

# Create a new routing table just for docker
echo "1 docker" >> /etc/iproute2/rt_tables

# Add a rule stating any traffic from the docker0 bridge interface should use 
# the newly added docker routing table
ip rule add from 172.17.42.1 table docker

# Add a route to the newly added docker routing table that dictates all traffic
# go out the 192.168.1.2 interface on eth1
ip route add default via 192.168.1.2 dev eth1 table docker

# Flush the route cache
ip route flush cache

# Restart the Docker daemon so it uses the correct network settings
# Note, I do this as I found Docker containers often won't be able
# to connect out if any changes to the network are made while it's     
# running
/etc/init.d/docker restart

Kiedy podnoszę pojemnik, nie mogę z niego pingować po wykonaniu tej czynności. Nie jestem pewien, czy interfejsy mostkowe są obsługiwane w taki sam sposób, jak interfejsy fizyczne dla tego rodzaju routingu, i po prostu chcę kontroli poczytalności, a także wszelkich wskazówek, jak mogę wykonać to z pozoru proste zadanie.


Twój komentarz na temat NAT jest niewłaściwy. Ustawiono maskaradę na adres źródłowy 172.17.0.0/16, gdzie interfejs wyjściowy nie jest dokerem0. tj. -A POSTROUTOWANIE -s 172.17.0.0/16! -o doker0 -j MASQUERADE. Co oznacza, że ​​jeśli pakiet pochodzący z kontenera dokującego zostanie zakończony przez eth0 lub eth1, przejmie adres IP tego interfejsu, a nie adres IP 172.17.xx.
Matt

Dzięki za komentarz. Więc to zmieni moje podejście do routingu poza określony interfejs, prawda? Czy wiesz, jak mógłbym to osiągnąć? Na obecnym etapie Docker wydaje się po prostu używać domyślnej bramy systemu hosta i nie jest to pożądane zachowanie. Chcę, aby wszystkie rzeczy Docker kierowały poza określony interfejs.

Nie jestem pewien, dlaczego to, co zasugerowałem, nie działa. Ale inną opcją może być użycie rurociągów. github.com/jpetazzo/pipework Do przeczytania może być przydatna sekcja zaawansowanej sieci w pomocy dokera . docs.docker.com/articles/networking
Matt

@Matt Dziękuję za sugestie w tej sprawie. Z tego, co przeczytałem, rurociąg wymaga dodatkowych poleceń po uruchomieniu kontenera, aby uzyskać dostęp do właściwej bramy, co wydaje się być luką w zabezpieczeniach. Pierwotnie został stworzony do łączenia kontenerów na wielu hostach, co tak naprawdę nie jest moim celem. Jeśli chodzi o zaawansowane dokumenty sieciowe Dockera, przejrzę je jeszcze raz, ale do tej pory nie było to pomocne w tej sytuacji (przeczytałem go przed opublikowaniem tutaj). Zamierzam opublikować link do tego postu na stronie problemów z dokerem Github i zobaczę, jak to się potoczy.

Oto link z powrotem do wydania Github: github.com/docker/docker/issues/13762

Odpowiedzi:


1

Być może będziesz musiał zajrzeć także do konfiguracji iptables. Docker maskuje cały ruch pochodzący z podsieci kontenera, powiedzmy 172.17.0.0/16, na 0.0.0.0. Jeśli uruchomisz iptables -L -n -t nat, zobaczysz łańcuch POSTROUTING pod tabelą nat, która to robi -

POSTROUTOWANIE łańcucha (AKCEPTACJA zasad)
docelowy źródło docelowy prot opt ​​opt
MASQUERADE all - 172.17.0.0/16 0.0.0.0/0

Teraz możesz usunąć tę regułę i zastąpić ją regułą, która zamaskuje cały ruch pochodzący z podsieci kontenerów do adresu IP drugiego interfejsu - 192.168.1.2, ponieważ tego właśnie pragniesz. Reguła usuwania będzie, zakładając, że jest to pierwsza reguła w łańcuchu POSTROUTING -

iptables -t nat -D POSTROUTOWANIE 1

Następnie dodajesz tę niestandardową regułę -

iptables -t nat -A POSTROUTING -s 172.17.0.0/16 -j SNAT --to-source 192.168.1.2

Właściwie to maskaraduje go do interfejsu wyjściowego. Ta część docelowa mówi po prostu, że każdy ruch pochodzący z podsieci źródłowej do dowolnego miejsca docelowego będzie maskaradowany.
Matt

Niestety to nie zadziałało. My cały proces był prowadzony do: ip rule add from 172.17.0.0/16 table docker ip route add default via 192.168.1.2 dev eth1 table docker ip route flush cache iptables -t nat -D POSTROUTING 1 iptables -t nat -A POSTROUTING -s 172.17.0.0/16 -j SNAT --to-source 192.168.1.2 /etc/init.d/docker restart. Potem próbowałem uruchomić ping i traceroute z kontenera i nie byłem w stanie nic osiągnąć.

Miałem podobne wymaganie, host ma dodatkową konfigurację adresu IP, aby dotrzeć do publicznego adresu IP. I chciałem, aby kontener dokujący postępował tak samo. To zadziałało w takim przypadku: „iptables -t nat -I POSTROUTING 1 -s 172.17.0.0/16 -d PUBIP / 32 -j SNAT --to-source SECONDARYIP”
Ram

1

Wpadłem z przyjacielem na ten właśnie problem, w którym chcieliśmy, aby doker obsługiwał wiele interfejsów sieciowych obsługujących żądania. W szczególności pracowaliśmy z usługą AWS EC2, w której także podłączaliśmy / konfigurowaliśmy / przywoływaliśmy dodatkowe interfejsy. W tym projekcie jest coś więcej niż potrzebujesz, dlatego postaram się uwzględnić tylko to, czego potrzebujesz.

Po pierwsze, stworzyliśmy osobną tabelę tras dla eth1:

ip route add default via 192.168.1.2 dev eth1 table 1001

Następnie skonfigurowaliśmy tabelę mangle, aby ustawić niektóre znaki połączenia przychodzące z eth1:

iptables -t mangle -A PREROUTING -i eth1 -j MARK --set-xmark 0x1001/0xffffffff
iptables -t mangle -A PREROUTING -i eth1 -j CONNMARK --save-mark --nfmask 0xffffffff --ctmask 0xffffffff

Na koniec dodajemy tę regułę, aby wszyscy fwmarkmogli korzystać z nowej tabeli, którą utworzyliśmy.

ip rule add from all fwmark 0x1001 lookup 1001

Poniższe iptablespolecenie przywróci znak połączenia, a następnie pozwoli regule routingu korzystać z właściwej tabeli routingu.

iptables -w -t mangle -A PREROUTING -i docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j CONNMARK --restore-mark --nfmask 0xffffffff --ctmask 0xffffffff

Wierzę, że to wszystko, co jest potrzebne z naszego bardziej złożonego przykładu, w którym (jak powiedziałem) nasz projekt podłączał / konfigurował / uruchamiał eth1interfejs w czasie rozruchu.

Teraz ten przykład nie powstrzyma połączeń od eth0obsługi zgłoszeń, docker0ale uważam, że możesz dodać regułę routingu, aby temu zapobiec.


@stuntmachine tylko ciekawy, czy miałeś okazję to wypróbować? Jeśli już coś wymyśliłeś, czy mógłbyś podzielić się swoim rozwiązaniem?
williamsbdev

Cześć @williamsbdev - stary post i długi strzał, ale czy uważasz, że to rozwiązanie zadziałałoby również w przypadku mojego problemu z SO? stackoverflow.com/questions/51312310/…
Jolly Roger

2
Jolly Roger - Wierzę, że to rozwiąże twój problem. Niedawno inny zespół zapytał mnie o ten post na blogu (zasadniczo to samo rozwiązanie, co tutaj) i powiedzieli, że działa świetnie. williamsbdev.com/posts/docker-connection-marking
williamsbdev

0

Maskarada nie pochodzi z 172.17.42.1, ale raczej

 -A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE

Co oznacza, że ​​ta reguła nie będzie działać poprawnie.

ip rule add from 172.17.42.1 table docker

Spróbuj zamiast tego

ip rule add from 172.17.0.0/16 table docker

Niestety to nie zadziałało. Moje kontenery nadal kierowały się do tej samej domyślnej bramy, co host. Oto, co uruchomiłem: ip rule add from 172.17.0.0/16 table docker ip route add default via 192.168.1.2 dev eth1 table docker ip route flush cache /etc/init.d/docker restart Z kontenera uruchomiłem traceroute, a pierwszy skok to 10.1.1.1, kiedy powinien to być 192.168.1.1
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.