Compose: сети, тома, healthcheck

О лекции

В сети Compose сервисы находят друг друга по имени. localhost внутри контейнера — это не Postgres на ноутбуке. Том переживает удаление контейнера. Healthcheck говорит, готов ли сервис, а не «процесс просто стартовал».

Контейнеры и оркестрация docker собеседование

Docker Compose поднимает несколько контейнеров вместе: общая сеть, DNS по имени сервиса, тома, порядок старта. Это удобно локально. Это не Kubernetes.

Многие прод-ошибки видны уже здесь: не тот localhost, потеря данных, api стартовал раньше базы.

Сети и localhost

Compose создаёт свою сеть. Имя сервиса в YAML становится DNS-именем. Контейнер api ходит к базе как postgres:5432.

Внутри контейнера localhost — сам этот контейнер. Не ноутбук. Не соседний сервис. Порт 5432 на хосте сюда не «просвечивает».

Секция ports: нужна вам на машине: браузер, psql, IDE. Внутри сети Compose она не обязательна. Сервисы ходят друг к другу по имени.

Пример. На ноутбуке открыт localhost:5432 — вы подключаетесь к Postgres с хоста. Тот же адрес из контейнера api попадёт в сам api. Базы там нет. Нужен хост postgres.

services:
  postgres:
    image: postgres:16
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U app"]
      interval: 5s
      retries: 10
  api:
    build: .
    environment:
      DATABASE_URL: postgres://app@postgres:5432/app
    depends_on:
      postgres:
        condition: service_healthy
volumes:
  pgdata:

API резолвит postgres по DNS сети. Старт ждёт healthcheck. Данные живут в named volume.

Тома

Контейнер можно удалить. RW-слой умрёт вместе с ним. Данные базы в этом слое пропадут.

Named volume живёт отдельно. Удалили контейнер — том на месте, пока явно не сделали down -v.

  • Named volume — данные вне контейнера. Для Postgres монтируют в каталог данных, не в корень.
  • Bind-mount — папка с хоста. Удобно для кода в dev. В проде легко ошибиться с правами и путём.
  • Один том на две базы — способ перезаписать оба датадира.

Пример. Postgres без тома: пересоздали контейнер — база пустая. С named volume pgdata таблицы на месте.

Healthcheck

Процесс стартовал — ещё не значит, что сервис готов. База может накатывать файлы. Api может ждать миграцию.

Healthcheck — команда внутри контейнера: HTTP, TCP, pg_isready. Compose помечает сервис unhealthy. Сосед может подождать.

depends_on без condition: service_healthy ждёт только «контейнер создали и запустили». Api стучится в Postgres слишком рано. Тесты мигают.

Пример. Postgres открыл процесс, но ещё не принимает SQL. Api без healthcheck получает «connection refused» и падает. С service_healthy api стартует, когда pg_isready уже зелёный.

Типичная ошибка

Писать из api в localhost:5432, потому что «порт же проброшен». Внутри контейнера localhost — сам контейнер. Ещё: датадир Postgres в git-папку проекта и один volume на две СУБД.

На собеседовании

Сервисы ходят по имени, не на localhost. Том нужен, чтобы данные пережили контейнер. Healthcheck — «готов принимать запросы», не «процесс жив».