Docker network: bridge, host, overlay — типы сетей
Контейнер запустился, а порт не пробрасывается, или два контейнера на разных серверах не видят друг друга — почти всегда причина в том, что выбран не тот сетевой драйвер. Docker предлагает четыре принципиально разных способа организовать сеть, и они решают разные задачи: один изолирует контейнер, другой убирает изоляцию ради скорости, третий соединяет хосты в кластер. Разберём каждый — с командами и конкретными сценариями, когда его стоит применять.
Содержание
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Как Docker вообще управляет сетью
Когда вы устанавливаете Docker, он создаёт виртуальный сетевой мост docker0 на хосте и подключает к нему каждый новый контейнер через отдельный veth-интерфейс — по сути, виртуальный сетевой кабель. Контейнер получает свой IP из приватного диапазона, свой network namespace (изолированное сетевое пространство ядра) и по умолчанию видит только то, что ему разрешили.
Посмотреть, какие сети уже есть на хосте:
docker network ls
Обычно там три системные сети: bridge, host, none — они появляются сразу после установки, ничего создавать не нужно. Overlay-сети — исключение, они требуют Docker Swarm или отдельной настройки.
Посмотреть детали конкретной сети — какие контейнеры подключены, какая подсеть, какой шлюз:
docker network inspect bridge
Дальше — по каждому драйверу отдельно.
bridge — сеть по умолчанию для контейнеров на одном хосте
Это стандартный режим: если вы не указали --network явно, контейнер подключается к bridge. Все контейнеры на одном хосте, использующие эту сеть, получают IP из подсети 172.17.0.0/16 (или другой, в зависимости от конфигурации) и могут стучаться друг к другу по этим IP.
Проблема сети bridge по умолчанию в том, что контейнеры видят друг друга только по IP-адресу — DNS-резолвинг по именам контейнеров в ней не работает. Поэтому на практике почти всегда создают собственную bridge-сеть:
docker network create --driver bridge my-app-net
Внутри пользовательской bridge-сети Docker поднимает встроенный DNS: контейнеры видят друг друга по имени (или по алиасу из docker-compose.yml), а не только по IP. Именно поэтому в docker-compose.yml не нужно вручную прописывать IP базы данных — достаточно указать имя сервиса, например postgres:5432.
Порты наружу пробрасываются явно:
docker run -d --name web --network my-app-net -p 8080:80 nginx
Когда выбирать bridge. Это сценарий по умолчанию для 90% случаев: одиночный сервер с несколькими контейнерами (веб + база + кеш), которым нужна изоляция от хостовой сети и друг от друга, но с контролируемыми точками входа через -p. Если поднимаете стек через docker-compose.yml без явного указания network_mode, Compose сам создаёт для проекта отдельную bridge-сеть — это ровно то, что нужно для большинства приложений.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать VPShost — без изоляции, сеть хоста напрямую
В режиме host контейнер не получает собственный network namespace — он использует сетевой стек хоста напрямую. Порт, который слушает процесс внутри контейнера, доступен на IP хоста без проброса через -p:
docker run -d --network host nginx
Если nginx внутри слушает 80-й порт, он сразу доступен на http://<ip-хоста>:80 — без -p 80:80, и, что важно, эта опция здесь просто не сработает: -p в режиме host игнорируется, потому что порт и так открыт напрямую.
Плюс — минимальные накладные расходы: нет NAT, нет трансляции адресов, пакет идёт напрямую через сетевой стек ядра хоста. Для сетевых бенчмарков или высоконагруженных прокси это ощутимо. Минус — никакой изоляции портов: если у вас на хосте уже занят 80-й порт, контейнер в режиме host его не запустит, конфликт будет как между обычными процессами. И два контейнера с --network host не смогут слушать один и тот же порт одновременно.
Когда выбирать host. Есть три типичных сценария:
- Сетевые утилиты и мониторинг, которым нужно видеть трафик хоста как есть (например, агенты вроде
netdataв контейнере, снифферы). - Высоконагруженные прокси/балансировщики, где важна каждая доля миллисекунды и NAT — лишний слой.
- Ситуации, где контейнер использует широкий или заранее неизвестный диапазон портов (например, некоторые игровые серверы или VoIP-сервисы) — тогда проще открыть весь стек хоста, чем перечислять десятки
-p.
Если вы арендуете VPS специально под контейнеры с прямым доступом к сети хоста, важно, чтобы у провайдера не было дополнительных сетевых прослоек с непредсказуемыми задержками — тогда преимущество host в скорости действительно ощущается.
overlay — сеть между контейнерами на разных хостах
Это единственный драйвер из четырёх, который решает задачу не одного сервера, а кластера. Overlay-сеть инкапсулирует трафик между контейнерами в VXLAN-туннели поверх обычной IP-сети между хостами — так контейнеры на разных физических или виртуальных серверах видят друг друга напрямую, как будто они в одной локальной сети.
Работает только в контексте Docker Swarm. Сначала нужно инициализировать кластер:
docker swarm init --advertise-addr <ip-этого-сервера>
Команда выведет токен для присоединения других узлов — его нужно выполнить на каждом дополнительном сервере:
docker swarm join --token <токен> <ip-менеджера>:2377
После этого создаётся overlay-сеть:
docker network create --driver overlay --attachable my-overlay-net
Флаг --attachable разрешает подключать к сети не только сервисы Swarm, но и обычные контейнеры, запущенные через docker run — без него сеть доступна только сервисам, созданным через docker service create.
Пример сервиса, растянутого на несколько узлов и подключённого к overlay-сети:
docker service create --name api --network my-overlay-net --replicas 3 my-api-image
Три реплики могут оказаться на трёх разных серверах кластера, но благодаря overlay-сети они обращаются друг к другу и к другим сервисам по именам — Docker сам маршрутизирует трафик между узлами через VXLAN.
Когда выбирать overlay. Только если у вас действительно несколько физических или виртуальных серверов, объединённых в Docker Swarm (или аналогичный кластер), и контейнерам на разных машинах нужно общаться друг с другом напрямую — например, микросервисы, распределённые по узлам для отказоустойчивости, или воркеры очереди задач, разнесённые по нескольким VPS для распределения нагрузки. Если у вас один сервер — overlay не нужен, это usual bridge с лишними накладными расходами на инкапсуляцию VXLAN. Подробнее о частых проблемах Swarm-кластеров и их диагностике — в статье про ошибки Docker Swarm на сервере.
none — полная изоляция без сети
Самый простой драйвер: контейнер получает только loopback-интерфейс (lo), никакого внешнего сетевого доступа у него нет вообще — ни к другим контейнерам, ни к хосту, ни в интернет.
docker run --network none my-batch-job
Проверить, что сети действительно нет, можно изнутри контейнера — ip a покажет только lo.
Когда выбирать none. Это сценарий для задач, которым сеть в принципе не нужна и присутствие сети — риск, а не удобство:
- Пакетная обработка данных, которая читает файлы из смонтированного volume и пишет результат туда же, не обращаясь наружу.
- Запуск непроверенного или потенциально вредоносного кода в песочнице — если вредоносный процесс не может ничего слить по сети или получить команды с C2-сервера, риск ограничен.
- Тестирование и линтеры, у которых сетевой доступ — не часть контракта, а значит его отсутствие ловит скрытые зависимости (например, если тест внезапно пытается сходить в интернет вместо использования мока).
Сравнение драйверов
| Драйвер | Область действия | Изоляция портов | Типичный сценарий |
|---|---|---|---|
| bridge | один хост | есть, порты пробрасываются через -p | стандартный стек: веб + база + кеш на одном сервере |
| host | один хост | нет, сеть хоста напрямую | высокая производительность, сетевые утилиты, широкий диапазон портов |
| overlay | несколько хостов (Swarm) | есть, через сервисы и -p при публикации | кластер, микросервисы на разных серверах |
| none | контейнер полностью изолирован | сети нет вообще | пакетные задачи, песочницы, тесты без сети |
Если сомневаетесь, с чего начать — начинайте с пользовательской bridge-сети (docker network create), а не с bridge по умолчанию: DNS-резолвинг по именам контейнеров экономит массу времени на отладке и избавляет от захардкоженных IP в конфигах. К host переходите только когда измерили, что NAT реально даёт заметную просадку — в большинстве вебориентированных нагрузок разница не критична. К overlay — только когда контейнеры физически на разных серверах. Если контейнер не видит сеть или порт не пробрасывается на bridge-сети, разбор частых причин есть в статье нет доступа к сети из контейнера и в статье про непробрасываемые порты.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать VPSНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Можно ли переключить сеть у уже запущенного контейнера без пересоздания?
Да, частично: docker network connect <сеть> <контейнер> подключит контейнер к дополнительной сети на лету, а docker network disconnect отключит от текущей. Но сменить --network host на bridge (и наоборот) у работающего контейнера нельзя — это фиксируется при создании, нужен пересоздание контейнера с новым параметром.
Работает ли --network host на Windows и macOS?
Нет, только на Linux. На macOS и Windows Docker Desktop запускает Linux-VM под капотом, и режим host там либо не работает вовсе, либо ведёт себя иначе, чем на настоящем Linux-хосте. Если статья написана с прицелом на прод — держите это в уме, для боевых серверов актуален Linux VPS.
Чем overlay отличается от VPN между серверами?
По задаче — похоже, но overlay работает на уровне контейнеров и интегрирован в Docker Swarm: маршрутизация, service discovery и балансировка нагрузки между репликами настраиваются автоматически. Обычный VPN просто соединяет сети хостов, а маршрутизацию между контейнерами вам придётся настраивать вручную поверх него.
Нужен ли overlay, если контейнеры общаются через публичный интернет и открытые порты?
Нет, это альтернативный (и менее безопасный) вариант — трафик между контейнерами на разных хостах можно пустить и через обычные -p и публичные IP, но тогда он не шифруется и не изолирован от остального интернета. Overlay-сеть с включённым шифрованием (--opt encrypted при создании) решает это правильнее.
Почему docker-compose создаёт свою сеть, а не использует bridge по умолчанию?
Потому что так работает DNS между сервисами: Compose создаёт отдельную bridge-сеть для проекта именно для того, чтобы сервисы видели друг друга по именам из docker-compose.yml, а не по IP, которые могут меняться при перезапуске.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →