Совет по умолчанию в 2026 году — «просто заDockerь это». Обычно он верный, но иногда это ошибка. Контейнеры дают воспроизводимость и изоляцию, однако на небольшом VPS они ещё и едят память, добавляют лишнюю подвижную деталь и делают одноприложенческий сервер сложнее, чем нужно. Честный вопрос не «Docker или нет» — а «что нужно именно вашей установке?».
Что Docker реально даёт
- Воспроизводимость. Образ — это и есть ваше окружение. Никакого дрейфа «у меня работает» между локальной машиной, CI и продом.
- Изоляция. Падение или зависимость одного приложения не рушит хост и его соседей.
- Запуск одной командой.
docker compose upподнимает весь ваш стек — приложение, БД, прокси — из файла, который можно версионировать. - Чистые обновления и откаты. Меняете тег образа, а если что-то не так — возвращаете обратно. Уже одно это стоит многого.
Что это вам стоит
- Память. Контейнеры добавляют накладные расходы поверх RSS процесса (базовый образ + рантайм + слой контейнера), а лимит памяти Docker считает весь контейнер, а не только ваше приложение.[1] На машине с 1–2 ГБ, когда приложение + Postgres + Nginx живут каждый в своём контейнере, вы незаметно дойдёте до свопа — а своп на VPS это жестоко. Накладные расходы зависят от рантайма и базового образа; измерьте память в простое на каждый контейнер через
docker stats, прежде чем планировать бюджет. - Размер образа. Полный образ
node:24тащит весь тулчейн — сотни мегабайт ещё до вашего приложения; небрежный Dockerfile отправляет в прод ваши dev-зависимости. Многоступенчатые сборки — это решение, а не украшение. - Ещё один слой для отладки. Сеть, тома и права — реальная поверхность для траблшутинга. Для одного Node-приложения это накладные расходы, которые могут быть не нужны.
- Больше CPU за ту же работу. Рантайм контейнеров добавляет тонкий слой; для веб-приложений это обычно незаметно, но на крошечной машине каждый бит на счету.
Рамка для решения
| Ваша ситуация | Что брать |
|---|---|
| Одно приложение, один сервер, без команды | Сырой VPS, pm2/systemd |
| Приложение + база данных + надо расти | Docker Compose |
| Несколько приложений на одной машине | Docker Compose (с namespaces) |
| Нужны чистые откаты всего стека | Docker Compose |
| У вас машина на 1 ГБ | Docker, но тощий |
| Жёсткий лимит по диску | Сырой VPS |
Реальная граница — сколько независимо версионируемых сервисов вы запускаете и насколько цените откат. Одно долгоживущее Node-приложение с одним Postgres позади: это можно вести через systemd и обычную установку — меньше слоёв, меньше RAM. Как только вам нужно менять версии нескольких сервисов вместе или отдавать настройку кому-то другому — выигрывают контейнеры.
Экономный средний путь (что я бы реально запускал)
Если уж докеризовать — делайте это без типичного налога на накладные расходы.
Собирайте маленьким. Многоступенчатый Dockerfile, который тащит в прод только рантайм:
FROM node:24-slim AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:24-slim AS runtime
WORKDIR /app
ENV NODE_ENV=production
COPY --from=build /app/.next/standalone ./
COPY --from=build /app/.next/static ./.next/static
COPY --from=build /app/public ./public
EXPOSE 3000
CMD ["node", "server.js"]
Если приложение не использует Next.js standalone, копирование в runtime отличается — подгоните строки COPY под ваш вывод сборки.[2] Важна сама форма стадии FROM … AS runtime — никаких dev-зависимостей, никакого дерева исходников, никакого git-репозитория.
node:24-slim (а не полный node:24) резко уменьшает базу. Ещё меньшие варианты (Alpine, distroless) меняют удобство отладки на размер — выбирайте, насколько вам хочется копаться внутри работающего контейнера.
Задайте лимиты ресурсов. Одна из самых полезных вещей, чтобы держать контейнеры в узде на маленькой машине:
# docker-compose.yml
services:
app:
build: .
restart: unless-stopped
ports:
- "127.0.0.1:3000:3000"
environment:
- NODE_ENV=production
deploy:
resources:
limits:
memory: 384m
cpus: "0.50"
Привязка порта приложения к 127.0.0.1 вместо 0.0.0.0 означает, что можно поставить Nginx спереди (или другой контейнер), не выставляя приложение напрямую в интернет. Блок deploy.resources.limits не даёт одному контейнеру уморить хост — особенно важно, если вы добавляете в стек базу данных.
Добавьте базу данных в тот же файл. Типичный путь роста:
db:
image: postgres:18
restart: unless-stopped
environment:
- POSTGRES_DB=myapp
- POSTGRES_USER=myapp
- POSTGRES_PASSWORD=change-me
volumes:
- dbdata:/var/lib/postgresql/data
deploy:
resources:
limits:
memory: 256m
volumes:
dbdata:
Зафиксируйте поддерживаемый мажор Postgres — 18 это текущий стабильный релиз (19 всё ещё в бете на сентябрь 2026).[3] Проверьте потребление памяти образа, прежде чем ставить лимит слишком низко: недокормленный Postgres получает OOM-kill при записи.[1]
Запускайте.
docker compose up -d --build
docker compose logs -f
docker compose down
Когда возвращаться к сырому VPS
Если у вас одно приложение, хранилище «строки в файле» или лёгкая база, нет нужды в много-контейнерной оркестрации, а вы хотите меньше памяти и подвижных деталей — пропускайте Docker. Используйте PM2 или systemd. Вы получаете:
- Меньше RAM на процесс.
- Более быстрое и простое отлаживание (нет слоя томов/прав, о который спотыкаешься).
- Прямой доступ к
node, вашему пакетному менеджеру и файловой системе. - Меньше вещей, которые придётся объяснять следующему человеку, унаследовавшему сервер.
Мы публикуем цифры простоя/перезагрузок и памяти для этих двух установок только после замера на чистом платном VPS — см. как мы тестируем. До этого считайте любые цифры выше структурой, а не результатами.
Итог
Docker — не значение по умолчанию, а инструмент для конкретной задачи. Используйте его, когда у вас несколько независимо версионируемых сервисов, нужны обратимые деплои или вы хотите передать стек кому-то другому без документации на 20 страниц. Пропускайте, когда у вас одно приложение, одна машина и сильное предпочтение меньшего числа слоёв. Если всё же используете — собирайте маленьким и задавайте лимиты: именно оттуда берутся большинство страшилок про «накладные расходы контейнеров», и это предотвратимо.
Источники
- Docker — Resource constraints (лимиты памяти и поведение OOM). https://docs.docker.com/engine/containers/resource_constraints/ — проверено 2026-09-27
- Next.js —
output: 'standalone'(справочникnext.config.js). https://nextjs.org/docs/app/api-reference/config/next-config-js/output — проверено 2026-09-27 - PostgreSQL — Versioning policy (текущие поддерживаемые мажоры). https://www.postgresql.org/support/versioning/ — проверено 2026-09-27