Сети в Docker: связываем контейнеры между собой

Рейтинг: 68.5% · 14 голосов
Практический курс по Docker: образы, контейнеры, тома, сети, Compose и продакшен. Уроки по главам с обсуждением.
Ответить
Аватара пользователя
Marina_DevOps
Сообщения: 25
Зарегистрирован: 11 май 2026, 05:31

Сети в Docker: связываем контейнеры между собой

Сообщение Marina_DevOps »

АкадемияDocker с нуляГлава 6 из 17
Оглавление курса (17)
  1. Что такое Docker и какие задачи он решает
  2. Установка Docker и запуск первого контейнера
  3. Образы: слои, теги и реестр Docker Hub
  4. Пишем свой Dockerfile
  5. Тома и хранение данных: volumes и bind mounts
  6. Сети в Docker: связываем контейнеры между собой (вы здесь)
  7. Переменные окружения и конфигурация контейнеров
  8. Docker Compose: поднимаем многоконтейнерное приложение
  9. Оптимизация образов: multi-stage сборка, размер и кэш слоёв
  10. Логи, отладка и мониторинг контейнеров
  11. Базовая безопасность контейнеров
  12. Подготовка к продакшену: что важно учесть
  13. Dockerfile глубже: ENTRYPOINT и CMD, HEALTHCHECK, .dockerignore, запуск не от root
  14. Реестры образов: приватные registry, push и pull, теги и digest, imagePullSecrets
  15. BuildKit и buildx: multi-arch сборки, секреты сборки, экспорт кэша
  16. Docker в CI/CD: автосборка, сканирование образов (Trivy, Docker Scout), публикация
  17. Итоговый проект и куда расти: от Dockerfile до прода, обзор оркестрации (Kubernetes, Podman, OCI)
В прошлых главах мы запускали контейнеры по одному: тут веб-сервер, там база. Но реальное приложение почти всегда состоит из нескольких частей, и им нужно общаться. Эта глава про то, как Docker связывает контейнеры в сеть и почему обращение по имени контейнера работает как магия (на самом деле нет, это просто встроенный DNS).

Что происходит по умолчанию:

При установке Docker создает три сети, посмотреть их можно так:

Код: Выделить всё

docker network ls
Вы увидите bridge, host и none. Если запустить контейнер без флага --network, он попадет в сеть bridge. Это сеть по умолчанию, и у нее есть неприятная особенность: контейнеры в ней не видят друг друга по именам. Только по IP, который меняется при каждом пересоздании контейнера. Строить на этом что-то серьезное нельзя.

Сеть host убирает изоляцию: контейнер использует сетевой стек хоста напрямую (полноценно это работает только на Linux). Сеть none отключает сеть совсем. Обе нужны редко, для типовых задач хватает bridge-сетей.

Пользовательские сети:

Правильный путь: создать свою сеть и запустить контейнеры в ней.

Код: Выделить всё

docker network create app-net

docker run -d --name pg --network app-net \
  -e POSTGRES_PASSWORD=secret postgres:16

docker run -d --name api --network app-net \
  -p 8080:8080 my-api:1.0
Главный бонус пользовательской сети: встроенный DNS. Контейнер api может обратиться к базе просто по имени pg. Строка подключения в приложении будет выглядеть так:

Код: Выделить всё

postgres://postgres:secret@pg:5432/postgres
Никаких IP-адресов в конфигах. Контейнер pg можно пересоздать, имя останется прежним, и все продолжит работать. Проверить связность можно изнутри контейнера:

Код: Выделить всё

docker exec -it api sh
# внутри контейнера (если образ на alpine)
nc -z pg 5432 && echo "база доступна"
Заметьте: флаг -p 8080:8080 мы повесили только на api. Базе он не нужен. Публикация порта открывает доступ снаружи, с хост-машины и из внешнего мира. Для общения контейнеров между собой внутри одной сети порты публиковать не надо, они и так видят друг друга. Это еще и вопрос безопасности: чем меньше портов торчит наружу, тем лучше. К этому вернемся в главе 11.

Контейнер можно подключать к сетям и на лету:

Код: Выделить всё

docker network inspect app-net
docker network connect app-net redis
docker network disconnect app-net redis
Команда inspect показывает, кто сейчас в сети и какие у кого адреса. Один контейнер может состоять в нескольких сетях одновременно. Это удобно, когда нужно изолировать базу от фронтенда, но дать к ней доступ бэкенду.

Типичные грабли:

Первое и главное: localhost внутри контейнера указывает на сам контейнер, а не на вашу машину. Если приложение в контейнере пытается достучаться до postgres://localhost:5432, а Postgres крутится в соседнем контейнере или на хосте, ничего не выйдет. Для соседнего контейнера используйте его имя. Для хоста на Docker Desktop (Mac и Windows) есть специальное имя host.docker.internal, на Linux его нужно добавить вручную флагом --add-host=host.docker.internal:host-gateway.

Второе: при общении контейнеров используется внутренний порт, а не опубликованный. Если вы запустили базу с -p 55432:5432, то с хоста подключаетесь к localhost:55432, а из соседнего контейнера все равно к pg:5432.

Третье: имена резолвятся только в пользовательских сетях. Запустили два контейнера без --network и удивляетесь, почему обращение по имени не работает. Потому что они в дефолтном bridge, там DNS по именам контейнеров нет.

Что усвоили:

Контейнеры связываются через сети. Создавайте свои bridge-сети и обращайтесь к соседям по имени контейнера, а порты публикуйте только там, где нужен доступ снаружи. В главе 8 Docker Compose будет создавать такие сети за вас автоматически, и вы узнаете в его конфиге все, что мы сейчас делали руками. А следующая глава про переменные окружения: пароль от базы, который мы прописали прямо в команде запуска, так оставлять нельзя.
👍3 ❤️2 🔥1 😄 🤔3
✔ Лучший ответ сформирован автоматически — streamd
Marina_DevOps писал(а):при общении контейнеров используется внутренний порт, а не опубликованный вот на этом у меня в свое время полдня ушло. подключался из api к pg:55432, потому что так с хоста работало, и не мог понять, что не так. жаль, этой главы тогда не было
Перейти к ответу →
Аватара пользователя
streamd
Сообщения: 2
Зарегистрирован: 15 май 2026, 13:23

Re: Сети в Docker: связываем контейнеры между собой

Сообщение streamd »

✔ Лучший ответ — сформирован автоматически
Marina_DevOps писал(а):при общении контейнеров используется внутренний порт, а не опубликованный
вот на этом у меня в свое время полдня ушло. подключался из api к pg:55432, потому что так с хоста работало, и не мог понять, что не так. жаль, этой главы тогда не было
👍 ❤️1 🔥 😄 🤔1
Аватара пользователя
andrei123
Сообщения: 2
Зарегистрирован: 14 май 2026, 11:27

Re: Сети в Docker: связываем контейнеры между собой

Сообщение andrei123 »

а если контейнеры на разных машинах? bridge же только в пределах одного хоста работает, или я путаю? скажем, у меня два vps на timeweb, на одном база, на другом приложение. это уже swarm/kubernetes надо или есть способ попроще?
👍1 ❤️ 🔥1 😄 🤔1
Аватара пользователя
morrowi
Сообщения: 2
Зарегистрирован: 18 май 2026, 10:24

Re: Сети в Docker: связываем контейнеры между собой

Сообщение morrowi »

небольшая поправка: nc и ping есть далеко не во всех образах, в slim и distroless их обычно нет. я в таких случаях поднимаю рядом временный контейнер в той же сети: docker run --rm --network app-net alpine ping -c2 pg. и образ трогать не надо
👍2 ❤️ 🔥1 😄 🤔
Аватара пользователя
clickhouseandy
Сообщения: 1
Зарегистрирован: 02 июн 2026, 05:36

Re: Сети в Docker: связываем контейнеры между собой

Сообщение clickhouseandy »

спасибо, наконец дошло, почему мое приложение не видело постгрес на localhost. я уж думал, докер сломан, а оказалось, сам себе злобный буратино)) про --add-host на линуксе вообще нигде внятно не находил, утащил в заметки
👍 ❤️ 🔥 😄 🤔
Ответить
← Предыдущая глава
Тома и хранение данных: volumes и bind mounts
Следующая глава →
Переменные окружения и конфигурация контейнеров

Все главы курса «Docker с нуля»

Поделиться темой: ✈ Telegram VK

Вернуться в «Docker с нуля»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 1 гость