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