Инструменты пользователя

Инструменты сайта


linux:docker_network_conflict

Различия

Здесь показаны различия между двумя версиями данной страницы.

Ссылка на это сравнение

Следующая версия
Предыдущая версия
linux:docker_network_conflict [2026/08/13 07:47]
werwolf создано
linux:docker_network_conflict [2026/08/13 08:03] (текущий)
werwolf
Строка 1: Строка 1:
-====== Конфликт сети Docker с корпоративной/​VPN-сетью ======+====== Конфликт сети Docker с корпоративной / VPN-сетью ====== 
 + 
 +<note tip> 
 +**Страница:​** ''​dev:​docker_network_conflict'' ​  
 +**Когда смотреть:​** внутренний сервис не открывается,​ DNS «в порядке»,​ VPN подключён,​ недавно поднимали Docker. 
 +</​note>​
  
 ===== Симптомы ===== ===== Симптомы =====
  
-  * В браузере или ''​curl''​ не открывается внутренний сервис (Jira, LDAP, change-pass,​ git и т.п.)+  * Не открывается внутренний сервис (Jira, LDAP, ''​change-pass.iep.loc''​, git и т.п.) ​— ни в браузере,​ ни в ''​curl''​
   * Ошибка:​ ''​Connection refused''​ или ''​Failed to connect''​ на портах 80/443   * Ошибка:​ ''​Connection refused''​ или ''​Failed to connect''​ на портах 80/443
-  * DNS резолвится **правильно** (''​getent hosts hostname''​ возвращает ожидаемый IP) +  * ''​getent hosts hostname''​ возвращает ​**ожидаемый** IP 
-  * Проблема появляется ​**после** ''​docker compose up''​ или когда на машине много ​Docker-сетей +  * Проблема ​часто ​появляется после ''​docker compose up''​ или когда на машине много ​compose-проектов 
-  * VPN подключён,​ но трафик до нужного IP **не идёт через tun0/tun1**+  * VPN подключён ​(''​tun0''​ / ''​tun1''​ есть), но сервис недоступен
  
 ===== Суть проблемы ===== ===== Суть проблемы =====
  
-Docker создаёт bridge-интерфейсы (''​br-xxxxxxxxxxxx''​) с собственными подсетями, например:+Docker создаёт bridge-интерфейсы (''​br-xxxxxxxxxxxx''​) с собственными подсетями:​
  
   * ''​172.17.0.0/​16''​ — default bridge   * ''​172.17.0.0/​16''​ — default bridge
Строка 17: Строка 22:
   * ''​172.18.0.0/​16''​ — ''​status_app-network''​   * ''​172.18.0.0/​16''​ — ''​status_app-network''​
  
-Если подсеть Docker **пересекается** с корпоративной ​сетью ​(часто ''​172.16.0.0/​12'' ​или конкретно ​''​172.22.0.0/​16'' ​для IEP), Linux направляет пакеты **в Docker-bridge**,​ а не в VPN.+Если подсеть Docker **пересекается** с корпоративной (часто ​диапазон ​''​172.16.0.0/​12''​, в IEP — ''​172.22.0.0/​16''​),​ Linux направляет пакеты **в Docker-bridge**,​ а не в VPN.
  
-**Пример:** ''​change-pass.iep.loc''​ → ''​172.22.224.153''​. Сеть ''​rpcserver_default''​ заняла ''​172.22.0.0/16''​. Маршрут:+<note important>​ 
 +Это ​**не** проблема DNS и **не** ''​resolv.conf''​. ​Имя резолвится верно; ломается **маршрутизация** на уровне ядра Linux. 
 +</​note>​ 
 + 
 +===== Один IP — два разных случая ===== 
 + 
 +Типичная ловушка:​ **DNS и маршрут говорят разное** про один и тот же хостПоэтому кажется, что «имя резолвится — значит всё ок», а ''​curl''​/браузер всё равно не открывают URL. 
 + 
 +==== Пример с change-pass.iep.loc ==== 
 + 
 +Выполняем подряд:​ 
 + 
 +<code bash> 
 +grep -n change-pass /etc/hosts /​etc/​resolv.conf 2>/​dev/​null 
 +getent hosts change-pass.iep.loc 
 +ip route get 172.22.224.153 
 +</code> 
 + 
 +Вывод **при конфликте с Docker**:
  
 <​code>​ <​code>​
-172.22.224.153 dev br-355c08cd95dd src 172.22.0.1+172.22.224.153 ​ change-pass.iep.loc 
 +172.22.224.153 dev br-355c08cd95dd src 172.22.0.1 ​uid 1891243316 
 +    cache
 </​code>​ </​code>​
  
-Пакеты уходят в пустой Docker-bridge → ''​Connection refused''​. ​Реальный ​сервер ​в корпсети недоступен.+Разбор по строкам: 
 + 
 +^ Команда / строка ^ Что кажется ^ Что на самом деле ^ 
 +''​getent hosts'' ​→ ''​172.22.224.153 change-pass.iep.loc''​ | DNS/hosts работает, IP «правильный» | Да, имя → IP определено ​верно. Это **не** ​проблема ''​resolv.conf''​ | 
 +| ''​ip route get''​ → ''​dev br-355c08cd95dd src 172.22.0.1''​ | — | Пакеты к ''​172.22.224.153''​ уходят в **Docker-bridge**,​ а не в VPN/IEP | 
 +| ''​grep … /​etc/​hosts''​ — пусто | Запись только в DNS | Имя может резолвиться и без ''/​etc/​hosts''​ |
  
 <note important>​ <note important>​
-Это ​**не** ​проблема DNS и **не** ''​resolv.conf''​. ​Имя ​резолвится верноломается **маршрутизация** на уровне ядра Linux.+**Два случая использования одной подсети ''​172.22.0.0/​16'':​** 
 + 
 +  - **Корпоративная сеть IEP** — реальный сервер ​''​change-pass.iep.loc'' ​(''​172.22.224.153''​),​ доступ через ​VPN (''​tun0''​) 
 +  - **Docker-сеть ''​rpcserver_default''​** — локальный bridge ''​br-355c08cd95dd'' ​с адресом ''​172.22.0.1/​16''​ 
 + 
 +Ядро Linux не различает ​«корпоративный''​ и «docker''​ ''​172.22.x.x''​ — срабатывает ​маршрут ​''​172.22.0.0/​16 dev br-...''​. Трафик **не доходит** до сервера ​в IEP → ''​Connection refused''​.
 </​note>​ </​note>​
 +
 +==== Как отличить:​ DNS vs маршрут ====
 +
 +^ Проверка ^ Норма (конфликта нет) ^ Конфликт с Docker ^
 +| ''​getent hosts HOST''​ | IP из корпсети (напр. ''​172.22.224.153''​) | То же — IP верный |
 +| ''​ip route get IP''​ | ''​via 10.x.x.x dev tun0''​ (VPN) | ''​dev br-xxxxxxxxxxxx src 172.22.0.1''​ |
 +| ''​curl https://​HOST/''​ | HTTP 200 / редирект | ''​Connection refused''​ |
 +
 +<note tip>
 +Если ''​getent''​ и ''​curl''​ расходятся по смыслу — **сначала смотрите ''​ip route get''​**,​ не ''​resolv.conf''​.
 +</​note>​
 +
 +==== После устранения конфликта ====
 +
 +<code bash>
 +docker compose down   # в проекте с сетью 172.22.0.0/​16
 +ip route get 172.22.224.153
 +</​code>​
 +
 +Ожидаемый маршрут:​
 +
 +<​code>​
 +172.22.224.153 via 10.5.192.1 dev tun0 src 10.5.193.211
 +    cache
 +</​code>​
 +
 +Тот же IP ''​172.22.224.153'',​ но теперь трафик идёт **через VPN**, а не в Docker-bridge.
  
 ===== Быстрая диагностика ===== ===== Быстрая диагностика =====
  
-==== 1. Проверить ​DNS ====+==== 1. DNS ====
  
 <code bash> <code bash>
-HOST=change-pass.iep.loc ​  # подставьте свой хост+HOST=change-pass.iep.loc
 getent hosts "​$HOST"​ getent hosts "​$HOST"​
 </​code>​ </​code>​
  
-Если IP получен — DNS в порядке (или ​запись в ''/​etc/​hosts''​).+Если IP получен — резолв ​в порядке (DNS или ''/​etc/​hosts''​).
  
-==== 2. Куда уходит маршрут ====+==== 2. Маршрут ​(главная проверка) ​====
  
 <code bash> <code bash>
Строка 48: Строка 110:
 </​code>​ </​code>​
  
-**Плохо** ​(конфликт с Docker):+**Плохо** ​— трафик ​в Docker:
  
 <​code>​ <​code>​
-172.22.224.153 dev br-xxxxxxxxxxxx ​src 172.22.0.1+172.22.224.153 dev br-355c08cd95dd ​src 172.22.0.1
 </​code>​ </​code>​
  
-**Хорошо** ​(через VPN/​корпсеть):+**Хорошо** ​— трафик ​через VPN:
  
 <​code>​ <​code>​
Строка 60: Строка 122:
 </​code>​ </​code>​
  
-==== 3. Проверить порты ====+==== 3. Порты ​и HTTP ====
  
 <code bash> <code bash>
Строка 69: Строка 131:
 </​code>​ </​code>​
  
-При конфликте с Docker — ''​Connection refused''​ **до** VPN, даже если ​VPN подключён.+При конфликте с Docker — ''​Connection refused''​ **до** VPN, даже если ​''​tun0'' ​поднят.
  
 ==== 4. Найти конфликтующую Docker-сеть ==== ==== 4. Найти конфликтующую Docker-сеть ====
  
 <code bash> <code bash>
-ip route | grep 172.22 ​         # или другая проблемная подсеть+ip route | grep 172.22
 docker network ls docker network ls
 docker network inspect $(docker network ls -q) | grep -E '"​Name"​|Subnet|Gateway'​ docker network inspect $(docker network ls -q) | grep -E '"​Name"​|Subnet|Gateway'​
Строка 81: Строка 143:
 Ищите сеть, у которой ''​Subnet''​ совпадает с диапазоном корпоративных адресов. Ищите сеть, у которой ''​Subnet''​ совпадает с диапазоном корпоративных адресов.
  
-**Пример из практики:**+**Кейс 2026-08-13:**
  
   * Сеть: ''​rpcserver_default''​   * Сеть: ''​rpcserver_default''​
Строка 113: Строка 175:
  
 echo echo
-echo "=== Docker routes (172.16/​12 ​overlap) ==="+echo "=== Docker routes (172.16/12) ==="
 ip route | grep -E '​172\.(1[6-9]|2[0-9]|3[0-1])\.'​ || echo "​(none)"​ ip route | grep -E '​172\.(1[6-9]|2[0-9]|3[0-1])\.'​ || echo "​(none)"​
  
Строка 121: Строка 183:
   | grep -E '"​Name"​|Subnet|Gateway'​ || echo "​docker not available"​   | grep -E '"​Name"​|Subnet|Gateway'​ || echo "​docker not available"​
 </​file>​ </​file>​
 +
 +Запуск:​
  
 <code bash> <code bash>
Строка 129: Строка 193:
 ===== Решение ===== ===== Решение =====
  
-==== Временное (сразу восстановить доступ==== +==== Сразу восстановить доступ ====
- +
-Остановить проект,​ который создал конфликтующую сеть:+
  
 <code bash> <code bash>
-cd ~/​projects/​rpc.server ​   # путь к compose-проекту+cd ~/​projects/​rpc.server
 docker compose down docker compose down
-# или: docker-compose down 
 </​code>​ </​code>​
  
-Проверить:+Проверка:
  
 <code bash> <code bash>
Строка 146: Строка 207:
 </​code>​ </​code>​
  
-Маршрут должен идти через ''​tun0''​ / ''​tun1'',​ не через ''​br-...''​.+Маршрут должен идти через ''​tun0'',​ не через ''​br-...''​. ''​curl''​ — HTTP 200.
  
-==== Постоянное (при следующем ''​docker ​compose ​up''​) ​====+==== Навсегда: другой subnet в compose ====
  
-В ''​docker-compose.yml''​ проекта задайте ​**другую** ​подсетьне пересекающуюся с корпоративной:​+В ''​docker-compose.yml''​ проекта задайте подсеть ​**вне** корпоративной:​
  
 <code yaml> <code yaml>
Строка 158: Строка 219:
       config:       config:
         - subnet: 192.168.220.0/​24         - subnet: 192.168.220.0/​24
-</​code>​ 
- 
-Или для named network: 
- 
-<code yaml> 
-networks: 
-  app-network:​ 
-    ipam: 
-      config: 
-        - subnet: 192.168.221.0/​24 
 </​code>​ </​code>​
  
Строка 174: Строка 225:
 </​note>​ </​note>​
  
-==== Глобально для ​всех ​новых Docker-сетей ====+==== Глобально: пулы ​для новых Docker-сетей ====
  
 ''/​etc/​docker/​daemon.json'':​ ''/​etc/​docker/​daemon.json'':​
Строка 185: Строка 236:
 } }
 </​code>​ </​code>​
 +
 +Применить:​
  
 <code bash> <code bash>
Строка 198: Строка 251:
 ^ Симптом ^ Вероятная причина ^ Что смотреть ^ ^ Симптом ^ Вероятная причина ^ Что смотреть ^
 | DNS не резолвит | ''​resolv.conf'',​ VPN DNS, ''/​etc/​hosts''​ | ''​getent hosts''​ | | DNS не резолвит | ''​resolv.conf'',​ VPN DNS, ''/​etc/​hosts''​ | ''​getent hosts''​ |
-| DNS OK, route через ''​br-...''​ | Конфликт ​Docker ​subnet | ''​ip route get'',​ ''​docker network inspect''​ |+| DNS OK, route через ''​br-...''​ | Конфликт subnet ​Docker ​| ''​ip route get'',​ ''​docker network inspect''​ |
 | Route через ''​tun0'',​ но timeout | VPN без маршрута в сеть | ''​ip route'',​ админы VPN | | Route через ''​tun0'',​ но timeout | VPN без маршрута в сеть | ''​ip route'',​ админы VPN |
-| Route OK, Connection refused | Сервис не слушает порт | ''​nc -vz IP 443''​ на стороне ​сервера +| Route OK, Connection refused | Сервис не слушает порт | ''​nc -vz IP 443''​ на сервере 
-| TLS verify error | Корпоративный CA | ''​curl -k'' ​vs установка CA в систему |+| TLS verify error | Корпоративный CA | ''​curl -k'' ​установка CA в систему |
  
 ===== Профилактика ===== ===== Профилактика =====
  
   - Не использовать ''​172.16.0.0/​12''​ для Docker, если работаете с IEP/RTLabs VPN   - Не использовать ''​172.16.0.0/​12''​ для Docker, если работаете с IEP/RTLabs VPN
-  - Перед ''​docker compose up''​ нового проекта:​ ''​docker network inspect ​... | grep Subnet''​ +  - Перед ''​docker compose up''​ нового проекта:​ ''​docker network inspect ​… | grep Subnet''​ 
-  - При смене машины / VPN — один раз ​прогнать ​''​ip route get <​корп-хост>''​ +  - При смене машины / VPN — один раз''​ip route get <​корп-хост>''​ 
-  - Документировать subnet ​каждого локального compose в README проекта+  - Subnet ​каждого локального compose ​— в README проекта
  
-===== Связанные команды =====+===== Полезные команды =====
  
 <code bash> <code bash>
-# все маршруты Docker-bridge+# все маршруты Docker-bridge ​в 172.16/12
 ip route | grep '​^172\.'​ ip route | grep '​^172\.'​
  
Строка 226: Строка 279:
 ===== История кейса ===== ===== История кейса =====
  
-**Дата:​** 2026-08-13 ​  +  * **Дата:​** 2026-08-13 
- +  ​* ​**Хост:​** ''​change-pass.iep.loc''​ → ''​172.22.224.153''​ 
-**Хост:​** ''​change-pass.iep.loc''​ → ''​172.22.224.153''  ​ +  **Причина:​** Docker-сеть ''​rpcserver_default'' ​(''​172.22.0.0/​16''​перехватывала маршрут 
- +  **Решение:​** ''​docker compose down''​ в ''​rpc.server''​ + subnet ''​192.168.220.0/​24'' ​в compose 
-**Причина:​** Docker-сеть ''​rpcserver_default'' ​с ''​172.22.0.0/​16''​ перехватывала маршрут  +  ​* ​**Результат:​** ''​ip route get''​ → ''​via 10.5.192.1 dev tun0'',​ ''​curl''​ → HTTP 200
- +
-**Решение:​** ''​docker compose down''​ в ''​rpc.server''​ + смена ​subnet ​в compose на ''​192.168.220.0/​24''​.   +
- +
-**Результат:​** ''​ip route get''​ → ''​via 10.5.192.1 dev tun0'',​ ''​curl''​ → HTTP 200.+
linux/docker_network_conflict.1786607269.txt.gz · Последние изменения: 2026/08/13 07:47 — werwolf