Вход на сайт

Просмотр новости

Найдите то, что Вас интересует

Почему Docker не всегда лучший выбор и чем его заменить

Дата публикации: 21-07-2026 13:01:21

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

Основное содержимое страницы с новостью.

0d8692b5bdc189fd034e7785716ae497.png

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

За что Docker любят разработчики

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

Docker сделал контейнеры доступными, ведь до этого собирать файловую систему, настраивать изоляцию процессов, создавать сеть и отдельно продумывать доставку приложения на другой сервер нужно было практически вручную.

e7a592c6e0789e5bdaac621c5d5da367.png

В 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-систем, дать им отдельные сетевые интерфейсы, настроить лимиты ресурсов и делать снапшоты. 

Если нужно ограничить один процесс — Firejail 

Firejail — это SUID-программа, которая создаёт песочницу для запуска приложений через namespaces и seccomp. Она появилась в 2015 году и изначально создавалась для десктопных приложений (запускать браузер или PDF-ридер в изоляции). Но она неплохо работает и на сервере. 

Для установки и запуска используйте: 

# Установить

apt install firejail

# Запустить без доступа к сети

firejail --net=none /usr/bin/myapp

# Запустить с временным домашним каталогом

firejail --private /usr/bin/myapp

Firejail использует профили — текстовые файлы, которые описывают, что приложению разрешено. Некоторые уже включены в поставку, но вы можете написать свой:

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 МБ5828-06-2026
2Как я подружил self-hosted Supabase с VictoriaMetrics, VictoriaLogs, Grafana и Vector5713-07-2026
3Инвентаризируем контейнеры с помощью Wazuh-агента0526-06-2026
4Своя self-hosted двухсерверная VPN-архитектура. Подробный путь разработки и ошибки, с которыми вы можете столкнуться7813-07-2026
5Когда TIME_WAIT становится врагом-18.9622-07-2026
6Сможет ли DB Client от OpenIDE заменить DataGrip?0516-07-2026
7Ошибки не должны быть безмолвными: Sentry, Firebase Crashlytics и Datadog в одном Flutter‑приложении07.4722-07-2026
8Query‑first подход или как из SQL запросов или MongoDB контрактов получить готовое REST API5706-07-2026
9Как я писал диплом в LaTeX: Docker, CI/CD, Latexmk, Mermaid, и многое другое5828-06-2026
10Организовал весь пентест-арсенал в одном месте: всё под рукой, офлайн и на русском5728-06-2026

Классификация: Мнения. Схожих патентов: 0. Схожих новостей: 10. Тональность: 1. Информативность: 6.36. Источник: habr.com.