Docker упаковывает приложение вместе с зависимостями в изолированный контейнер, который запускается одинаково на любой машине с установленным движком. На VPS это избавляет от конфликтов версий PHP или Node.js между разными проектами на одном сервере.
Установка Docker через официальный скрипт
curl -fsSL https://get.docker.com | sh
systemctl enable --now docker
# Добавляем пользователя в группу docker (без sudo)
usermod -aG docker $USER
newgrp docker
Официальный скрипт сам определяет дистрибутив и подключает нужный репозиторий — для production предпочтительнее явная установка по инструкции docs.docker.com под конкретную версию Ubuntu или Debian, чтобы зафиксировать пакет, а не получать последнюю версию скриптом при каждом новом сервере.
Установка Docker Compose v2
apt install docker-compose-plugin -y
docker compose version
Первый контейнер
# Запуск Nginx в контейнере
docker run -d \
--name mynginx \
-p 80:80 \
-v /var/www/html:/usr/share/nginx/html:ro \
nginx:alpine
# Проверка
docker ps
curl http://localhost
Основные команды Docker
| Команда | Описание |
|---|---|
| docker ps -a | Все контейнеры |
| docker images | Список образов |
| docker logs -f name | Логи контейнера (live) |
| docker exec -it name bash | Войти в контейнер |
| docker stats | Использование ресурсов |
| docker system prune | Очистка неиспользуемых данных |
Разбор типичных ошибок
Ошибка docker: permission denied while trying to connect to the Docker daemon socket появляется, когда пользователь не входит в группу docker либо изменение группы ещё не подхватилось в текущей сессии. Команда newgrp docker или повторный вход по SSH решает проблему без перезагрузки сервера.
docker: Error response from daemon: driver failed programming external connectivity on endpoint mynginx: Bind for 0.0.0.0:80 failed: port is already allocated
Эта ошибка значит, что порт 80 на хосте уже занят — либо другим контейнером, либо системным Nginx или Apache вне Docker. Проверяется командой ss -tulpn | grep :80 до запуска контейнера, а не после отладки непонятного отказа.
Контейнер завершается сразу после запуска (статус Exited (0) или с ненулевым кодом) — обычно значит, что основной процесс внутри контейнера отработал и вышел, а Docker не держит контейнер живым сам по себе. Причина смотрится в логах: docker logs mynginx покажет, что именно пошло не так на старте — от отсутствующего конфига до ошибки в entrypoint-скрипте.
Docker и файрвол: важная деталь
Docker прописывает собственные правила в iptables напрямую, в обход UFW. Опубликованный порт контейнера (-p 8080:8080) может остаться доступным снаружи, даже если в UFW стоит ufw deny 8080 — правила Docker в цепочке DOCKER-USER применяются раньше, чем успевает сработать политика UFW. Если нужен контроль доступа к портам контейнеров через файрвол, правила добавляются именно в цепочку DOCKER-USER, а не через обычный ufw, — иначе создаётся ложное чувство защищённости, разобранное в статье про настройку UFW на VDS.
Сравнение Docker и обычной установки приложения
| Параметр | Docker-контейнер | Установка напрямую на хост |
|---|---|---|
| Изоляция зависимостей | Полная, свои версии библиотек | Общая с системой, конфликты версий возможны |
| Перенос на другой сервер | Образ переносится как есть | Нужно повторять установку и настройку |
| Потребление ресурсов | Небольшой оверхед на движок | Минимальный, без прослойки |
| Отладка на низком уровне | Сложнее, нужен вход в контейнер | Прямой доступ к процессам и файлам |
Когда Docker не подходит
- Единственное приложение на всём VDS и без планов масштабирования — оверхед на изучение Docker может не окупиться против прямой установки пакета из репозитория.
- Приложению нужен прямой доступ к устройствам или ядру хоста (специфичные драйверы, низкоуровневая работа с сетью) — контейнеризация такого требует привилегированного режима, что снижает саму пользу изоляции.
- Команда не готова контролировать файрвол на уровне цепочки
DOCKER-USER— иначе публикация портов контейнеров может незаметно открыть больше, чем предполагалось в UFW. - Нужна максимальная производительность дисковых операций без прослойки — оверлейная файловая система Docker добавляет накладные расходы по сравнению с прямой записью на хостовую ФС.
Проверка результата
- Проверьте, что демон запускается автоматически:
systemctl is-enabled dockerдолжно вернутьenabled. - Убедитесь, что непривилегированный пользователь может выполнять команды docker без sudo:
docker psиз-под обычного пользователя не должен требовать пароль или падать с ошибкой доступа. - Проверьте реальную доступность опубликованного порта снаружи, а не только через
curl http://localhostна самом сервере. - Сверьте правила файрвола для портов контейнеров:
iptables -L DOCKER-USER -nпокажет, что реально фильтруется на уровне Docker, отдельно от выводаufw status.