Урок 7. Сети контейнеров
Реальные сервисы редко живут поодиночке: сайту нужна база данных, базе — панель управления, всем вместе — обратный прокси (веб-сервер, который принимает запросы снаружи и передаёт их нужному сервису). В этом уроке — как контейнеры находят друг друга и почему базе данных не нужен опубликованный порт.
Сети по умолчанию
Docker сразу создаёт три сети:
docker network ls- bridge — сеть по умолчанию. На хосте ей соответствует виртуальный интерфейс
docker0, контейнеры получают адреса вида172.17.0.2. Через неё контейнеры выходят в интернет; - host — контейнер без своей сети, прямо в сети хоста;
- none — сети нет совсем.
Контейнеры в сети bridge могут связаться друг с другом только по IP-адресу, а адрес меняется при каждом пересоздании контейнера. По имени они друг друга в этой сети не находят. Поэтому для своих сервисов создают свою сеть.
Своя сеть
Если контейнеры web и db из прошлых уроков ещё есть, удалите их, чтобы имена не мешали: docker rm -f web db (тома при этом останутся).
docker network create appnet
docker run -d --name web --network appnet nginx:alpine
docker run --rm --network appnet alpine wget -qO- http://web | grep titleПоследняя команда запускает одноразовый контейнер в той же сети и запрашивает страницу у контейнера web — по имени:
<title>Welcome to nginx!</title>В своей сети у Docker работает встроенный DNS (служба, которая по имени находит адрес): имя контейнера — это его адрес в сети. Адрес может меняться, имя — нет. Контейнеры в разных сетях друг друга не видят.
Подключить к сети уже работающий контейнер — например, site из урока о томах — и отключить его:
docker network connect appnet site
docker network disconnect appnet siteКонтейнер может состоять в нескольких сетях сразу — так, например, обратный прокси видит и сайты, и внешний мир, а базы данных сидят в отдельной сети только с теми, кому они нужны.
Порт внутри сети и порт снаружи
Внутри общей сети контейнеры обращаются друг к другу на порт программы, а не на опубликованный порт хоста. Пример — PostgreSQL и сайт в одной сети:
docker run -d --name db --network appnet -e POSTGRES_PASSWORD=Smena-Parol-2026 -v pgdata:/var/lib/postgresql postgres:18Сайт в сети appnet подключается к базе по адресу db:5432. Ключ -p для этого не нужен: он открывает порт для хоста и внешнего мира. Сайту порт публикуют, базе — нет.
Опубликованный порт базы (-p 5432:5432) виден всем, кто может достучаться до сервера, и Docker открывает его в обход ufw. Если базе не нужны подключения снаружи, не публикуйте её порт: внутри сети Docker она доступна и так. Если нужны с самого хоста — -p 127.0.0.1:5432:5432.
localhost внутри контейнера
Внутри контейнера localhost и 127.0.0.1 — это сам контейнер, а не хост и не соседний контейнер. Частая ошибка: в настройках сайта написано «база на localhost», а база — в другом контейнере. Нужно имя контейнера базы: db.
Если программе в контейнере нужна служба, запущенная прямо на хосте, есть особое имя host.docker.internal. В Docker Desktop оно работает само, на Linux его включают при запуске:
docker run --rm --add-host host.docker.internal:host-gateway alpine ping -c 2 host.docker.internalСлужба на хосте при этом должна слушать не только 127.0.0.1, иначе из контейнера до неё не достучаться.
Сеть host
С ключом --network host контейнер работает прямо в сети хоста: программа слушает порты хоста без всяких -p, а -p в этом режиме не действует. Так запускают программы, которым нужен прямой доступ к сетевым интерфейсам, — например, системы мониторинга сети.
В режиме host нет сетевой изоляции: контейнер видит все сетевые интерфейсы хоста, и каждый порт, который слушает программа, сразу открыт на хосте. Используйте его только когда без него нельзя.
Посмотреть, что в сети
docker network inspect appnet
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}} {{end}}' webПервая команда показывает настройки сети и список подключённых контейнеров с адресами. Вторая — только адреса одного контейнера. Удалить сеть можно, когда в ней не осталось контейнеров: docker network rm appnet.
Сети в Docker Compose
Docker Compose создаёт отдельную сеть для каждого проекта и подключает к ней все его сервисы. Имена сервисов из файла становятся адресами: сервис db доступен остальным как db. Поэтому в Compose сети обычно не настраивают вручную — об этом следующий урок.
Шпаргалка
| Задача | Команда |
|---|---|
| Список сетей | docker network ls |
| Создать сеть | docker network create имя |
| Запустить контейнер в сети | docker run --network имя … |
| Подключить работающий контейнер | docker network connect сеть контейнер |
| Подробности о сети | docker network inspect имя |
| Удалить сеть | docker network rm имя |
Коротко
- В сети
bridgeпо умолчанию контейнеры не находят друг друга по имени — для своих сервисов создают свою сеть. - В своей сети имя контейнера служит его адресом:
http://web,db:5432. - Внутри сети обращаются на порт программы;
-pнужен только для доступа снаружи. - Порты баз данных не публикуют: в сети Docker они доступны и так.
localhostв контейнере — сам контейнер; хост —host.docker.internal(на Linux с--add-host … host-gateway).--network hostубирает сетевую изоляцию — только когда без этого нельзя.