Маршрутизація з контейнерів докера з використанням іншого фізичного інтерфейсу мережі та шлюзу за замовчуванням


13

Довідкова інформація

У мене є сервер з двома мережевими інтерфейсами, на якому працює Docker. Docker, як і деякі інструменти для віртуалізації, створює мостовий інтерфейс Linux, який називається docker0. Цей інтерфейс налаштований за замовчуванням з IP-адресою, 172.17.42.1і всі контейнери Docker спілкуються з цим інтерфейсом як їх шлюзом і присвоюються IP-адресам у тому ж /16діапазоні. Як я розумію, весь мережевий трафік до / з контейнерів проходить через NAT, тому зовнішній вигляд, як видається, надходить 172.17.42.1, і вхідний він надсилається до нього 172.17.42.1.

Моя настройка виглядає так:

                                          +------------+        /
                                          |            |       |
                            +-------------+ 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|       |
                                          +------------+            

Проблема

Я хочу перенести весь трафік з / до будь-яких контейнерів Docker з другого eth1 192.168.1.2інтерфейсу до шлюзу за замовчуванням 192.168.1.1, при цьому маючи весь трафік від / до хост-машини вийти з eth0 10.1.1.2інтерфейсу до шлюзу за замовчуванням 10.1.1.1. Наразі я пробував багато речей безрезультатно, але одне, що, на мою думку, є найбільш правильним - це використовувати iproute2 так:

# 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

Коли я піднімаю контейнер, я взагалі не можу з нього виїхати. Я не впевнений, чи використовуються мостові інтерфейси так само, як фізичні інтерфейси для такого роду маршрутизації, і я просто хочу перевірити обґрунтованість, а також будь-які поради щодо того, як я міг би виконати цю, здавалося б, просту задачу.


Ваш коментар щодо NAT неправильний. Він встановлений для маскування на адресу джерела 172.17.0.0/16, де вихідний інтерфейс не docker0. тобто -A РОЗМІСТЕННЯ -s 172.17.0.0/16! -o docker0 -j MASQUERADE. Що означає, якщо пакет, що походить з контейнера докера, виходить або через eth0, або eth1, він буде приймати IP-адресу цього інтерфейсу, а не IP 172.17.xx.
Метт

Дякуємо за ваш коментар Отже, це змінило б мій підхід до маршрутизації з певного інтерфейсу, правильно? Чи знаєте ви, як я міг би досягти цього? Наразі Докер, здається, просто використовує шлюз за замовчуванням хост-системи, і це не бажана поведінка. Я хочу, щоб усі речі Докера прокладалися з певного інтерфейсу.

Я не впевнений, чому те, що я запропонував, не працює. Але іншим варіантом може бути використання трубопроводів. github.com/jpetazzo/pipework Також може бути корисним для читання розширений розділ про мережу докерів. docs.docker.com/articles/networking
Метт

@Matt Дякую вам за ваші пропозиції щодо цього. З того, що я читав, трубопровід вимагає додаткових команд після запуску контейнера, щоб отримати доступ до правильного шлюзу, що здається вразливим для безпеки. Спочатку було створено для з'єднання контейнерів між кількома хостами, що насправді тут не є моєю метою. Щодо Докерів про розвинені мережеві документи Docker, я ще раз перегляну, але це не було корисно в цій ситуації (я читав це, перш ніж розміщувати тут). Я збираюся опублікувати посилання на цю публікацію на сторінці докера Github Issues і подивіться, як це відбувається звідти.

Ось посилання на випуск Github: github.com/docker/docker/isissue/13762

Відповіді:


1

Можливо, вам доведеться також більше подивитися на налаштування iptables. Docker маскує весь трафік, що походить з контейнерної підмережі, скажімо, 172.17.0.0/16, до 0.0.0.0. Якщо ви запустите iptables -L -n -t nat, ви можете побачити ланцюг POSTROUTING під таблицею nat, яка робить це -

РЕГУЛЮВАННЯ ланцюга (прийняття політики)
цільове місце вибору джерела призначення
МАСКВЕРАДА всі - 172.17.0.0/16 0.0.0.0/0

Тепер ви можете видалити це правило і замінити його правилом, яке маскує весь трафік, що виникає з підмережі контейнерів, до IP вашого другого інтерфейсу - 192.168.1.2, як саме цього ви хочете. Правило видалення буде, якщо припустити, що це перше правило в ланцюжку ПОСТРОЮВАННЯ -

iptables -t nat -D ПОСТРОЙКА 1

Потім ви додаєте це спеціальне правило -

iptables -t nat -A РОЗСТРОЙКА -s 172.17.0.0/16 -j SNAT - to-source 192.168.1.2

Насправді це маскує його до вихідного інтерфейсу. Ця частина призначення просто говорить про те, що будь-який трафік, що походить від вихідної підмережі до будь-якого пункту призначення, буде замаскований.
Метт

На жаль, це не вийшло. Мій повний процес повинен був працювати: 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. Потім я спробував запустити пінг і сліду з контейнера, і нічого не зміг дістатися.

У мене була схожа вимога, хост має вторинну настройку ip, щоб вийти на публічний IP. І я хотів, щоб докер-контейнер дотримувався того ж самого. Це спрацювало в такому випадку: "iptables -t nat -I POSTROUTING 1 -s 172.17.0.0/16 -d PUBIP / 32 -j SNAT - to-source SECONDARYIP"
Ram 11

1

Ми з другом зіткнулися з цією проблемою, коли ми хотіли, щоб докер підтримував декілька мережевих інтерфейсів, які обслуговували запити. Ми спеціально працювали зі службою AWS EC2, де ми також приєднували / конфігурували / піднімали додаткові інтерфейси. У цьому проекті є більше того, що вам потрібно, тому я спробую сюди включити лише те, що вам потрібно.

Спочатку ми створили окрему таблицю маршрутів для eth1:

ip route add default via 192.168.1.2 dev eth1 table 1001

Далі ми налаштували таблицю mangle, щоб встановити деякі знаки з'єднання, що надходять від 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

Нарешті ми додаємо це правило для всіх fwmarks, щоб використовувати нову створену нами таблицю.

ip rule add from all fwmark 0x1001 lookup 1001

Наведена нижче iptablesкоманда відновить позначку з'єднання, а потім дозволить правилу маршрутизації використовувати правильну таблицю маршрутизації.

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

Я вважаю, що це все, що потрібно з нашого більш складного прикладу, коли (як я вже сказав) наш проект приєднував / конфігурував / підводив eth1інтерфейс під час завантаження.

Тепер цей приклад не зупинить з'єднання від eth0обслуговування запитів до, docker0але я вважаю, що ви можете додати правило маршрутизації, щоб запобігти цьому.


@stuntmachine цікаво, якби у вас була можливість спробувати це? Якщо ви вже щось зрозуміли самостійно, чи зможете ви поділитися своїм рішенням?
williamsbdev

Привіт @williamsbdev - старий пост і довгий кадр, але ви вважаєте, що це рішення також буде працювати для моєї проблеми на SO? stackoverflow.com/questions/51312310/…
Jolly Roger

2
Джолі Роджер - я вірю, що це вирішить вашу проблему. Нещодавно у мене була інша команда, яка запитала мене про цю публікацію в блозі (фактично таке ж рішення, як тут), і вони сказали, що це чудово працює. williamsbdev.com/posts/docker-connection-marking
williamsbdev

0

Маскарад не з 172.17.42.1, а скоріше

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

Це означає, що це правило не буде працювати правильно.

ip rule add from 172.17.42.1 table docker

Спробуйте замість цього

ip rule add from 172.17.0.0/16 table docker

На жаль, це не вийшло. Мої контейнери все ще маршрутизувались до того ж шлюзу за замовчуванням, що і хост. Ось що я запустив: 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 З контейнера я запустив traceroute, і перший
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.