Введение: когда стандартного bridge недостаточно
Стандартная bridge-сеть Docker решает базовую задачу: контейнеры на одном хосте видят друг друга, а наружу смотрят через NAT. Хост пробрасывает порты, трансляция адресов скрывает внутреннюю кухню. Это удобно для разработки и простых стендов, но в production-сценариях модель упирается в потолок.
Три типичные ситуации, где bridge перестаёт справляться:
- Контейнер должен выглядеть как полноценный узел физической сети - со своим IP, MAC-адресом, без проброса портов. Например, когда вы переносите legacy-сервис в контейнер, а остальная инфраструктура должна обращаться к нему напрямую.
- Среда накладывает ограничения: Wi-Fi-подключение хоста, политика безопасности порта на коммутаторе, облачный провайдер с лимитом MAC-адресов. Bridge здесь не помощник, нужен другой механизм.
- Контейнеры разнесены по разным физическим хостам и должны общаться в общей изолированной сети, как будто они на одной машине. Микросервисная архитектура в чистом виде.
Под эти задачи Docker предлагает три специализированных драйвера: macvlan, ipvlan и overlay. Они закрывают сценарии прямой интеграции в физическую сеть, обхода инфраструктурных ограничений и построения мультихостовых сетей. Ниже - детальный разбор каждого с пошаговыми инструкциями, которые вы сможете применить сразу.
Если вы проектируете сетевую инфраструктуру для production-кластера, рекомендую также изучить руководство по выбору сетевых драйверов под высокие нагрузки - там разобрана интеграция с Kubernetes, CNI-плагинами и оптимизация для 50k+ подключений.
Обзор сетевых драйверов Docker: macvlan, ipvlan и overlay
Каждый из трёх драйверов решает свой класс задач. Принципиальная разница - в способе взаимодействия контейнера с сетевым стеком хоста и внешней инфраструктурой. Разберём механику, сильные стороны и ограничения.
macvlan: контейнер как физическое устройство в вашей сети
Драйвер macvlan назначает контейнеру собственный MAC-адрес и IP из подсети родительского интерфейса хоста. С точки зрения коммутатора и других устройств в сети контейнер выглядит как отдельная физическая машина. Никакого NAT, никакого проброса портов - трафик идёт напрямую.
macvlan работает в трёх режимах:
- Bridge - контейнеры в одной macvlan-сети видят друг друга через родительский интерфейс, трафик между ними коммутируется на уровне ядра.
- Private - полная изоляция: контейнеры не могут общаться друг с другом, только с внешней сетью. Подходит для сценариев с жёсткими требованиями безопасности.
- Passthru - прямой доступ к физическому интерфейсу, используется редко, в основном для случаев, когда нужно отдать контейнеру эксклюзивный контроль над сетевым адаптером.
Типичный пример: запуск веб-сервера в контейнере, который получает IP 192.168.1.100 из локальной сети офиса. Любой сотрудник открывает этот адрес в браузере без настройки port forwarding на хосте. Контейнер становится полноправным участником сети.
Ключевое ограничение: macvlan не работает, если хост подключен через Wi-Fi. Большинство точек доступа и драйверов беспроводных сетей блокируют фреймы с чужими MAC-адресами. Подробнее об этой проблеме и путях обхода - в разделе про ipvlan.
ipvlan: решение для сред с ограничениями по MAC-адресам
ipvlan использует общий MAC-адрес родительского интерфейса для всех контейнеров. Каждый контейнер получает уникальный IP, но на уровне L2 все фреймы идут с одним и тем же MAC. Это решает проблему сред, где нельзя плодить MAC-адреса: Wi-Fi-сети, облачные платформы с политиками безопасности портов, коммутаторы с ограничением числа MAC на порт.
Два режима работы:
- L2 (бриджевый) - контейнеры находятся в одной подсети с хостом, работают как bridge. Хост изолирован от контейнеров на уровне ядра - напрямую пинг не пройдёт. Требуется создание дочернего ipvlan-интерфейса на хосте для связи.
- L3 (маршрутизируемый) - контейнеры получают отдельную подсеть, хост выступает маршрутизатором между ней и внешней сетью. На внешних устройствах нужно прописать статический маршрут к подсети контейнеров через IP хоста.
Преимущество ipvlan: работает там, где macvlan блокируется. Недостаток: в L2-режиме связь хост-контейнер требует дополнительной настройки, в L3-режиме - изменения маршрутизации на внешнем оборудовании. Выбор между macvlan и ipvlan сводится к одному вопросу: разрешено ли в вашей сети появление дополнительных MAC-адресов. Если нет - ipvlan.
Практическое сравнение двух драйверов с готовыми конфигурациями docker-compose и таблицей выбора под конкретные сценарии смотрите в статье Macvlan и IPvlan в Docker: интеграция в корпоративную сеть.
overlay: мультихостовые сети для Docker Swarm
Overlay-драйвер создаёт виртуальную сеть поверх физической инфраструктуры с помощью VXLAN-туннелей. Контейнеры на разных хостах общаются так, будто подключены к одному коммутатору. Трафик инкапсулируется в UDP-пакеты и передаётся между узлами кластера.
Обязательное условие: Docker Swarm. Overlay-сеть разворачивается поверх swarm-кластера, который управляет обнаружением узлов и распределением трафика. Без swarm overlay не работает.
Ключевые возможности:
- Прозрачная связность контейнеров на разных хостах в рамках одной подсети.
- Встроенное шифрование трафика (опция
--opt encrypted), использующее IPsec. Требует установки пакета ipsec-tools на всех узлах. - Поддержка как сервисов Swarm, так и обычных контейнеров (с флагом
--attachable).
Типичный сценарий: микросервисное приложение, где frontend, backend и база данных разнесены по трём хостам, но должны общаться по внутренним IP в общей сети 10.0.0.0/24. Overlay даёт эту связность без ручной настройки VPN или сложной маршрутизации.
Детальный разбор архитектуры bridge, host и overlay-драйверов, включая таблицы маршрутизации и диагностику проблем доступности, - в руководстве по сетевой архитектуре Docker.
Пошаговая настройка macvlan: интеграция контейнера в физическую сеть
Переходим к практике. Задача: контейнер должен получить IP из физической сети 192.168.1.0/24 и быть доступным для всех устройств в этой сети без проброса портов.
Предварительные требования:
- Определите родительский интерфейс хоста:
ip link show- обычно это eth0, enp0s3 или ens18. - Узнайте подсеть и шлюз:
ip route | grep default. - Выберите IP для контейнера вне DHCP-пула, чтобы избежать конфликтов.
Создаём macvlan-сеть:
docker network create \
-d macvlan \
--subnet=192.168.1.0/24 \
--gateway=192.168.1.1 \
--ip-range=192.168.1.224/27 \
-o parent=eth0 \
macnet
Флаг --ip-range ограничивает пул адресов, которые Docker будет назначать автоматически. Это страховка от пересечения с DHCP-сервером. Если планируете назначать IP только вручную, диапазон можно не указывать.
Назначение статического IP-адреса контейнеру
Запускаем контейнер с явным указанием IP:
docker run -d \
--name web01 \
--network macnet \
--ip=192.168.1.100 \
nginx:alpine
IP должен быть из подсети macvlan-сети и не входить в DHCP-пул вашего роутера. Проверяем: с любой машины в сети выполняем ping 192.168.1.100 - ответ идёт от контейнера.
Для docker-compose конфигурация выглядит так:
services:
web:
image: nginx:alpine
networks:
macnet:
ipv4_address: 192.168.1.100
networks:
macnet:
driver: macvlan
driver_opts:
parent: eth0
ipam:
config:
- subnet: 192.168.1.0/24
gateway: 192.168.1.1
Важный нюанс: статический IP через --ip работает только для пользовательских сетей. Встроенная bridge-сеть этого не поддерживает.
Решение проблемы связи между хостом и контейнерами macvlan
После настройки macvlan вы обнаружите: контейнеры пингуют внешний мир, внешние устройства пингуют контейнеры, но хост не может достучаться до собственных контейнеров. Это не баг, а особенность архитектуры Linux: macvlan изолирует трафик между родительским интерфейсом и дочерними виртуальными интерфейсами на уровне ядра.
Решение: создать на хосте дочерний macvlan-интерфейс с IP из той же подсети. Через него хост будет общаться с контейнерами:
ip link add macvlan0 link eth0 type macvlan mode bridge
ip addr add 192.168.1.200/24 dev macvlan0
ip link set macvlan0 up
После этого ping 192.168.1.100 с хоста работает. Интерфейс macvlan0 существует до перезагрузки. Для постоянной конфигурации добавьте правила в systemd-networkd или /etc/network/interfaces в зависимости от вашего дистрибутива.
Настройка ipvlan: когда macvlan недоступен
Сценарий: хост подключен через Wi-Fi (интерфейс wlan0), macvlan не поднимается - точка доступа отбрасывает фреймы с чужими MAC. Или облачный провайдер разрешает только один MAC на виртуальную машину. Переходим на ipvlan.
Создаём ipvlan-сеть в режиме L2:
docker network create \
-d ipvlan \
--subnet=192.168.1.0/24 \
--gateway=192.168.1.1 \
-o parent=wlan0 \
-o ipvlan_mode=l2 \
ipvnet
Запускаем контейнер:
docker run -d \
--name app01 \
--network ipvnet \
--ip=192.168.1.101 \
nginx:alpine
Контейнер доступен из внешней сети, но хост его не видит - та же проблема изоляции, что и с macvlan. Решается аналогично: создаём ipvlan-интерфейс на хосте:
ip link add ipvlan0 link wlan0 type ipvlan mode l2
ip addr add 192.168.1.201/24 dev ipvlan0
ip link set ipvlan0 up
Режим L2 vs L3 в ipvlan: выбор под задачу
L2-режим подходит, когда контейнеры должны сидеть в одной подсети с хостом и внешними устройствами. Минимум изменений в инфраструктуре, но хост изолирован (лечится дочерним интерфейсом, как показано выше).
L3-режим нужен, когда вы хотите вынести контейнеры в отдельную подсеть и управлять маршрутизацией на уровне хоста. Контейнеры получают адреса из диапазона, отличного от подсети хоста. Хост автоматически становится маршрутизатором между этой подсетью и внешней сетью.
Создание L3-сети:
docker network create \
-d ipvlan \
--subnet=10.0.1.0/24 \
-o parent=eth0 \
-o ipvlan_mode=l3 \
ipvnet-l3
Контейнеры получат адреса из 10.0.1.0/24. Чтобы внешние устройства могли до них достучаться, на роутере или других хостах нужно прописать маршрут: ip route add 10.0.1.0/24 via 192.168.1.10, где 192.168.1.10 - IP хоста Docker. L3-режим даёт чистую изоляцию и гибкость, но требует прав на сетевом оборудовании.
Overlay-сети в Docker Swarm: связь контейнеров на разных хостах
Задача: три хоста, на каждом - часть микросервисного приложения. Нужна общая внутренняя сеть, чтобы сервисы видели друг друга по IP, независимо от того, на каком узле они запущены.
Требования к инфраструктуре:
- Открытые порты между хостами: TCP 2377 (управление swarm), TCP/UDP 7946 (обнаружение узлов), UDP 4789 (VXLAN-трафик).
- Docker Engine на всех узлах одной версии (рекомендуется 24+).
Инициализируем swarm на первом хосте:
docker swarm init --advertise-addr 192.168.1.10
Команда выведет токен для присоединения воркеров. На остальных хостах выполняем:
docker swarm join --token SWMTKN-... 192.168.1.10:2377
Создаём overlay-сеть с возможностью подключения обычных контейнеров:
docker network create \
-d overlay \
--attachable \
--subnet=10.0.0.0/24 \
my-overlay
Флаг --attachable разрешает подключать к сети не только сервисы Swarm, но и контейнеры, запущенные через docker run. Без него сеть доступна только для docker service create.
Запускаем контейнеры на разных хостах:
# Хост 1
docker run -d --name backend --network my-overlay --ip=10.0.0.10 nginx:alpine
# Хост 2
docker run -d --name frontend --network my-overlay --ip=10.0.0.20 nginx:alpine
Проверяем связность: на хосте 2 выполняем docker exec frontend ping 10.0.0.10. Пакеты идут через VXLAN-туннель, контейнеры видят друг друга как в одной локальной сети.
Шифрование трафика в overlay-сетях
По умолчанию VXLAN-трафик между хостами идёт открытым текстом. Для защиты данных создаём сеть с шифрованием:
docker network create \
-d overlay \
--attachable \
--opt encrypted \
--subnet=10.0.1.0/24 \
secure-overlay
Обязательное условие: на всех узлах swarm должен быть установлен пакет ipsec-tools (или strongswan для некоторых дистрибутивов). Docker использует IPsec ESP для шифрования полезной нагрузки VXLAN-пакетов. Проверить, что трафик действительно шифруется, можно через tcpdump: в дампе не должно быть читаемой полезной нагрузки.
Предупреждение: шифрование создаёт дополнительную нагрузку на CPU. Для внутренних сетей в доверенном дата-центре его часто отключают в пользу производительности. В распределённых системах, где трафик идёт через публичные каналы, шифрование обязательно.
Сравнение драйверов и критерии выбора
Выбор драйвера сводится к трём вопросам. Ответьте на них последовательно - получите однозначную рекомендацию.
Вопрос 1: контейнер должен быть доступен из физической сети без NAT и проброса портов?
Если да - macvlan или ipvlan. Если нет и достаточно bridge с пробросом портов - остаётесь на стандартном драйвере.
Вопрос 2: среда разрешает множественные MAC-адреса на порту?
Если да - macvlan. Это производительнее и проще в настройке. Если нет (Wi-Fi, облачные провайдеры, строгие политики коммутатора) - ipvlan.
Вопрос 3: контейнеры разнесены по разным хостам и должны быть в общей изолированной сети?
Если да - overlay. Требует Docker Swarm, но даёт прозрачную мультихостовую связность.
| Критерий | macvlan | ipvlan | overlay |
|---|---|---|---|
| Связь хост-контейнер по умолчанию | Нет | Нет | Да |
| Работа через Wi-Fi | Нет | Да | Да (поверх сети хоста) |
| Мультихостовая сеть | Нет | Нет | Да |
| Изоляция от хоста | Полная (L2) | Полная (L2) | Частичная (сеть виртуальная) |
| Производительность | Высокая (почти нативная) | Высокая | Средняя (накладные расходы VXLAN) |
| Требования к инфраструктуре | Поддержка нескольких MAC на порту | Нет особых требований | Swarm, открытые порты 2377/7946/4789 |
Драйверы можно комбинировать. Например, на хосте одновременно работают macvlan-сеть для сервисов, требующих прямого доступа из физической сети, и overlay-сеть для внутреннего взаимодействия микросервисов в swarm. Docker допускает подключение контейнера к нескольким сетям одновременно.
Типичные проблемы и их решение
За годы работы с Docker-сетями я собрал список проблем, с которыми сталкиваются администраторы. Вот решения, которые работают.
Проблема 1: macvlan не работает на Wi-Fi. Контейнеры не получают IP или не видят сеть.
Причина: драйвер беспроводного адаптера или точка доступа блокирует фреймы с MAC-адресами, отличными от MAC хоста. Решение: использовать ipvlan, который работает с одним MAC. Команды для перехода - в разделе про ipvlan выше.
Проблема 2: хост не пингует контейнеры в macvlan/ipvlan. Внешние устройства контейнеры видят, хост - нет.
Причина: изоляция на уровне ядра Linux между родительским и дочерними интерфейсами. Решение: создать на хосте дочерний macvlan/ipvlan-интерфейс с IP из той же подсети. Команды приведены в соответствующих разделах.
Проблема 3: контейнеры в overlay не видят друг друга. Пинг не проходит, сервисы не соединяются.
Причины и решения:
- Закрыты порты 7946 (TCP/UDP) и 4789 (UDP) на фаерволе между хостами - открыть.
- Разные версии Docker на узлах swarm - привести к одной мажорной версии.
- Неправильно указан --advertise-addr при инициализации swarm - переинициализировать с корректным IP.
Проблема 4: конфликт IP-адресов в macvlan/ipvlan. Контейнер получает адрес, уже занятый другим устройством в сети.
Причина: DHCP-сервер не знает о статических назначениях Docker. Решение: использовать --ip-range при создании сети, чтобы ограничить пул Docker вне DHCP-диапазона. Либо назначать IP вручную через --ip, выбирая адреса из зарезервированного диапазона, исключённого из DHCP.
Для углублённого изучения безопасности и оптимизации контейнерных сред рекомендую практический гайд по продвинутому Docker - там разобраны сканирование CVE, отказ от root-привилегий и тонкая настройка cgroups для production-нагрузок.
Если вы разворачиваете контейнеры в облаке, обратите внимание на Timeweb Cloud - облачную инфраструктуру с VDS, управляемыми базами данных и Kubernetes. Провайдер не накладывает ограничений на количество MAC-адресов, что упрощает работу с macvlan.