Если вы используете контейнеры на VDS и хотите упростить стек, уменьшить накладные расходы и усилить безопасность, переход на связку containerd + nerdctl — логичный шаг. containerd — это контейнерный рантайм промышленного уровня (его использует Kubernetes), а nerdctl — совместимая с Docker CLI, которая предоставляет привычные команды вроде run, pull, logs и даже compose. В этой статье покажу, как поднять связку на VDS, включить cgroup v2, настроить rootless-режим, автозапуск через systemd, а также как мигрировать с Docker/Compose без простоя.
Зачем переходить с Docker на containerd + nerdctl
Docker удобен «из коробки»: демоны, CLI, compose, buildx. Но за удобство мы платим избыточной сложностью и зависимостями. containerd — это ядро выполнения контейнеров, без лишних прослоек. Вместе с nerdctl вы получаете:
- Привычные команды и совместимость с Docker-образами (
images,pull/push,run,exec,logs,compose). - Меньше движущихся частей и демонов — проще сопровождать на VDS.
- Нативную поддержку
cgroup v2и интеграцию сsystemd(SystemdCgroup=true). - Безопасный
rootless-режим без привилегий root. - Гибкую работу с реестрами (авторизация, зеркала, политики, TLS).
Главная мысль: вы сохраняете привычные воркфлоу и формат образов, но упрощаете базовую платформу. На VDS это означает меньше рисков и меньше накладных расходов.
Подготовка VDS: ядро, cgroup v2, overlay
Для стабильной работы containerd важно включить cgroup v2, иметь overlayfs и актуальное ядро с поддержкой необходимых пространств имён. Проверьте окружение:
uname -r
stat -fc %T /sys/fs/cgroup
lsmod | grep overlay
Идеально, если вывод показывает cgroup2fs и загруженный модуль overlay. Если у вас старая система, включите единое древо групп (для старых релизов):
sudo sed -i 's/GRUB_CMDLINE_LINUX="\(.*\)"/GRUB_CMDLINE_LINUX="\1 systemd.unified_cgroup_hierarchy=1"/' /etc/default/grub
sudo update-grub
sudo reboot
Проверьте сетевой стек (форвардинг и nftables/iptables):
sudo sysctl net.ipv4.ip_forward
sudo sysctl net.ipv6.conf.all.forwarding
sudo iptables -L -n
sudo nft list ruleset
Для большинства случаев хватит стандартной конфигурации ядра современных дистрибутивов (Debian 12, Ubuntu 22.04+, AlmaLinux/Rocky 9). Если overlay не загружается автоматически, добавьте модуль в автозагрузку:
echo overlay | sudo tee /etc/modules-load.d/overlay.conf
sudo modprobe overlay
Установка containerd и nerdctl
В дистрибутивах пакеты containerd и nerdctl есть в репозиториях. На Debian/Ubuntu:
sudo apt update
sudo apt install -y containerd nerdctl runc
На RHEL-совместимых системах:
sudo dnf install -y containerd nerdctl runc
Сгенерируйте и отредактируйте конфиг /etc/containerd/config.toml:
sudo containerd config default | sudo tee /etc/containerd/config.toml
sudo editor /etc/containerd/config.toml
Минимально рекомендую:
SystemdCgroup = trueв секции[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options].snapshotter = "overlayfs"в[plugins."io.containerd.grpc.v1.cri".containerd].- Отключить устаревшие или неиспользуемые плагины по необходимости.
Перезапуск и проверка:
sudo systemctl enable --now containerd
sudo systemctl status containerd
nerdctl info
nerdctl info должен показать доступные snapshotter’ы, поддержку cgroup v2 и информацию о рантайме (runc или crun, если установлен).

Первый запуск: образы, контейнеры, volumes, networks
Стандартные операции эквивалентны Docker:
nerdctl pull nginx:1.27
nerdctl images
nerdctl run -d --name web -p 8080:80 nginx:1.27
nerdctl ps
nerdctl logs -f web
nerdctl exec -it web bash
Директории данных по умолчанию:
/var/lib/containerd— данные containerd./var/lib/nerdctl— namespace’ы, сети, тома, состояние командnerdctl.
Создаём том и сеть:
nerdctl volume create webdata
nerdctl network create --subnet 10.12.0.0/24 appnet
Примонтируем том и подключим сеть:
nerdctl run -d --name app --network appnet -v webdata:/var/www/html php:8.2-apache
Миграция с Docker: образы, теги, перенос compose
Образы совместимы: можно использовать docker save/docker load или напрямую тянуть из registry. Варианты переноса:
- Через registry:
nerdctl pullнужные теги, затемnerdctl tagиnerdctl pushв свой реестр. - Файловый экспорт/импорт:
# На старом хосте с Docker
docker save myapp:1.0 | gzip > myapp-1.0.tar.gz
# На новом хосте
zcat myapp-1.0.tar.gz | nerdctl load
nerdctl images | grep myapp
Команды docker run часто можно перевести простым поиском-заменой на nerdctl run. Посмотрите внимательно на:
- Монтирование томов и права (uid/gid).
- Сетевые ключи:
--network, алиасы, публикация портов. - Ограничения ресурсов:
--cpus,--memory,--pids-limit,--ulimit. - Политику рестартов:
--restart=alwaysи т. п.
Перенос docker-compose.yml
nerdctl compose поддерживает привычные сценарии up / down / logs / ps и многое из формата Compose. В простых случаях достаточно выполнить:
cd /srv/myapp
nerdctl compose pull
nerdctl compose up -d
nerdctl compose ps
Обратите внимание на нюансы:
- Ключи
deploy(Swarm) игнорируются. - Плагины сетей/томов должны быть поддержаны (в типичных кейсах bridge/host/volume без экзотики — всё работает).
- Если используете
profiles, проверьте совместимость в вашей версииnerdctl. - Включите режим
SystemdCgroupв containerd, чтобы лимиты CPU/памяти сходились с ожиданиями. О нюансах cgroup и системных слайсов читайте в материале Настройка cgroup через systemd slices.
Логи и ротация: json-file и journald
По умолчанию nerdctl пишет логи контейнеров в собственные файлы в каталоге состояния. Можно переключить драйвер на journald (если сборка поддерживает), чтобы логи уходили в системный журнал:
nerdctl run -d --name web --log-driver=journald nginx:1.27
journalctl -u containerd --no-pager | tail -n 100
nerdctl logs web | tail -n 100
Для json-файлов используйте ротацию штатными средствами системы (logrotate) либо периодические очистки с учётом ретенции. Учитывайте, что высокочастотные логи на VDS быстро заполняют диск — задайте ретенцию и контроль объёмов.
Интеграция с systemd: автозапуск контейнеров и compose-стека
Базовая автоматизация — использовать --restart у контейнеров. Но для управляемых стэков удобнее отдельный unit, который поднимает и гасит nerdctl compose атомарно.
sudo tee /etc/systemd/system/myapp-compose.service > /dev/null << 'EOF'
[Unit]
Description=MyApp stack via nerdctl compose
After=network-online.target containerd.service
Wants=network-online.target
[Service]
Type=oneshot
WorkingDirectory=/srv/myapp
RemainAfterExit=yes
ExecStart=/usr/bin/nerdctl compose up -d
ExecStop=/usr/bin/nerdctl compose down
TimeoutStartSec=300
TimeoutStopSec=300
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now myapp-compose.service
sudo systemctl status myapp-compose.service
Такой unit гарантирует запуск после сети и containerd. Если у вас несколько проектов, создайте отдельные юниты на каждый. Для отдельных контейнеров можно аналогично оформить oneshot-юнит с ExecStart=nerdctl run ... и ExecStop=nerdctl stop. Про готовность сервисов лучше заботиться healthcheck-ами; про рестарты и healthchecks см. материал Перезапуски и проверки живости контейнеров.
Rootless: запуск без root, cgroup v2 и подводные камни
Rootless повышает безопасность: процессы не получают привилегий root на хосте. Требования:
cgroup v2, поддержкаuser namespaces, пакетыnewuidmap/newgidmap.- Настроенные
/etc/subuidи/etc/subgidдля пользователя. - Сетевой стек для непривилегированных:
slirp4netnsи при желанииrootlesskit.
sudo apt install -y slirp4netns uidmap
id -u
id -g
echo "$(whoami):100000:65536" | sudo tee -a /etc/subuid
echo "$(whoami):100000:65536" | sudo tee -a /etc/subgid
Установите и запустите rootless-containerd от своего пользователя. На многих системах доступна утилита настройки:
containerd-rootless-setuptool.sh install
systemctl --user enable --now containerd.service
loginctl enable-linger $(whoami)
Проверьте:
nerdctl --namespace k8s.io info
nerdctl --namespace default info
В rootless-режиме публикация «низких» портов (<1024) невозможна без дополнительных трюков. Обычно используют порты ≥1024 и проксируют наружу обратным прокси на хосте (например, Nginx) или системой порт-форвардинга на VDS. Сети bridge реализуются через slirp4netns — MTU может отличаться, что иногда влияет на производительность. Для быстрой диагностики сети в rootless проверьте iptables/nft и DNS из контейнера.
Registry: авторизация, зеркала, политики, TLS
С nerdctl вы можете пушить и тянуть образы в любой совместимый реестр. Авторизуйтесь:
nerdctl login registry.example.com
nerdctl push registry.example.com/myproj/myapp:1.0
nerdctl pull registry.example.com/myproj/myapp:1.0
Глобальные настройки зеркал и правил подключения к реестрам делаются через hosts.toml и конфиг containerd. Для конкретного реестра создайте каталог с хост-файлом, например:
sudo mkdir -p /etc/containerd/certs.d/registry.example.com
sudo tee /etc/containerd/certs.d/registry.example.com/hosts.toml > /dev/null << 'EOF'
server = "https://registry.example.com"
[host."https://registry.example.com"]
capabilities = ["pull", "resolve", "push"]
skip_verify = false
EOF
sudo systemctl restart containerd
Если у вас внутренний test-реестр с самоподписанным сертификатом, положите доверенные CA в соответствующий каталог и не отключайте проверку без крайней необходимости. Для продакшн-проектов оформляйте валидные SSL-сертификаты, чтобы избежать проблем с цепочкой доверия.
Compose: типовая структура проекта и приёмы
Типичная структура:
/srv/myapp
├── docker-compose.yml
├── .env
├── app
│ └── Dockerfile
└── config
Запуск:
cd /srv/myapp
nerdctl compose build
nerdctl compose up -d
nerdctl compose logs -f --tail=100
nerdctl compose ps
Несколько практических приёмов:
- Явно задавайте версии образов (pinning), избегайте
:latest. - Выносите секреты и конфиги в файлы, монтируйте как
bindили используйте механизмsecretsCompose; детали — в статье Секреты в Compose и их ротация. - Сеть назовите уникально, чтобы избежать пересечения с другими проектами на VDS.
- Используйте
depends_onтолько для порядка запуска, а готовность проверяйте healthcheck-скриптами внутри контейнеров и ретраями клиентов.

Ограничения и отличия от Docker
Несмотря на высокую совместимость, есть моменты:
- Не все возможности Docker Engine воспроизводимы один-в-один (особенно вокруг Swarm/stack, экзотических сетевых плагинов). Для Compose-стека это обычно не критично.
- На старых системах могут встретиться шероховатости с
cgroup v2, CPU/IO лимитами и совместимостью с конкретной версиейnerdctl. - Некоторые флаги логирования и драйверов в
nerdctlотличаются. Проверьте, что вы используете поддерживаемые варианты:json-fileи/илиjournald. - Rootless неизбежно накладывает сетевые ограничения и особенности производительности.
Обновления, резервное копирование и перенос
Процедуры обслуживания простые и прозрачные:
- Обновления образов:
nerdctl compose pull, затемnerdctl compose up -dс перезапуском изменившихся сервисов. - Бэкапы образов:
nerdctl image saveи хранение тарболов вместе с lock-файлами сборки. - Бэкапы томов: файловая копия каталогов из
/var/lib/nerdctl/<ns>/volumes/<name>/_dataс остановкой контейнеров или с использованием снапшотов ФС. - Перенос на другой VDS: перенесите compose-файлы, .env, образы (pull/save) и содержимое томов, затем поднимите через
nerdctl compose up -d.
Диагностика и типичные проблемы
Что проверить в первую очередь:
- containerd не стартует: смотрим
journalctl -u containerd, путь кconfig.toml, права каталогов/var/lib/containerd. - Лимиты ресурсов не применяются: включите
SystemdCgroup=true, убедитесь вcgroup v2, проверьте версиюrunc/crun. - Сеть не работает: проверьте nftables/iptables,
net.ipv4.ip_forward, конфликты подсетей, DNS в контейнере. - Порты заняты:
ss -lntpна хосте и в контейнерах, избегайте пересечений публикации портов между стэками. - Rootless не пускает на 80/443: публикуйте на 8080/8443 и проксируйте через Nginx на хосте, либо используйте cap_net_bind_service с осторожностью.
- Compose ругается на опции: проверьте версию
nerdctlи соответствие ключей формату, избегайте Swarm-специфичныхdeployв простых сценариях.
Безопасность и политика обновлений
Несколько практик для продакшн-стэков на VDS:
- Ограничивайте capabilities контейнерам (
--cap-drop=ALLи точечные добавления). - Старайтесь использовать
read-onlyrootfs, монтируйте только нужные каталоги и под нужными uid/gid. - Переходите на
crunдля более быстрой и строгой работы с cgroups (где доступно). - Поддерживайте актуальные версии
containerd/runc/nerdctlи ядра. Обновляйте базовые образы регулярно. - Сканируйте образы на уязвимости до пуша в registry в вашем CI.
Итоги
Связка containerd + nerdctl на VDS даёт лёгкую и предсказуемую платформу для контейнеров с минимальным отрывом от привычного Docker-опыта. С включённым cgroup v2, корректной интеграцией с systemd, поддержкой rootless и compose можно безопасно мигрировать существующие проекты, сократив сложность и повысив управляемость. Начните с тестового стенда, переведите один сервис в продакшн и постепенно выведите целиком стек Docker/Compose на containerd.


