Назад | Перейти на главную страницу

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

Исходная информация

У меня есть сервер с двумя сетевыми интерфейсами, на котором работает 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

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

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

Возможно, вам также придется больше узнать о настройке 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

Маскарад не из 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