Учебное руководство
Главы руководства
На этой странице

Docker, Compose, сеть и хранение

Оглавление · Далее: настройки

Почему несколько контейнеров

Каждый сервис имеет собственные зависимости, команду запуска и жизненный цикл. Next.js и воркер используют общий build stage, но получают разные runtime-образы. Strapi собирается независимо. PostgreSQL, Hatchet Lite и Caddy берутся из готовых образов. Это позволяет обновлять приложение без установки Node.js на VPS.

СервисОбраз/targetВнутренний портНазначение
postgrespostgres:17-alpine5432Базы и очередь
hatchethatchet-lite:v0.107.08888 / 7070HTTP-панель/API и gRPC
webtarget web3000Next.js
functionstarget functionsНет HTTP-портаВоркер
strapiinfra/strapi/Dockerfile1337CMS и её API
caddycaddy:2-alpine80 / 443Входной proxy

Теги node:24-bookworm-slim, postgres:17-alpine, caddy:2-alpine закрепляют ветку, но не полный digest. Web/functions/Strapi в production получают digest из текущей сборки Actions. Все зависимости инфраструктуры пока не воспроизводятся побитово между произвольными датами pull.

Этапы Dockerfile

Корневой Dockerfile:

  1. build: Node 24, pnpm, установка по lockfile и сборка contracts.
  2. web-build: чтение CMS с BuildKit secret и статическая сборка Next.js.
  3. web: копирование Next standalone, .next/static и public; запуск под node.
  4. functions-deploy: сборка воркера и pnpm deploy --prod.
  5. functions: только production-файлы; node dist/index.js.

Standalone — минимальная серверная сборка Next.js со traced dependencies. outputFileTracingRoot расширен до корня монорепо, чтобы попасть могли локальные workspace-пакеты. Без копирования static/public HTML мог бы открываться без картинок, стилей или robots.txt.

Strapi Dockerfile сначала устанавливает build tools и npm ci, собирает CMS, затем выполняет npm prune --omit=dev. Build tools не устанавливаются в финальном stage отдельно; runtime содержит файлы собранного приложения и production-пакеты.

.dockerignore исключает node_modules, сборки и .env. .gitignore и .dockerignore — разные механизмы: добавление файла в один не меняет другой.

Profile и production override

Локально web, functions, strapi, caddy имеют profiles: [app]. infra:up запускает PostgreSQL, Hatchet и Garage; stack:up включает profile app.

compose.production.yaml накладывается после базового Compose:

  • build заменяется на !reset null, используются готовые образы;
  • profiles сбрасываются, чтобы все приложения запускались обычным up;
  • CMS/Hatchet получают реальные домены и защиту панели;
  • PostgreSQL init-файл монтируется со стабильного пути /opt/gheilt/postgres-init.sh;
  • Caddy использует production Caddyfile.

Compose объединяет volume entries по пути назначения. Поэтому override заменяет init script/Caddyfile, но сохраняет том с данными PostgreSQL и тома Caddy.

Адрес внутри сети и адрес на хосте

В общей Compose-сети DNS-именем служит имя сервиса: postgres, web, hatchet. localhost внутри контейнера — этот контейнер, а не весь стек.

СоединениеПравильный адрес
Web → Strapistrapi:1337, read-only token
Web → Garage websites3:3902, фиксированный Host
Strapi → Garage S3s3:3900, S3 credentials
Strapi → PostgreSQLpostgres:5432
Strapi → webhookhttp://web:3000/api/webhooks/strapi
Worker → Hatchet gRPChatchet:7070
Worker на компьютере → Hatchet127.0.0.1:7070
Браузер → локальный сайт Dockerlocalhost:8080

На хост опубликованы Caddy 8080/8443 локально или 80/443 на VPS. Hatchet 8888/7070 привязаны к 127.0.0.1 в обоих режимах. PostgreSQL, web и Strapi напрямую не публикуют порты. Production доступ к HTTP Hatchet идёт через Caddy.

Порты Caddy локально привязаны не только к loopback: учитывайте настройки firewall и доверие к сети компьютера. Локальный CMS-домен и панели не стоит считать защищёнными потому, что это dev-сборка.

Тома и базы

Имя ComposeФактическое имя для project gheiltЧто хранится
postgres_datagheilt_postgres_dataВсе базы PostgreSQL
strapi_uploadsgheilt_strapi_uploadsСтарые local uploads (сохраняются)
hatchet_configgheilt_hatchet_configКонфигурация/ключи Hatchet
caddy_datagheilt_caddy_dataTLS-данные Caddy
caddy_configgheilt_caddy_configСохранённая конфигурация Caddy

Init script создаёт пользователя/базу strapi и пользователя/базу hatchet. Пользователь gheilt, заданный через POSTGRES_USER, является административным пользователем контейнера. Служебная база gheilt не является бизнес-базой сайта.

Init scripts образа PostgreSQL выполняются на новом пустом data volume. Изменение файла или .env при уже созданном томе не создаст пользователей заново и не поменяет существующие пароли. Нужна явная миграция/ротация.

down сохраняет named volumes. down -v удаляет их. Не удаляйте тома для решения проблемы несовпадения паролей без понимания, какие данные исчезнут.

Порядок запуска и перезапуска

depends_on.condition: service_healthy заставляет Compose ждать готовности зависимости при старте. restart: true у зависимости просит перезапустить зависимый сервис при её управляемом обновлении через Compose. Это помогло избежать потери соединений Hatchet после пересоздания PostgreSQL.

restart: unless-stopped — отдельная политика Docker для контейнера после выхода процесса или перезапуска daemon. Она не означает, что приложение с зависшей бизнес- логикой обязательно будет признано неисправным.

Различие и порядок запуска в документации Compose.

HealthcheckЧто реально проверяет
PostgreSQLpg_isready
HatchetHTTP-ответ на /
Web/api/health
Strapi/_health
Functions / CaddyСобственного healthcheck нет

Даже up --wait не доказывает прохождение сообщения через очередь. Для readiness воркера нужна отдельная функциональная проверка.

Где смотреть код

Compose, override, Dockerfile, Strapi image, init script, Caddy.

Отдельный S3-сервис

Garage 2.3.0 запускается одним узлом, с двумя persistent volumes: s3_data и s3_metadata. S3 API 3900 и website 3902 опубликованы только на loopback; RPC 3901 не опубликован. Caddy отдаёт публичный bucket media по отдельному media-домену, с фиксированным upstream Host. Strapi сохраняет новые uploads через официальный AWS S3 provider, прежние local uploads остаются в старом томе.

pnpm infra:up теперь также запускает Garage; pnpm infra:s3 запускает только хранилище и включает website для bucket. stack:up делает эту подготовку до запуска приложений. Подробности.