Вопрос или проблема
Фоновая информация
У меня есть сервер с одним физическим сетевым интерфейсом, на котором работает Docker. Этот интерфейс настроен как транк 802.1Q. Чтобы избежать ассиметричной маршрутизации, я настроил таблицы маршрутизации для каждой подсети. Вот мои интерфейсы /etc/network/interfaces:
auto enp3s0
iface enp3s0 inet dhcp
post-up ip route add 192.168.1.0/24 dev enp3s0 table 1
post-up ip route add default via 192.168.1.1 table 1
post-up ip rule add from 192.168.1.0/24 table 1 priority 101
post-up ip route flush cache
pre-down ip rule del from 192.168.1.0/24 table 1 priority 101
pre-down ip route flush table 1
pre-down ip route flush cache
auto enp3s0.2
iface enp3s0.2 inet dhcp
hwaddress ether 00:11:22:33:44:55
post-up ip route add 192.168.2.0/24 dev enp3s0.2 table 2
post-up ip route add default via 192.168.2.1 table 2
post-up ip rule add from 192.168.2.0/24 table 2 priority 102
post-up ip route flush cache
pre-down ip rule del from 192.168.2.0/24 table 2 priority 102
pre-down ip route flush table 2
pre-down ip route flush cache
auto enp3s0.4
iface enp3s0.4 inet dhcp
hwaddress ether 00:11:22:33:44:56
post-up ip route add 192.168.4.0/24 dev enp3s0.4 table 4
post-up ip route add default via 192.168.4.1 table 4
post-up ip rule add from 192.168.4.0/24 table 4 priority 104
post-up ip route flush cache
pre-down ip rule del from 192.168.4.0/24 table 4 priority 104
pre-down ip route flush table 4
pre-down ip route flush cache
...
Эта настройка работает нормально, если я запускаю контейнер с параметром –net=host. Контейнеры доступны из каждой подсети/VLAN.
Проблема
Я хотел бы иметь больше контроля над портами и доступностью (не каждый Docker должен быть доступен в каждой подсети). Если я использую параметр -p (например, -p 3777:3777), контейнеры больше не доступны.
Этот гид https://hicu.be/docker-networking-macvlan-vlan-configuration
решает аналогичную проблему, но я не хочу расширять свои VLAN на Docker и назначать IP-адрес каждому экземпляру Docker. Это слишком много.
Желательное решение
У моего сервера есть IP-адрес в каждой подсети/VLAN,
192.168.1.199 (родной VLAN / управление)
192.168.2.199 (vlan2)
192.168.4.199 (vlan4)
Я хотел бы запускать Docker с параметром -p и выбирать, на каком интерфейсе он будет доступен.
Например, docker run –p 9000:9000 –name portainer … и он должен быть доступен только через 192.168.1.199:9000.
Возможно, моя настройка ip route/ip rule не совсем корректна или/и мне нужен мост Docker для каждой подсети… но на этом этапе я не знаю, как двигаться дальше. На данный момент, если я выбираю параметр –p и Docker подключен к стандартному мосту Docker… контейнер совсем недоступен.
Есть ли у вас идеи?
С уважением,
Марк
Редактирование:
Контейнер portainer_test недоступен по адресу 192.168.4.199:9001
mark@server:~/docker$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
359ebfd027b2 portainer/portainer "/portainer -H unix:…" 21 минуты назад Работающий около минуты 192.168.4.199:9001->9000/tcp portainer_test
9d523a8b22e4 eclipse-mosquitto "/docker-entrypoint.…" 10 дней назад Работающий 16 часов mosquito
a2eeb9582838 portainer/portainer "/portainer" 10 дней назад Работающий 16 часов portainer
f4ef7570cea2 symcon/symcon:stable "/usr/bin/symcon" 10 дней назад Работающий 16 часов symcon
ae43e8be871f jacobalberty/unifi:stable "/usr/local/bin/dock…" 10 дней назад Работающий 16 часов (здоровый) unifi
mark@server:~/docker$ sudo netstat -tulpn | grep LISTEN
tcp 0 0 127.0.0.1:27117 0.0.0.0:* LISTEN 23374/bin/mongod
tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN 30474/systemd-resol
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1592/sshd
tcp 0 0 0.0.0.0:1883 0.0.0.0:* LISTEN 22212/mosquitto
tcp 0 0 0.0.0.0:3777 0.0.0.0:* LISTEN 22247/symcon
tcp 0 0 192.168.4.199:9001 0.0.0.0:* LISTEN 18622/docker-proxy
tcp6 0 0 :::8843 :::* LISTEN 22511/java
tcp6 0 0 :::8880 :::* LISTEN 22511/java
tcp6 0 0 :::8080 :::* LISTEN 22511/java
tcp6 0 0 :::8443 :::* LISTEN 22511/java
tcp6 0 0 :::1883 :::* LISTEN 22212/mosquitto
tcp6 0 0 :::6789 :::* LISTEN 22511/java
tcp6 0 0 :::9000 :::* LISTEN 22273/portainer
Для параметра -p
вы можете использовать формат ip:hostPort:containerPort
, например
docker run -p 192.168.1.199:9000:9000 ...
Дополнительную информацию о доступных форматах можно найти в документации
Может быть, уже поздно, но я опубликую то, что сработало с моей стороны с транком VLAN, подключенным к моему NAS, работающему на Docker….
Вам нужно создать свою собственную сетевую сеть BRIDGE => https://docs.docker.com/network/network-tutorial-standalone/#use-user-defined-bridge-networks
Стандартный мост, созданный по умолчанию, связывается со всеми IP-адресами хоста (0.0.0.0), что и является вашей проблемой.
Убедитесь, что вы используете эту опцию при его создании: com.docker.network.bridge.host_binding_ipv4 с желаемым IP-адресом вашего сервера (в вашем случае 192.168.1.199, чтобы созданный мост связывался только с этим IP)
Затем просто укажите (в вашем примере), что контейнер Portainer использует эту созданную сеть пользователя (–network при создании/запуске контейнера).
Кроме того, вы также можете рассмотреть тип сети macvlan. Удачи 🙂
Ответ или решение
Вам необходимо настроить контейнеры Docker так, чтобы они были доступны только через определённые IP-адреса и порты в ваших VLAN. Рассмотрим, как это можно сделать, шаг за шагом.
Шаг 1: Использование синтаксиса ip:hostPort:containerPort
Первое, что вам нужно знать, это то, что при использовании параметра -p
можно привязывать порты контейнера к конкретному IP-адресу вашего хоста. Используйте следующий формат:
docker run -p 192.168.1.199:9000:9000 --name portainer ...
Этот подход позволяет вам явно указать, что контейнер Portainer должен быть доступен только через IP-адрес 192.168.1.199
на порту 9000
. То же самое можно сделать для других VLAN:
docker run -p 192.168.4.199:9001:9000 --name portainer_test ...
Шаг 2: Создание пользовательской сетевой моста
Вы можете создать свою собственную сетевую мостовую сеть Docker, чтобы контролировать, какие IP-адреса используются для связи. Для этого выполните следующие команды:
- Создайте пользовательскую мостовую сеть, ограничив её привязкой к определённому IP:
docker network create \
--driver bridge \
--subnet 192.168.1.0/24 \
--opt com.docker.network.bridge.host_binding_ipv4=192.168.1.199 \
my_custom_bridge
Замените 192.168.1.199
на любой IP-адрес, который должен использоваться для привязки, и my_custom_bridge
на любое имя сети.
- Теперь запустите ваш контейнер, указав созданную сеть:
docker run --network my_custom_bridge -p 9000:9000 --name portainer ...
Шаг 3: Проверка доступности
После запуска контейнера проверьте, что он слушает указанный IP-адрес и порт. Вы можете использовать netstat
для этого, аналогично тому, как это было указано в вашем вопросе. Вы должны увидеть строки, подобные следующим:
tcp 0 0 192.168.1.199:9000 0.0.0.0:* LISTEN ...
Если доступность работает, вы должны иметь возможность получить доступ к вашему Portainer по адресу http://192.168.1.199:9000
.
Заключение
Используя вышеперечисленные методы, вы сможете контролировать доступность ваших контейнеров Docker в зависимости от VLAN и IP-адресов. Не забывайте также корректно настраивать свои маршруты и ip правила, чтобы избежать проблем с асимметричной маршрутизацией.
Если у вас возникнут дополнительные вопросы или сложности, дайте знать — я постараюсь помочь!