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

Справочная информация

У меня есть сервер с двумя сетевыми интерфейсами, который выполняет Докера. Докер, как некоторые инструменты виртуализации, создает названный интерфейс моста Linux docker0. Этот интерфейс настроен по умолчанию с IP 172.17.42.1 и все контейнеры Докера общаются с этим интерфейсом как своим шлюзом и являются присвоенными 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|       |
                                          +------------+            

Проблема

Я хочу направить весь трафик из/в любые контейнеры Докера из второго 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

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

13
задан 4 June 2015 в 23:47
3 ответа

Возможно, вам также придется больше узнать о настройке iptables. Docker маскирует весь трафик, исходящий из подсети контейнера, скажем, 172.17.0.0/16, в 0.0.0.0. Если вы запустите iptables -L -n -t nat , вы увидите цепочку POSTROUTING под таблицей nat, которая делает это -

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination
MASQUERADE  all  --  172.17.0.0/16        0.0.0.0/0

Теперь вы можете удалить это правило и заменить его правилом, которое маскирует все трафик, исходящий из подсети контейнеров на IP-адрес вашего второго интерфейса - 192.168.1.2, так как это именно то, что вам нужно. Правило удаления будет, при условии, что это первое правило в цепочке POSTROUTING -

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
1
ответ дан 2 December 2019 в 21:28

Маскарад не из 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
0
ответ дан 2 December 2019 в 21:28

Мы с другом столкнулись именно с этой проблемой, когда хотели, чтобы докер поддерживал несколько сетевых интерфейсов, обслуживающих запросы. Мы специально работали с сервисом 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

Наконец, мы добавляем это правило для всех fwmark s, чтобы использовать новую таблицу мы создали.

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 , но я считаю, что вы можете добавить правило маршрутизации, чтобы предотвратить это.

1
ответ дан 2 December 2019 в 21:28

Теги

Похожие вопросы