Docker, Compose, сеть и хранение
Оглавление · Далее: настройки
Почему несколько контейнеров
Каждый сервис имеет собственные зависимости, команду запуска и жизненный цикл. Next.js и воркер используют общий build stage, но получают разные runtime-образы. Strapi собирается независимо. PostgreSQL, Hatchet Lite и Caddy берутся из готовых образов. Это позволяет обновлять приложение без установки Node.js на VPS.
| Сервис | Образ/target | Внутренний порт | Назначение |
|---|---|---|---|
postgres | postgres:17-alpine | 5432 | Базы и очередь |
hatchet | hatchet-lite:v0.107.0 | 8888 / 7070 | HTTP-панель/API и gRPC |
web | target web | 3000 | Next.js |
functions | target functions | Нет HTTP-порта | Воркер |
strapi | infra/strapi/Dockerfile | 1337 | CMS и её API |
caddy | caddy:2-alpine | 80 / 443 | Входной proxy |
Теги node:24-bookworm-slim, postgres:17-alpine, caddy:2-alpine закрепляют
ветку, но не полный digest. Web/functions/Strapi в production получают digest
из текущей сборки Actions. Все зависимости инфраструктуры пока не воспроизводятся
побитово между произвольными датами pull.
Этапы Dockerfile
Корневой Dockerfile:
build: Node 24, pnpm, установка по lockfile и сборка contracts.web-build: чтение CMS с BuildKit secret и статическая сборка Next.js.web: копирование Next standalone,.next/staticиpublic; запуск подnode.functions-deploy: сборка воркера иpnpm deploy --prod.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 → Strapi | strapi:1337, read-only token |
| Web → Garage website | s3:3902, фиксированный Host |
| Strapi → Garage S3 | s3:3900, S3 credentials |
| Strapi → PostgreSQL | postgres:5432 |
| Strapi → webhook | http://web:3000/api/webhooks/strapi |
| Worker → Hatchet gRPC | hatchet:7070 |
| Worker на компьютере → Hatchet | 127.0.0.1:7070 |
| Браузер → локальный сайт Docker | localhost: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_data | gheilt_postgres_data | Все базы PostgreSQL |
strapi_uploads | gheilt_strapi_uploads | Старые local uploads (сохраняются) |
hatchet_config | gheilt_hatchet_config | Конфигурация/ключи Hatchet |
caddy_data | gheilt_caddy_data | TLS-данные Caddy |
caddy_config | gheilt_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 | Что реально проверяет |
|---|---|
| PostgreSQL | pg_isready |
| Hatchet | HTTP-ответ на / |
| 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 делает эту подготовку до
запуска приложений. Подробности.