Перейти к содержанию
Бэкенд и системы

Docker Compose: DNS сервисов и готовность базы при запуске

API работает на ноутбуке, но падает в Compose: он может обращаться не по тому адресу или подключаться до готовности PostgreSQL. Разберём один локальный пример с API и базой и проверим эти причины по отдельности.

Автор: Опубликовано

4 мин чтенияРедакционный разборОбновлено
  • Docker Compose
  • DNS
  • Healthcheck
  • PostgreSQL
Главная мысль

Из другого контейнера используйте имя сервиса и внутренний порт базы. Проверяйте готовность перед запуском API, а последующие разрывы соединений обрабатывайте в приложении.

Сначала проверьте адрес подключения API

Допустим, API использует postgres://localhost:15432/app. Такой адрес подходит клиенту на ноутбуке, если порт базы опубликован на хосте. Внутри контейнера API localhost указывает на сам контейнер API. Публикация порта этого не меняет. Запишите в диагностический лог хост и порт соединения, исключив пароль.

В примере сервисы подключены к общей сети Compose по умолчанию. Внутренний адрес базы — db:5432, а клиент на Docker-хосте обращается к 127.0.0.1:15432. При собственных сетях проверьте, что API и база имеют хотя бы одну общую сеть. Два отдельных Compose-проекта автоматически общую сеть не получают.

Адрес зависит от расположения клиента
КлиентАдрес базы
Контейнер APIdb:5432
Docker-хост127.0.0.1:15432
Другой Compose-проектНужна общая сеть

Добавьте проверку готовности базы

Пример предполагает Dockerfile для Node API в текущем каталоге и приложение, слушающее 0.0.0.0:8080. Пароль local-demo предназначен только для временного локального стенда. Версия образа PostgreSQL выбрана для упражнения; хранение данных и выбор образа для production требуют отдельного решения.

Сохраните конфигурацию в compose.yaml. Healthcheck выполняется внутри db и проверяет локальный сервер. Условие service_healthy заставляет Compose дождаться успешной проверки перед запуском api. Краткая форма depends_on задаёт порядок запуска, но не гарантирует готовность базы. Для соединения контейнеров публикация порта 15432 не нужна.

services:
  api:
    build: .
    environment:
      DATABASE_URL: postgres://app:local-demo@db:5432/app
    depends_on:
      db:
        condition: service_healthy
    ports:
      - "127.0.0.1:8080:8080"
  db:
    image: postgres:17
    environment:
      POSTGRES_USER: app
      POSTGRES_PASSWORD: local-demo
      POSTGRES_DB: app
    ports:
      - "127.0.0.1:15432:5432"
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -h 127.0.0.1 -U app -d app"]
      interval: 5s
      timeout: 3s
      retries: 12
      start_period: 10s

Разделите ошибки DNS, TCP и PostgreSQL

Выполняйте команды из каталога с compose.yaml и замените имена сервисов своими. Последние две проверки требуют работающего контейнера API с Node. Если api сразу завершается, сначала изучите его логи или используйте диагностический контейнер в той же сети.

Ошибка разрешения имени указывает на название сервиса или состав сети. Имя разрешается, но соединение отклонено — проверяйте слушающий процесс, порт и состояние запуска. Успешное TCP-соединение ещё не подтверждает пароль, наличие базы и выполнение SQL. Сопоставьте сообщение приложения с конкретным уровнем, прежде чем менять конфигурацию.

docker compose config --quiet
docker compose ps -a
docker compose logs --tail=50 db api
docker compose port db 5432
docker compose exec -T api node -e 'require("dns").lookup("db", (error, address) => { if (error) throw error; console.log(address); })'
docker compose exec -T api node -e 'const socket = require("net").createConnection({ host: "db", port: 5432 }); socket.setTimeout(3000); socket.on("connect", () => { console.log("TCP connected"); socket.end(); }); socket.on("timeout", () => { socket.destroy(); process.exitCode = 1; }); socket.on("error", error => { console.error(error.message); process.exitCode = 1; });'

Проверяйте готовность к нужной операции

pg_isready проверяет, принимает ли сервер PostgreSQL соединения. Он не доказывает, что пароль API верен или нужная таблица уже создана. Если сначала требуется миграция, выполните её отдельной задачей и явно дождитесь успешного завершения либо обеспечьте понятную ошибку инициализации в приложении.

В нашем примере сначала исправьте localhost. Если затем при старте иногда появляется connection refused, добавьте проверку готовности. Если после успешного healthcheck возникает relation does not exist, исследуйте миграции. Это разные результаты, требующие разных исправлений, даже если все они проявляются при запуске API.

Восстанавливайте соединения после запуска

Успешная проверка описывает состояние в конкретный момент. База может перезапуститься позже, а пересозданный контейнер — получить другой IP. Сохраните db как имя хоста. Пул соединений должен отбрасывать разорванные соединения, заново разрешать имя и подключаться с ограниченными повторами, задержкой и общим дедлайном.

Таймаут после записи может оставить неизвестный результат: операция могла выполниться. Повторяйте её только при безопасной семантике или защите от дубликатов. depends_on restart: true относится к явным операциям Compose над зависимостью; это не универсальный механизм восстановления API после любого падения базы.

Проверяйте каждое исправление отдельно

Проверьте итоговую конфигурацию Compose, запустите стенд и сопоставьте состояние базы с логами старта API. Затем на временном стенде перезапустите db и наблюдайте, восстановится ли API без ручного вмешательства. Критерий успеха — выполнение нужной операции с базой, а не только разрешение имени.

Сохраните отдельные результаты для неверного адреса, медленного старта и разрыва после запуска. Такой небольшой набор проверок помогает объяснить диагноз и на собеседовании, и при разборе инцидента. После этого переходите к общим вопросам о Docker.

Коротко

Частые вопросы

Почему localhost не соединяет контейнеры Compose?

Обычно у каждого контейнера своё сетевое пространство имён. Внутри api localhost относится к api. Если сервисы в общей сети, обращайтесь к db по внутреннему порту базы.

Ждёт ли depends_on готовности PostgreSQL?

Краткая форма задаёт порядок запуска. Условие service_healthy ждёт успешного healthcheck зависимости. Сама проверка должна соответствовать тому, что требуется приложению.

Нужно ли публиковать порт базы?

Контейнерам в одной сети достаточно внутреннего порта. Публикуйте его для клиента на хосте, если такой доступ нужен. В примере порт привязан к loopback хоста.

Исправит ли healthcheck неверный пароль?

Нет. pg_isready может подтвердить готовность сервера без проверки пароля приложения. Изучите ошибку аутентификации и отдельно проверьте настоящее соединение.

Источники

Источники и редакционная политика

Сведения проверены 4 октября 2026 г. Ссылки рядом с разделами указывают источники фактов и технических объяснений. Выводы, учебные сценарии и рекомендации по подготовке — редакционная работа RecallDeck.

От чтения к воспроизведению

Отрепетируйте полный цикл интервью.

RecallDeck возвращает сложные темы по расписанию и помогает удерживать в памяти язык, SQL, архитектуру и поведенческие истории.

Начать подготовку

Продолжить подготовку