Docker — отличный инструмент, но «отличный» не значит «единственный» и тем более не значит, что он подходит для любой задачи. На одиночном сервере с одним-двумя приложениями Docker может принести больше проблем, чем пользы. Демон, образы, слои, сети и тома упрощают упаковку и запуск приложений, но на одиночке или небольшом VDS они избыточны. Под катом о том, в каких случаях Docker не нужОн, чем его заменить и как. Читать

Docker — отличный инструмент, но «отличный» не значит «единственный» и тем более не значит, что он подходит для любой задачи. На одиночном сервере с одним-двумя приложениями Docker может принести больше проблем, чем пользы. Демон, образы, слои, сети и тома упрощают упаковку и запуск приложений, но на одиночке или небольшом VDS они избыточны. Под катом о том, в каких случаях Docker не нужОн, чем его заменить и как.
За что Docker любят разработчикиDocker появился в марте 2013 года, когда французский разработчик Соломон Хайкс показал его на конференции PyCon в Санта-Кларе. Не удивляйтесь, но до этого контейнеры также существовали, например, LXC развивался с 2008 года, а отдельные механизмы изоляции появлялись в ядре Linux ещё раньше. Первый namespace добавили в 2002 году, а cgroups вошли в основное ядро в 2008 году.
Docker сделал контейнеры доступными, ведь до этого собирать файловую систему, настраивать изоляцию процессов, создавать сеть и отдельно продумывать доставку приложения на другой сервер нужно было практически вручную.

В Docker всего лишь нужно описать окружение в Dockerfile, собрать образ и получить результат. В этом и заключается основная ценность платформы — она сильно упрощает сборку, доставку и воспроизведение окружения. По этой причине статья создана не с целью критики, а для того, чтобы показать новичкам, что не Docker единым…
Поговорим о траблахВо-первых, Docker тратит ресурсы. Да, контейнеры легче виртуальных машин — они делят ядро хоста, не требуют эмуляции железа и стартуют за секунды, но это не означает «бесплатно».
Docker Engine держит в памяти dockerd, containerd и процессы runtime. Каждый контейнер также требует служебных структур ядра и процессов управления, однако фиксированного оверхеда на контейнер не существует. Основную память потребляют PostgreSQL, Redis, nginx, бэкенд и другие запущенные приложения. Разницу лучше измерять прямо на сервере:
ps -C dockerd -C containerd -C containerd-shim-runc-v2 \
-o pid,comm,rss
docker stats --no-stream
systemd-cgtopНа сервере с 32 ГБ RAM расходы обычно незначительны, но на VPS с 1–2 ГБ даже несколько десятков мегабайт сокращают запас памяти и повышают риск использования свопа или срабатывания OOM killer.
Но RAM ещё полбеды. Во многих Linux-установках слои образов и записываемые слои контейнеров хранятся через overlay2 (на свежих установках Docker Engine 29 может использоваться containerd image store). Когда контейнер впервые изменяет файл из нижнего слоя, OverlayFS копирует его в верхний записываемый слой. Дальнейшие операции выполняются уже с этой копией.
Кроме того, со временем в хранилище остаются старые версии образов, промежуточные слои сборки, остановленные контейнеры и неиспользуемые тома. Проверяйте состояние хранилища через команды:
# Посмотреть драйвер
docker info | grep -E 'Storage Driver|containerd'
# Проверить занятое место
docker system df
docker system df -v
# Найти остановленные контейнеры
docker ps -a
# Посмотреть кэш Buildx
docker buildx duВо-вторых, демон Docker работает с правами root. Клиент передаёт ему команды через сокет /var/run/docker.sock, и, чтобы не использовать sudo при каждом запуске, учётную запись часто добавляют в группу docker. Такая учётка фактически получает привилегии уровня root. Частично эту проблему решает rootless-режим, однако он требует отдельной настройки и имеет ограничения.
В-третьих, Docker переписывает iptables, добавляя свои цепочки DOCKER, DOCKER-FORWARD и DOCKER-USER. Если вы привыкли управлять фаерволом через ufw или nftables — готовьтесь к тому, что придётся лезть в DOCKER-USER цепочку. Права Docker имеют приоритет, и ваши могут работать не так, как нужно.
В-четвёртых, Docker-контейнеры по замыслу эфемерны. Если вы храните данные внутри контейнера, они пропадут при пересоздании, нужно использовать volumes, но это ещё одна абстракция над обычными директориями.
В общем, главная проблема Docker на одиночном сервере — это то, что он добавляет ещё одну систему управления, которую нужно понимать не хуже самого Linux. В итоге он вреден в пяти ситуациях:
У вас один бэкенд и одна база на VPS. Node.js-приложение, PostgreSQL и nginx можно запустить обычными системными сервисами.
Вы поднимаете игровой сервер. Minecraft, Rust, CS и другие игровые серверы активно работают с сетью и файловой системой. Docker bridge добавляет NAT и усложняет настройку портов.
У вас VPS с 1–2 ГБ RAM. При небольшом запасе даже несколько десятков мегабайт могут повысить вероятность свопинга или срабатывание OOM killer.
Вы запускаете сервис, чувствительный к задержке (VoIP, видеосвязь, IoT-брокеры). Здесь Docker стоит использовать только после замеров.
Вы администрируете сервер в свободное время. Если у вас личный блог или домашнее хранилище, то с Docker вам придётся постоянно следить за образами, логами, политиками перезапуска и очисткой диска.
Что тогда использовать вместо Docker? Сейчас расскажу.
Чем заменить Docker на одиночном сервереЕсли контейнеры не нужны — systemd, venv, nginxЕсли на сервере работает одно приложение, база данных и nginx, контейнеризация вообще не нужна. В этом случае системные пакеты ставятся из репозитория, приложение запускается пользователем, а жизненным циклом процесса управляет systemd.
Важно, для Python-проекта сначала нужно установить модуль venv, создать системного пользователя и подготовить каталог приложения. Все команды ниже выполняются от root:
apt update
apt install python3-venv
useradd \
--system \
--user-group \
--home-dir /opt/myapp \
--shell /usr/sbin/nologin \
myapp
install -d -o myapp -g myapp /opt/myappПосле копирования кода и requirements.txt в /opt/myapp можно создать виртуальное окружение и установить зависимости. venv изолирует пакеты проекта от системного Python, а для запуска приложения активировать окружение необязательно. Достаточно использовать полный путь до интерпретатора:
runuser -u myapp -- \
/opt/myapp/venv/bin/python -m pip install \
-r /opt/myapp/requirements.txtПосле этого приложение оформляется как обычный systemd-сервис. Например, файл /etc/systemd/system/myapp.service может выглядеть так:
[Unit]
Description=My application
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=myapp
Group=myapp
WorkingDirectory=/opt/myapp
ExecStart=/opt/myapp/venv/bin/python /opt/myapp/app.py
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
Не забудьте вместо ExecStart указать команду запуска приложения, например Gunicorn, Uvicorn или собственный исполняемый файл.
После сохранения unit-файла systemd должен перечитать конфигурацию. Затем сервис можно запустить и добавить в автозагрузку:
systemctl daemon-reload
systemctl enable --now myapp
systemctl status myappЕсли приложение пишет сообщения в стандартный вывод и поток ошибок, они попадут в journald. PostgreSQL, Redis и nginx на Debian или Ubuntu можно установить из репозитория дистрибутива:
apt install nginx postgresql redis-serverЕсли нужны OCI-образы — PodmanИногда контейнеры всё же нужны, например, если приложение уже поставляется в OCI-образе, требуется несколько версий одной среды или вы используете контейнеры локально и хотите сохранить тот же способ развёртывания на сервере. В таком случае подойдёт Podman — он работает с теми же образами и поддерживает знакомые команды, но не требует постоянно запущенного центрального демона.
Главное преимущество Podman для одиночника — rootless mode. Вы можете запускать контейнеры от обычного пользователя, без sudo и добавления в группу docker. Контейнер думает, что внутри него root, но снаружи он работает от вашего UID.
Для того, чтобы запустить nginx используйте:
podman pull docker.io/library/nginx:alpine
podman run -d \
--name web \
-p 8080:80 \
docker.io/library/nginx:alpineПроверить, действительно ли Podman работает без root, можно командой:
podman info --format '{{.Host.Security.Rootless}}'Образы в Podman собираются через podman build. Команда работает с обычным Dockerfile или Containerfile и по синтаксису почти не отличается от docker build:
podman build -t myapp .
podman run -d --name myapp myappНо с Compose есть нюанс. Команда podman compose сама не реализует спецификацию Compose, а вызывает внешний провайдер, например podman-compose или docker compose. Соответствующий инструмент нужно установить отдельно:
podman compose up -dОднако Podman — чуть лучший Docker, но это не принципиально другой подход.
Если нужна отдельная пользовательская среда — systemd-nspawn.Когда приложению нужна не только изоляция процесса, но и полноценная файловая система со своим systemd, пакетным менеджером и набором служб, можно использовать systemd-nspawn.
Утилита входит в состав systemd и работает с каталогом, где развёрнута корневая файловая система. Контейнер запускается как обычный systemd-сервис, а его состояние и логи доступны через стандартные команды.
На Debian или Ubuntu окружение можно подготовить через debootstrap:
apt install debootstrap systemd-container
debootstrap stable \
/var/lib/machines/mycontainer \
https://deb.debian.org/debianПосле этого контейнер запускается командой:
systemd-nspawn \
-D /var/lib/machines/mycontainer \
-bФлаг -b загружает systemd внутри контейнера. Управлять средой можно через machinectl:
machinectl list
machinectl shell mycontainer
machinectl status mycontainer
journalctl -M mycontainerДля автозапуска используйте:
systemctl enable --now systemd-nspawn@mycontainer.serviceК слову, этот вариант больше подходит для тестовых сред, старых приложений с нестандартными библиотеками и сервисов, которым нужен собственный набор системных пакетов.
Если нужны системные контейнеры и снапшоты — IncusЕсли Docker и Podman в первую очередь запускают отдельные приложения, то Incus работает с системными контейнерами. Внутри такого контейнера находится почти полноценная Linux-система со своим пакетным менеджером, systemd, пользователями и набором служб. По модели работы это ближе к лёгкой ВМ, хотя контейнеры по-прежнему используют ядро хоста.
Incus появился как форк LXD и использует LXC в качестве низкоуровневой основы. Сам LXC отвечает за namespaces, cgroups и другие механизмы изоляции, а Incus добавляет управление образами, сетями, хранилищами, снапшотами и жизненным циклом контейнеров.
Создать две изолированные системы с Debian можно командами:
incus launch images:debian/12 production
incus launch images:debian/12 stagingПосмотреть список экземпляров и открыть оболочку внутри одного из них:
incus list
incus exec production -- bashКаждому контейнеру можно назначить собственный IP-адрес, ограничить число ядер и объём памяти:
incus config set production limits.cpu 2
incus config set production limits.memory 2GiBДля серверной эксплуатации обычно используют непривилегированные контейнеры. В этом режиме root внутри контейнера отображается на непривилегированный UID хоста. Если процесс вырвется за пределы контейнера, он не получит права root на основной системе.
Текущую карту идентификаторов можно посмотреть так:
incus config get production volatile.idmap.currentК слову, Incus оправдан, когда на одном физическом или виртуальном сервере нужно разместить несколько изолированных Linux-систем, дать им отдельные сетевые интерфейсы, настроить лимиты ресурсов и делать снапшоты.
Если нужно ограничить один процесс — FirejailFirejail — это SUID-программа, которая создаёт песочницу для запуска приложений через namespaces и seccomp. Она появилась в 2015 году и изначально создавалась для десктопных приложений (запускать браузер или PDF-ридер в изоляции). Но она неплохо работает и на сервере.
Для установки и запуска используйте:
# Установить
apt install firejail
# Запустить без доступа к сети
firejail --net=none /usr/bin/myapp
# Запустить с временным домашним каталогом
firejail --private /usr/bin/myappFirejail использует профили — текстовые файлы, которые описывают, что приложению разрешено. Некоторые уже включены в поставку, но вы можете написать свой:
cat > /etc/firejail/myapp.profile << 'EOF'
include /etc/firejail/disable-common.inc
include /etc/firejail/disable-devel.inc
whitelist /var/lib/myapp
whitelist /var/log/myapp
caps.drop all
nonewprivs
protocol unix,inet,inet6
seccomp
EOFГотовый профиль нужно проверить под конкретное приложение. Для запуска с профилем есть команда:
firejail \
--profile=/etc/firejail/myapp.profile \
/usr/bin/myappЭтот способ не заменяет Docker, но если вам нужно просто изолировать одно приложение на сервере, ограничить его доступ к файловой системе и сети, Firejail — ваш выбор.
Если нужна изоляция файловой системы — chroot + namespacesИногда лучший контейнер — это тот, которого нет. Если вам нужна всё-таки изоляция файловой системы, chroot решает эту задачу с 1979 года. Добавьте к нему Linux namespaces (clone с флагами), и вы получите минимальный контейнер без всякого Docker.
Проще не копировать бинарники и библиотеки вручную, а сразу подготовить минимальную систему через debootstrap:
apt install debootstrap
debootstrap --variant=minbase stable \
/var/lib/jail/myapp \
https://deb.debian.org/debian
chroot /var/lib/jail/myapp /bin/bashДля дополнительной изоляции можно использовать unshare:
unshare \
--mount \
--pid \
--net \
--fork \
--mount-proc \
--root=/var/lib/jail/myapp \
/bin/bashКоманда создаёт отдельные mount, PID и network namespaces.
chroot требует ручной работы (настройку UID mapping, сети, файловых монтирований, capabilities, seccomp, cgroups и жизненного цикла процесса), но если вам нужно изолировать одно приложение на сервере, этот вариант даст минимальный оверхед.
Когда Docker всё же нужОнЕсть сценарии, где Docker — правильный выбор даже для одного сервера, например:
ваш проект требует Redis, PostgreSQL, Elasticsearch, Celery и пяти микросервисов — в этом случае docker compose сэкономит часы на настройке.
вам нужно, чтобы окружение на сервере точно совпадало с окружением разработчика — Dockerfile позволяет воспроизводить пользовательское окружение, но архитектура процессора, ядро и настройки хоста по-прежнему будут влиять на работу приложения;
ваш пайплайн собирает Docker-образ и деплоит его (логично, да?);
ваше приложение уже упаковано в Docker, переписывать его под systemd бессмысленно (также логично).
О том, что лучше выбрать… Если вы сисадмин с 10–15-летним стажем, у вас стоит сервер с Debian, на нём работают nginx, PostgreSQL и приложение на Python, а логи, резервные копии и мониторинг через node_exporter и Prometheus давно настроены, то вы точно не читаете эту статью. Вы и так все знаете без моих советов.
Если вы разработчик, который хочет поднять что-нибудь на дешёвом VDS, и вам важнее, чтобы работало и легко поддерживалось, начните с systemd, virtualenv и nginx. Если нужна простая песочница для одного процесса, посмотрите на Firejail. Для отдельной системной среды со своим systemd подойдёт systemd-nspawn.
Если нужны системные контейнеры с отдельными сетями и снапшотами, используйте Incus. Если вы привыкли к Docker, но хотите обойтись без центрального root-демона, попробуйте Podman. А chroot и unshare выбирайте только для доверенных приложений и задач, где вы готовы настраивать изоляцию вручную.
Делитесь в комментариях, чем вы пользуетесь на своих серверах и почему.
© 2026 ООО «МТ ФИНАНС»
| # | Наименование новости | Тональность | Информативность | Дата публикации |
|---|---|---|---|---|
| 1 | Многоэтапные сборки в Docker: как уменьшить образ с 1,2 ГБ до 50 МБ | 5 | 8 | 28-06-2026 |
| 2 | Как я подружил self-hosted Supabase с VictoriaMetrics, VictoriaLogs, Grafana и Vector | 5 | 7 | 13-07-2026 |
| 3 | Инвентаризируем контейнеры с помощью Wazuh-агента | 0 | 5 | 26-06-2026 |
| 4 | Своя self-hosted двухсерверная VPN-архитектура. Подробный путь разработки и ошибки, с которыми вы можете столкнуться | 7 | 8 | 13-07-2026 |
| 5 | Когда TIME_WAIT становится врагом | -1 | 8.96 | 22-07-2026 |
| 6 | Сможет ли DB Client от OpenIDE заменить DataGrip? | 0 | 5 | 16-07-2026 |
| 7 | Ошибки не должны быть безмолвными: Sentry, Firebase Crashlytics и Datadog в одном Flutter‑приложении | 0 | 7.47 | 22-07-2026 |
| 8 | Query‑first подход или как из SQL запросов или MongoDB контрактов получить готовое REST API | 5 | 7 | 06-07-2026 |
| 9 | Как я писал диплом в LaTeX: Docker, CI/CD, Latexmk, Mermaid, и многое другое | 5 | 8 | 28-06-2026 |
| 10 | Организовал весь пентест-арсенал в одном месте: всё под рукой, офлайн и на русском | 5 | 7 | 28-06-2026 |