Какие порты Docker Compose открывать наружу: приложение, база и отладка
В проекте три сервиса: API, PostgreSQL и временная панель администратора. Во время разработки каждому добавили ports, чтобы всё было удобно открывать с ноутбука. При переносе на сервер такой файл превращает удобство разработки в набор дополнительных сетевых входов. База получает опубликованный порт, хотя приложение подключается к ней по внутренней сети.
Начните с простого вопроса для каждого соединения: кто его устанавливает и откуда? Браузер посетителя должен попасть в HTTP-сервис. Приложение должно попасть в PostgreSQL. Локальному инструменту разработчика иногда нужен доступ к базе с хоста. Это три разных маршрута, и им не требуется одинаковая публикация портов.
Внутреннему клиенту достаточно имени сервиса
В обычной сети Compose контейнер приложения обращается к базе по имени сервиса db и порту PostgreSQL 5432. Наличие ports у db для этого не требуется. Удаление публикации не меняет адрес подключения приложения: db:5432 остаётся тем же. При этом база должна слушать адрес, доступный внутри контейнера, а её собственная авторизация продолжает действовать.
EXPOSE в Dockerfile и expose в Compose не создают внешний порт хоста. Также они не являются отдельным межконтейнерным firewall: участники общей сети могут обращаться к слушающим портам друг друга. Если сервисы нужно действительно разделить, проектируйте сети и доступы, а не рассчитывайте на отсутствие строки expose.
Выберите точку входа для пользователя
Рассмотрим приложение, у которого процесс внутри контейнера слушает 0.0.0.0:8000. Прокси находится на самом Linux-хосте и обращается к приложению через 127.0.0.1:8080. Публикацию ограничим loopback. Ниже фрагмент файла: image APP_IMAGE должен быть задан заранее и обозначать ваш образ приложения, а не неизвестный готовый сервис.
services:
app:
image: ${APP_IMAGE:?Set APP_IMAGE}
ports:
- "127.0.0.1:8080:8000"
db:
image: postgres:18
environment:
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_password
secrets:
db_password:
file: ./db_password.txt
Файл db_password.txt создаётся локально принятым в проекте способом, не включается в Git, а приложение получает свои настройки подключения отдельно. Фрагмент показывает границу сети; для рабочего проекта добавьте том данных и конфигурацию самого API. У db нет ports, поэтому обычная публикация PostgreSQL на хосте отсутствует.
Если Nginx тоже находится в Compose, ему обычно удобнее обращаться к app:8000 в общей сети. Тогда API не нужен опубликованный порт, а наружу публикуется сам прокси. Адрес 127.0.0.1 внутри контейнера Nginx указывает на этот контейнер, поэтому хостовую схему нельзя механически перенести внутрь Compose.
Локальный доступ для администратора выделите явно
Для подключения SQL-клиента с того же компьютера можно добавить в отдельный локальный файл публикацию 127.0.0.1:15432:5432. Она предназначена для инструментов на хосте. Не переносите её на сервер только потому, что редактор базы так привык подключаться. Удалённый доступ оформляется отдельным согласованным маршрутом, например через SSH-туннель.
Запись "5432:5432" без адреса хоста обычно публикует порт на всех адресах. На сервере с публичным IP это меняет доступность. Учитывайте также firewall и особенности маршрутизации Docker: проверка только привычного хостового правила не заменяет проверку опубликованных портов. В Docker Engine до 28.0.0 у loopback-публикации есть известное ограничение изоляции от соседей в той же L2-сети; для такой схемы нужна актуальная версия и проверка окружения.
Не забывайте о подключениях в обратную сторону. Например, API обращается к внешнему почтовому серверу, а база ходит за архивом в объектное хранилище. Если для разделения вы выбираете сеть internal, проверьте необходимые исходящие маршруты для каждого её участника. Закрытие входного порта хоста и ограничение исходящего доступа решают разные задачи; оба решения должны соответствовать карте реальных вызовов.
Проверьте карту с двух сторон
Сначала посмотрите итоговую конфигурацию через docker compose config, затем публикации запущенного проекта через docker compose ps. Если используются несколько файлов, проверяйте именно их общую комбинацию. Дополнительный override способен вернуть порт, который вы убрали из базового файла.
docker compose config
docker compose ps
docker compose port app 8000
На самом хосте запрос к 127.0.0.1:8080 должен попасть в приложение. С другой машины прямой доступ к публичному адресу на 8080 должен быть недоступен, а штатный HTTPS-вход — работать. Проверяйте оба результата: закрытый лишний порт и открытый нужный маршрут. Внутри приложения отдельно подтвердите подключение к db:5432.
Карта подключений остаётся полезной при добавлении Redis, отладчика или панели метрик. Каждому новому входу назначайте клиента и назначение. Тогда временная диагностика не превращается в постоянную внешнюю поверхность доступа.
Адреса между сервисами подробнее разобраны в статье о localhost и PostgreSQL. Если запуск не удаётся даже при правильном адресе, отдельно проверьте готовность базы через healthcheck.
В курсе Docker и Docker Compose вы упакуете HTTP-сервис, подключите PostgreSQL, настроите порты, переменные и связь между контейнерами. Практика с недоступным сервисом и неверным localhost помогает закрепить эту карту на работающем учебном проекте. Откройте программу курса и переходите от случайных публикаций портов к объяснимому окружению.
Продолжить на практике
- Docker и Docker Compose: контейнеризация приложений ↗
Упакуйте приложение в Docker и запустите его с PostgreSQL через Compose. Образы, сети, тома, диагностика поломок, обновление версий и восстановление данных — с практикой и итоговым проектом.
