Сети в Docker: bridge, host и пользовательские сети
Основы3 минРедакция Innovialabs
Коротко
Контейнеры в одной пользовательской сети находят друг друга по имени сервиса, а наружу приложение доступно только через опубликованный порт (-p). Сеть host убирает изоляцию и нужна редко.
Как устроены сети в Docker
Каждый контейнер получает собственный сетевой стек: свой IP-адрес, свои порты, свой localhost. Docker связывает контейнеры между собой и с хостом через сетевые драйверы. В повседневной работе важны три варианта:
- bridge (по умолчанию) — виртуальная сеть внутри хоста. Контейнеры получают внутренние адреса, наружу выходят через NAT.
- пользовательская bridge-сеть — то же самое, но с встроенным DNS по имени контейнера и лучшей изоляцией. Это стандартный выбор.
- host — контейнер использует сетевой стек хоста напрямую, без изоляции и без публикации портов.
Есть и другие драйверы (none, overlay, macvlan), но они нужны для специальных задач: полной изоляции, кластеров или подключения контейнера напрямую в физическую сеть.
Публикация портов: как попасть в контейнер снаружи
Порт внутри контейнера по умолчанию недоступен с хоста и из интернета. Чтобы открыть его, порт нужно опубликовать:
docker run -d -p 8080:80 nginx
Запись читается как ХОСТ:КОНТЕЙНЕР: запросы на порт 8080 хоста попадают на порт 80 контейнера.
Важные детали:
-p 8080:80слушает на всех интерфейсах хоста, то есть порт может быть виден из интернета. Если сервис нужен только локально, используйте-p 127.0.0.1:8080:80.- Docker сам добавляет правила в firewall хоста, и они могут обходить настройки вроде
ufw. Не публикуйте порты баз данных без необходимости. EXPOSEв Dockerfile — это только документация, он не открывает порт.
DNS по имени сервиса
В пользовательской сети контейнеры обращаются друг к другу по имени, а не по IP. IP-адреса меняются при каждом пересоздании контейнера, имена — нет.
docker network create app-net
docker run -d --name db --network app-net postgres
docker run -d --name api --network app-net my-api
Теперь api подключается к базе по адресу db:5432. В стандартной сети bridge такой DNS не работает — это частая причина ошибки «не удаётся найти хост».
В Docker Compose пользовательская сеть создаётся автоматически, и имя сервиса из docker-compose.yml становится его DNS-именем:
services:
api:
build: .
ports:
- "8080:3000"
environment:
DATABASE_URL: postgres://user:pass@db:5432/app
db:
image: postgres:16
Обратите внимание: у db нет секции ports. Базе не нужно быть доступной снаружи — api достаёт до неё по внутренней сети.
Сравнение режимов
| Режим | Изоляция | DNS по имени | Нужен -p | Когда использовать |
|---|---|---|---|---|
| bridge по умолчанию | есть | нет | да | быстрые эксперименты |
| пользовательский bridge | есть | да | да, для доступа снаружи | почти всегда |
| host | нет | — | нет | особые случаи с производительностью сети, только Linux |
| none | полная | — | — | задачи без сети |
Частые ошибки
localhostвнутри контейнера. Для контейнераlocalhost— это он сам, а не хост и не соседний контейнер. Обращайтесь к соседям по имени сервиса.- Приложение слушает 127.0.0.1. Если сервер внутри контейнера привязан к
127.0.0.1, опубликованный порт не сработает. Слушайте0.0.0.0. - Перепутаны порты в
-p. Слева порт хоста, справа — контейнера. - Порт уже занят на хосте. Docker не запустит контейнер, если порт хоста используется другим процессом.
- Контейнеры в разных сетях. Сервисы из разных Compose-проектов по умолчанию не видят друг друга. Подключите их к общей внешней сети.
- Открытая наружу база данных. Публикация
5432или3306на всех интерфейсах — прямой риск безопасности.
Как проверить связь
docker network ls— список сетей.docker network inspect app-net— какие контейнеры подключены и их адреса.docker exec -it api sh, затемping dbилиnc -zv db 5432(если утилиты есть в образе) — проверка доступности изнутри.docker port api— какие порты опубликованы.
Подробности по драйверам есть в официальной документации Docker.