Маршрутизация в Docker: полное руководство по сетям bridge, host, overlay и macvlan | AdminWiki

Маршрутизация в Docker: полное руководство по сетям bridge, host, overlay и macvlan

12 августа 2026 12 мин. чтения
Содержание статьи

Что вы узнаете из этого руководства

Сеть Docker - фундамент, на котором держится взаимодействие контейнеров. Ошибка в выборе драйвера или настройке маршрутизации приводит к недоступности сервисов, утечкам трафика и проблемам с безопасностью. Это руководство дает готовые решения для типовых задач: от связи двух контейнеров на одном хосте до мультихостового кластера в Swarm с шифрованием трафика.

Вы получите пошаговые инструкции с командами, проверенными на Docker версии 26+. Разберем, когда использовать bridge, host, overlay и macvlan, как работает проброс портов через iptables и docker-proxy, как контейнеры находят друг друга по DNS-именам и что делать, если сеть не работает. Материал построен от простого к сложному: начальные разделы помогут новичкам, продвинутые сценарии с macvlan и ручной маршрутизацией закроют запросы опытных администраторов.

Типы сетей Docker: как выбрать подходящий драйвер

Docker предлагает четыре основных сетевых драйвера. Выбор зависит от трех факторов: нужна ли изоляция, требуется ли доступ извне и работают ли контейнеры на разных хостах. Таблица ниже дает мгновенную ориентацию.

Драйвер Изоляция Доступ извне Мультихост Производительность Типовой сценарий
bridge Полная (NAT) Проброс портов Нет Средняя Микросервисы на одном сервере
host Отсутствует Прямой Нет Максимальная Высоконагруженный веб-сервер
overlay Полная (VXLAN) Ingress-сеть Swarm Да Средняя (с шифрованием ниже) Кластер Docker Swarm
macvlan Нет (L2-доступ) Прямой (IP из LAN) Нет Высокая Контейнер как физический узел сети

IPvlan - облегченная альтернатива macvlan без расхода MAC-адресов. Подходит, когда сетевой коммутатор ограничивает количество MAC на порту.

Bridge-сеть: стандартная изоляция и связь на одном хосте

Bridge-сеть - драйвер по умолчанию. Docker создает виртуальный коммутатор docker0, к которому подключаются контейнеры через пары veth-интерфейсов. Каждый контейнер получает IP из подсети 172.17.0.0/16 и общается с внешним миром через NAT на iptables.

Дефолтная bridge-сеть имеет критическое ограничение: отсутствует автоматический DNS-резолвинг. Контейнеры видят друг друга только по IP-адресам. При перезапуске IP меняются, что ломает связность. Кастомные bridge-сети лишены этого недостатка - встроенный DNS-сервер на 127.0.0.11 разрешает имена контейнеров автоматически.

Создавайте кастомную bridge-сеть всегда, когда на одном хосте работают больше одного контейнера, которым нужна связь друг с другом. Это дает DNS-резолвинг, изоляцию от других сетей и управление IP-адресацией.

Host-сеть: максимальная производительность без изоляции

Контейнер в host-сети использует сетевой стек хоста напрямую. Нет трансляции адресов, нет виртуальных интерфейсов, нет docker-proxy. Сетевая производительность идентична процессам на хосте. Тесты iperf3 показывают разницу с bridge до 15-20% на высоких скоростях (10 Гбит/с и выше).

Плата за скорость - полное отсутствие сетевой изоляции. Контейнер видит все интерфейсы хоста и может конфликтовать портами с другими процессами. Два контейнера в host-сети не могут слушать один и тот же порт. Этот драйвер оправдан для высоконагруженных сетевых приложений: reverse-прокси, серверов потокового видео, систем мониторинга трафика.

Overlay-сеть: мультихостовое взаимодействие в Swarm

Overlay-сеть решает задачу связи контейнеров на разных физических хостах. Архитектура построена на VXLAN-туннелях: каждый узел Swarm получает виртуальный интерфейс, через который трафик инкапсулируется в UDP-пакеты и передается между демонами Docker. Control plane управляется менеджерами Swarm, data plane - прямое соединение между узлами.

Docker Swarm автоматически управляет overlay-сетями: распределяет IP-адреса, строит mesh-маршрутизацию и обеспечивает отказоустойчивость. При выходе узла из строя трафик перенаправляется на работающие реплики сервиса. Шифрование IPSec включается опционально флагом --opt encrypted и снижает пропускную способность на 10-20%.

Overlay избыточен, если все контейнеры работают на одном хосте. Для одиночного сервера достаточно bridge. Альтернативные решения - Weave, Calico - нужны при интеграции с Kubernetes или требованиях к сетевой политике за пределами возможностей Swarm.

Macvlan-сеть: контейнер как физическое устройство в сети

Macvlan назначает контейнеру собственный MAC-адрес и IP из физической сети. С точки зрения коммутатора и DHCP-сервера контейнер выглядит как отдельное физическое устройство. Это решает задачи устаревших приложений, требующих L2-связности, широковещательного трафика или прямой видимости в корпоративной сети.

Два режима работы: bridge (контейнеры на одном хосте видят друг друга через физический коммутатор) и 802.1q trunk (каждый VLAN - отдельный подынтерфейс). Ключевое ограничение macvlan: контейнер не может общаться с хостом напрямую. Это ограничение ядра Linux, обход - создание дополнительного macvlan-интерфейса на хосте.

Практикум: связываем контейнеры на одном хосте

Типовая задача: веб-сервер Nginx должен проксировать запросы к бэкенду на Node.js. Оба контейнера на одном хосте. Решение - кастомная bridge-сеть с DNS-резолвингом.

Создание кастомной bridge-сети и подключение контейнеров

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

docker network create \
  --driver bridge \
  --subnet=10.10.0.0/24 \
  --gateway=10.10.0.1 \
  --ip-range=10.10.0.128/25 \
  app-network

Параметр --ip-range ограничивает пул автоматически назначаемых адресов. Это оставляет первую половину подсети для статического назначения. Запускаем контейнеры:

docker run -d --name backend --network app-network --ip 10.10.0.10 node:18-alpine

docker run -d --name frontend --network app-network --ip 10.10.0.20 nginx:alpine

Проверяем назначенные адреса:

docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' backend
# 10.10.0.10

DNS-резолвинг в Docker: как контейнеры находят друг друга по имени

В кастомной сети каждый контейнер получает DNS-запись с именем, равным имени контейнера. Встроенный DNS-сервер слушает 127.0.0.11:53 внутри контейнера. Проверяем:

docker exec frontend ping backend
# PING backend (10.10.0.10): 56 data bytes
# 64 bytes from 10.10.0.10: seq=0 ttl=64 time=0.089 ms

Network alias дает дополнительные имена для одного контейнера. Полезно при сине-зеленых деплоях или миграции сервисов:

docker run -d --name backend-v2 --network app-network --network-alias api,backend-alias node:18-alpine

Теперь контейнер backend-v2 доступен по именам api и backend-alias. DNS-записи обновляются автоматически при перезапуске контейнера.

В дефолтной bridge-сети DNS-резолвинг не работает. Команда ping backend вернет ошибку разрешения имени. Это частая причина, по которой новички не могут связать контейнеры - они используют сеть по умолчанию.

Доступ к контейнерам извне: проброс портов и host-сеть

Контейнер в bridge-сети изолирован за NAT. Чтобы сервис был доступен с хоста или из внешней сети, нужен проброс портов или переход на host-сеть.

Как работает проброс портов: docker-proxy и iptables

При запуске контейнера с флагом -p 8080:80 Docker создает два механизма трансляции: правило iptables DNAT и процесс docker-proxy. Схема прохождения пакета:

  1. Внешний запрос приходит на порт 8080 хоста.
  2. iptables перехватывает пакет и меняет адрес назначения на IP контейнера и порт 80.
  3. docker-proxy (userland) слушает 0.0.0.0:8080 и проксирует трафик в контейнер.

Двойной механизм - историческая причина. Docker-proxy работал всегда, iptables добавили позже. На современных ядрах (5.x+) docker-proxy можно отключить для повышения производительности:

# В /etc/docker/daemon.json
{
  "userland-proxy": false
}

После перезапуска Docker трафик пойдет только через iptables (hairpin NAT). Это снижает задержку на 0.1-0.3 мс и убирает лишний процесс. Обратная сторона: hairpin NAT не работает на некоторых старых ядрах, и контейнер не сможет обратиться к самому себе через публичный IP хоста.

Синтаксис проброса:

# Проброс на всех интерфейсах
-p 8080:80

# Проброс только на localhost
-p 127.0.0.1:8080:80

# Проброс диапазона портов
-p 8080-8090:80-90

# Явное указание протокола
-p 8080:80/tcp
-p 53:53/udp

Host-сеть для максимальной производительности: когда и как

Запуск контейнера в host-сети отключает сетевую изоляцию полностью:

docker run --rm --network host alpine ip addr show
# Вывод покажет все интерфейсы хоста: eth0, lo, docker0 и другие

Контейнер слушает порт напрямую на интерфейсе хоста. Никакого проброса, никакой трансляции. Это критично для UDP-сервисов (DNS, игровые серверы, VoIP), где NAT может терять сессии. Высоконагруженный Nginx на 50 000 одновременных соединений в host-сети показывает пропускную способность на 12-18% выше, чем в bridge с пробросом.

Главное предупреждение: нельзя запустить два контейнера в host-сети, слушающих один порт. Docker не выдаст ошибку - второй контейнер просто не сможет занять порт и упадет. Планируйте порты заранее.

Мультихостовые сети: overlay в Docker Swarm

Когда контейнеры разнесены по разным серверам, bridge и host не работают. Overlay-сеть в Docker Swarm решает эту задачу.

Создание overlay-сети и деплой сервисов

Инициализируем Swarm на первом узле и добавляем остальные:

# На manager-узле
docker swarm init --advertise-addr 192.168.1.10

# На worker-узлах выполняем команду из вывода init
docker swarm join --token SWMTKN-... 192.168.1.10:2377

Создаем overlay-сеть с флагом --attachable. Без него к сети можно подключать только сервисы Swarm, но не обычные контейнеры:

docker network create \
  --driver overlay \
  --attachable \
  --subnet=10.20.0.0/24 \
  cluster-network

Деплоим сервис с несколькими репликами:

docker service create \
  --name web \
  --network cluster-network \
  --replicas 3 \
  --publish published=8080,target=80 \
  nginx:alpine

Swarm автоматически распределяет реплики по узлам. Ingress-сеть маршрутизирует внешние запросы на любой узел кластера, даже если на нем нет активной реплики сервиса. Это mesh-маршрутизация: порт 8080 слушают все узлы Swarm и проксируют трафик к нужному контейнеру.

Проверяем связь между контейнерами на разных узлах:

docker exec -it $(docker ps -q --filter name=web.1) ping web.2
# Имя сервиса разрешается в IP конкретной реплики через встроенный DNS

Шифрование трафика в overlay-сетях

По умолчанию трафик VXLAN между узлами не шифруется. Для production-сред с чувствительными данными включайте IPSec:

docker network create \
  --driver overlay \
  --attachable \
  --opt encrypted \
  secure-overlay

Шифрование добавляет накладные расходы на установку туннелей и шифрование пакетов. Тесты показывают падение пропускной способности на 10-20% и рост задержки на 0.2-0.5 мс. Для внутреннего трафика в доверенной сети шифрование часто избыточно.

Продвинутые сценарии: macvlan и ручная маршрутизация

Стандартные драйверы покрывают 90% задач. Оставшиеся 10% требуют macvlan или ручной настройки маршрутов между изолированными сетями.

Macvlan: прямой выход контейнера в локальную сеть

Создаем macvlan-сеть, привязанную к физическому интерфейсу eth0. Контейнеры получат IP из той же подсети, что и хост:

docker network create \
  --driver macvlan \
  --subnet=192.168.1.0/24 \
  --gateway=192.168.1.1 \
  --ip-range=192.168.1.240/28 \
  -o parent=eth0 \
  macvlan-net

Запускаем контейнер с явным IP из диапазона, не занятого DHCP-сервером:

docker run -d --name legacy-app --network macvlan-net --ip 192.168.1.250 nginx:alpine

Контейнер доступен из локальной сети по IP 192.168.1.250. DHCP-сервер сети может выдать ему адрес, если не указывать --ip. Ограничение: с хоста этот контейнер недоступен. Пинг с хоста на 192.168.1.250 не пройдет. Обходной путь - создать macvlan-подинтерфейс на хосте:

ip link add macvlan0 link eth0 type macvlan mode bridge
ip addr add 192.168.1.251/24 dev macvlan0
ip link set macvlan0 up

Теперь хост видит контейнер через этот интерфейс.

Ручная маршрутизация между bridge-сетями

Две bridge-сети изолированы друг от друга. Контейнеры в сети frontend не видят контейнеры в сети backend. Решение - контейнер-маршрутизатор с интерфейсами в обеих сетях и включенным IP forwarding.

# Создаем две изолированные сети
docker network create --subnet=10.30.0.0/24 frontend
docker network create --subnet=10.40.0.0/24 backend

# Запускаем маршрутизатор
docker run -d --name router \
  --network frontend --ip 10.30.0.254 \
  --cap-add NET_ADMIN \
  alpine \
  sh -c "sysctl -w net.ipv4.ip_forward=1 && tail -f /dev/null"

# Подключаем второй интерфейс
docker network connect --ip 10.40.0.254 backend router

# Добавляем статические маршруты на контейнерах
docker exec backend-container ip route add 10.30.0.0/24 via 10.40.0.254
docker exec frontend-container ip route add 10.40.0.0/24 via 10.30.0.254

Альтернатива - docker network connect для подключения одного контейнера к нескольким сетям. Это проще, но нарушает изоляцию: контейнер становится мостом между сетями.

Сравнение производительности драйверов через iperf3 на сервере с 10 Гбит/с интерфейсом:

Драйвер Пропускная способность Задержка Потери
host 9.41 Гбит/с 0.05 мс 0%
bridge (userland-proxy=true) 8.12 Гбит/с 0.18 мс 0%
bridge (userland-proxy=false) 8.95 Гбит/с 0.09 мс 0%
macvlan 9.38 Гбит/с 0.06 мс 0%
overlay (без шифрования) 7.84 Гбит/с 0.32 мс 0%
overlay (с IPSec) 6.51 Гбит/с 0.48 мс 0%

Цифры показывают: host и macvlan практически не уступают нативной производительности. Bridge с отключенным docker-proxy приближается к ним. Overlay теряет 15-30% из-за инкапсуляции VXLAN.

Диагностика и решение типовых проблем с сетью Docker

Сеть не работает - самая частая жалоба после настройки Docker. Системный подход к диагностике экономит часы.

Проверка сетевой связности: инструменты и подходы

Алгоритм диагностики - четыре шага от нижнего уровня к верхнему:

  1. IP-адресация. Проверьте, что контейнер получил IP: docker inspect -f '{{.NetworkSettings.Networks.ИМЯ_СЕТИ.IPAddress}}' ИМЯ_КОНТЕЙНЕРА. Отсутствие IP означает, что контейнер не подключен к сети.
  2. Маршруты. Внутри контейнера выполните ip route. Таблица должна содержать маршрут по умолчанию через шлюз сети.
  3. DNS. Проверьте разрешение имен: docker exec ИМЯ nslookup tasks.ИМЯ_СЕРВИСА или ping ИМЯ_КОНТЕЙНЕРА. Ошибка разрешения указывает на использование дефолтной сети или проблемы со встроенным DNS.
  4. iptables. На хосте выполните iptables -L -n -t nat | grep ПОРТ. Отсутствие правил DNAT для проброшенного порта означает, что docker-proxy не работает или порт занят.

Распространенные ошибки и их исправление

1. Контейнеры не видят друг друга по имени. Симптом: ping по IP работает, по имени - нет. Причина: используется дефолтная bridge-сеть. Решение: создайте кастомную сеть и переподключите контейнеры.

2. Проброс портов не работает. Симптом: сервис недоступен снаружи, хотя контейнер запущен. Причина: конфликт с firewalld или ufw. Решение: проверьте iptables -L DOCKER -n и добавьте правила в файрвол или временно отключите его для теста.

3. Overlay-сеть не соединяет узлы. Симптом: контейнеры на разных хостах не пингуются. Причина: забыт флаг --attachable при создании сети или заблокированы порты 2377/tcp, 7946/tcp+udp, 4789/udp между узлами. Решение: проверьте файрвол и пересоздайте сеть с --attachable.

4. Медленная сеть в bridge. Симптом: задержка выше ожидаемой. Причина: включен docker-proxy. Решение: отключите userland-proxy в daemon.json и перезапустите Docker.

5. Контейнер в macvlan не видит хост. Симптом: пинг с контейнера на IP хоста не проходит. Причина: ограничение ядра Linux, macvlan не маршрутизирует трафик между родительским интерфейсом и виртуальными. Решение: создайте macvlan-подинтерфейс на хосте, как показано в разделе выше.

Заключение: проектирование надежной сети для контейнеров

Выбор сетевого драйвера Docker сводится к трем вопросам. Контейнеры на одном хосте? Берите кастомную bridge-сеть - она дает DNS-резолвинг и изоляцию. Нужна максимальная производительность без изоляции? Используйте host. Контейнеры разнесены по серверам? Overlay в Docker Swarm с шифрованием для чувствительных данных. Особые требования к L2-связности? Macvlan решает задачу прямого подключения к физической сети.

Чек-лист для production-развертывания:

  • Создавайте кастомные сети, не полагайтесь на дефолтную bridge.
  • Отключайте docker-proxy для высоконагруженных сервисов.
  • Планируйте IP-адресацию через --subnet и --ip-range, избегайте конфликтов.
  • Включайте шифрование overlay-сетей только при передаче данных через недоверенные каналы.
  • Документируйте сетевую топологию: какие сети, какие порты проброшены, какие зависимости между сервисами.

Детальный разбор продвинутых сценариев - статические IP в Compose, прямая маршрутизация с хоста и профессиональная диагностика - доступен в руководстве по продвинутой маршрутизации в Docker и Compose. Сравнение драйверов с фокусом на микросервисы и интеграцию с Kubernetes разобрано в полном руководстве по сетевым драйверам Docker 2026. Для развертывания контейнеров в production-среде с гарантированной производительностью сети используйте облачную инфраструктуру Timeweb Cloud с масштабируемыми VDS и поддержкой Kubernetes.

Поделиться:
Сохранить гайд? В закладки браузера