Docker на VPS давно перестал быть экзотикой: в контейнерах разворачивают и одиночного Telegram-бота, и связку из веб-сервера, приложения, базы, очереди и мониторинга. Работает это хорошо, но у контейнеров есть свои расходы по памяти и диску и несколько ловушек, о которых узнают уже после аварии, — самая неприятная из них открывает порты базы данных в интернет в обход firewall. Разберём, сколько ресурсов закладывать, какой тариф брать под типовые связки и что настроить сразу после установки.
Что должен уметь сервер
Docker нужна полноценная виртуализация, где у машины своё ядро, — KVM. На контейнерной виртуализации (OpenVZ, LXC) ядро общее с соседями, и Docker там либо не запускается, либо работает с ограничениями. Это первое, что стоит проверить перед покупкой. У провайдера, тарифы которого мы отслеживаем, на страницах каталога указана виртуализация KVM, так что Docker и docker compose работают без плясок. Подробнее о типах виртуализации — в статье «VPS и VDS: в чём разница».
Что контейнеры дают, а что нет
Дают:
- Одинаковое окружение на машине разработчика и на сервере — оно описано в файле, а не собрано руками.
- Простое обновление и откат:
docker compose pull && docker compose up -d, а если что-то пошло не так — вернуть предыдущий тег образа. - Изоляцию зависимостей: два проекта с разными версиями PHP, Node или Python спокойно живут на одном сервере.
- Переезд за минуты: на новом сервере нужен только Docker, файл compose и данные томов.
Не дают:
- Границу безопасности уровня отдельной машины. Ядро общее, и уязвимость в нём касается всех контейнеров сразу. Для разделения доверенного и чужого кода контейнера мало.
- Скорости. Накладные расходы невелики, но медленный код в контейнере остаётся медленным.
- Сохранности данных. Образ пересобирается, данные — нет. Тома нужно копировать так же, как обычные файлы и базы.
Сколько памяти занимают контейнеры
Сам демон Docker забирает 50–100 МБ. Дальше каждый контейнер несёт свой процесс и библиотеки. Ориентиры в спокойном режиме:
| Контейнер | Память |
|---|---|
| Nginx, Caddy, Traefik | 10–50 МБ |
| Redis для кэша | 10–100 МБ + объём данных |
| Бот или API на Python / Go | 30–200 МБ |
| Приложение на Node.js | 100–300 МБ |
| PHP-FPM с WordPress | 150–400 МБ |
| PostgreSQL | 100–400 МБ, больше под кэш данных |
| MySQL / MariaDB | 300–600 МБ |
| Prometheus + Grafana | 300–700 МБ |
Сложите свою связку и добавьте 30% на пики и 300–400 МБ на систему. Как считать по компонентам в общем случае — в статье «Как выбрать тариф VPS».
Какой тариф под какую связку
| Что запускаете | Тариф | Цена/мес |
|---|---|---|
| 1–2 бота или небольшой API | Lite: 1 ядро, 1 ГБ, 20 ГБ | $6 |
| Сайт: прокси + приложение + база | Start: 2 ядра, 2 ГБ — впритык; Medium: 3 ядра, 4 ГБ — комфортно | $10–20 |
| Приложение + база + Redis + воркер очереди + прокси | Medium–Premium: 4–8 ГБ | $20–40 |
| Несколько проектов или self-hosted инструменты (Gitea, Nextcloud, мониторинг) | Premium–Elite: 8–16 ГБ | $40–60 |
Цены — для Европы, России, Казахстана и Северной Америки. Отдельно про диск: каждый образ весит от 50 МБ до гигабайта, а старые версии копятся после каждого обновления. На 20 ГБ Lite это заканчивается быстрее, чем кажется, — закладывайте запас и настройте очистку (ниже).
Для контейнеров полезен NVMe: запуск, сборка и базы в томах много работают с файловой системой. NVMe стоит во всех тарифах Финляндии, Нидерландов и Чехии.
Medium в Финляндии, NVMe — $20/мес Premium в Нидерландах, NVMe — $40/мес
Установка
Сначала базовая настройка сервера — пользователь, ключи, firewall, обновления: 10 шагов после покупки. Затем Docker из официального репозитория:
curl -fsSL https://get.docker.com | sh sudo usermod -aG docker deploy
После перелогина пользователь deploy сможет запускать docker без sudo. Учтите: членство в группе docker фактически равно root-доступу, поэтому давайте его только тем, кому доверяете как администратору.
Пять вещей, которые настроить сразу
1. Не открывать базу в интернет в обход firewall
Самая опасная ловушка. Docker сам пишет правила iptables, и порт, опубликованный как ports: - "5432:5432", становится доступен из интернета даже при включённом ufw с запретом этого порта. Именно так в сеть утекают базы с паролем по умолчанию.
Правило простое: наружу публикуется только обратный прокси на 80 и 443. Внутренние сервисы общаются по сети compose, без ports вовсе. Если порт нужен вам для отладки — привязывайте к localhost:
ports: - "127.0.0.1:5432:5432"
Проверить, что реально открыто наружу, можно с другой машины: nmap -Pn IP_СЕРВЕРА.
2. Ротация логов
По умолчанию логи контейнеров пишутся без ограничений и однажды съедают весь диск — одна из самых частых аварий на Docker-серверах. В /etc/docker/daemon.json:
{
"log-driver": "json-file",
"log-opts": { "max-size": "10m", "max-file": "3" }
}
Затем sudo systemctl restart docker. Настройка действует на контейнеры, созданные после неё, — существующие пересоздайте через docker compose up -d --force-recreate.
3. Лимиты памяти и процессора
Без лимитов один контейнер с утечкой памяти может занять всю машину и уронить соседей, а ядро при нехватке памяти первым убьёт базу. В compose:
services:
app:
image: myapp:1.4
mem_limit: 512m
cpus: 1.0
restart: unless-stopped
Лимит ставьте с запасом над обычным потреблением: смотрите реальные цифры в docker stats.
4. Автозапуск
restart: unless-stopped у каждого сервиса — и после перезагрузки сервера всё поднимется само. Без этого простой продлится до того момента, когда вы заметите.
5. Очистка
Старые образы, остановленные контейнеры и кэш сборки копятся гигабайтами. Раз в неделю по cron:
0 4 * * 0 docker system prune -af --filter "until=168h"
Флаг --volumes сюда не добавляйте: он удалит тома, не привязанные к контейнерам, — а среди них могут оказаться данные остановленного сервиса.
Бэкапы данных в контейнерах
Базу копируйте дампом изнутри контейнера, а не копированием файлов работающей базы:
docker exec db pg_dump -U app appdb | gzip > /var/backups/appdb.sql.gz docker exec mysql mysqldump -u root -p"$PASS" --all-databases | gzip > /var/backups/mysql.sql.gz
Файловые тома — архивом через временный контейнер:
docker run --rm -v uploads:/data -v /var/backups:/backup alpine \ tar czf /backup/uploads.tgz -C /data .
Дальше эти файлы забирает бэкап-сервер в другой стране. Как настроить так, чтобы взломщик не мог удалить копии, — в статье «Сервер для бэкапа».
Собирайте образы не на сервере
Сборка образа требовательна к процессору и диску: на Lite или Start она может занимать десятки минут и заметно тормозить работающие сервисы. Правильнее собирать образы в CI (GitHub Actions, GitLab CI) или на своём компьютере, отправлять в реестр, а на сервере делать только docker compose pull. Если собирать всё же приходится на сервере, упор будет в частоту процессора — здесь выигрывает HI-CPU на Ryzen.
Панель управления и Docker
Хостинговые панели вроде ISPmanager рассчитаны на собственную структуру конфигов и плохо уживаются с контейнерами, которые сами управляют портами и сетями. Если проект в Docker, обходитесь без панели или используйте интерфейс, сделанный для контейнеров, — например, Portainer. Подробнее о выборе — в статье «Панель или консоль».
Коротко
- Docker нужна KVM-виртуализация — проверьте до покупки.
- Считайте память по контейнерам: связка «прокси + приложение + база» комфортно живёт на 4 ГБ (Medium, $20).
- Не публикуйте порты базы наружу: Docker обходит ufw. Внутренние сервисы — без
portsили на 127.0.0.1. - Сразу настройте ротацию логов, лимиты памяти,
restart: unless-stoppedи еженедельную очистку. - Базы копируйте дампом, тома — архивом, и храните копии на другом сервере.
- Образы собирайте в CI, на сервер — только pull.
