Совет по умолчанию в 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 страниц. Пропускайте, когда у вас одно приложение, одна машина и сильное предпочтение меньшего числа слоёв. Если всё же используете — собирайте маленьким и задавайте лимиты: именно оттуда берутся большинство страшилок про «накладные расходы контейнеров», и это предотвратимо.

Источники

  1. Docker — Resource constraints (лимиты памяти и поведение OOM). https://docs.docker.com/engine/containers/resource_constraints/ — проверено 2026-09-27
  2. Next.js — output: 'standalone' (справочник next.config.js). https://nextjs.org/docs/app/api-reference/config/next-config-js/output — проверено 2026-09-27
  3. PostgreSQL — Versioning policy (текущие поддерживаемые мажоры). https://www.postgresql.org/support/versioning/ — проверено 2026-09-27