MHOSTMHOST

Docker и Docker Compose

Docker запускает приложения в изолированных контейнерах — без ручной установки зависимостей и конфликтов версий на хосте. В этой статье — установка Docker Engine и плагина Docker Compose на mHost VPS, запуск первого контейнера и разбор docker-compose.yml на примере из двух сервисов.

Docker — это контейнеры, а не виртуализация

Docker контейнеризирует приложения на уровне ОС: все контейнеры на сервере используют одно и то же ядро Linux хост-системы и изолированы друг от друга штатными механизмами ядра (namespaces, cgroups) — без гипервизора и без гостевых операционных систем внутри. Именно поэтому контейнеры лёгкие и быстро стартуют: это не «маленькая виртуальная машина», а обычный процесс, изолированный на том же ядре.

Важно: на виртуальных серверах mHost отключена вложенная виртуализация (nested virtualization) — поднять свой гипервизор, запустить вложенную VM или программный эмулятор (KVM и подобные) внутри VPS не получится. Docker вложенной виртуализацией не является и аппаратные расширения виртуализации не использует — он работает через контейнеры ядра, поэтому прекрасно устанавливается и работает на любом VPS mHost без каких-либо дополнительных настроек.

Что понадобится

  • VPS mHost на Ubuntu 22.04/24.04, Debian 11/12 или AlmaLinux/Rocky Linux 8/9.
  • Доступ по SSH под root или пользователем с правами sudo.
  • Публичный IP сервера — понадобится, чтобы проверить контейнер из браузера.

Шаг 1. Установите Docker Engine и плагин Docker Compose

Готового рецепта для Docker в VMmanager 6 нет (в отличие, например, от LEMP или Django — полный список в статье «Готовые рецепты VMmanager 6») — ставим вручную, любым из способов ниже.

Ставить будем docker-ce — официальную сборку Docker, а не docker.io из репозитория дистрибутива (там обычно более старая версия). Плагин Compose (docker-compose-plugin) ставится тем же пакетным менеджером и добавляет команду docker compose (два слова, без дефиса) — современную замену старому отдельному бинарнику docker-compose (через дефис), который больше не развивается.

Официальный репозиторий: Ubuntu и Debian

Если раньше на сервере уже стоял Docker из репозитория дистрибутива, сначала уберите старые пакеты:

bash
sudo apt remove $(dpkg --get-selections docker.io docker-compose docker-compose-v2 docker-doc podman-docker containerd runc | cut -f1)
Совет: если ни один из этих пакетов не установлен, команда просто выведет безобидную ошибку — на чистом сервере это нормально, идите дальше.

Подключите официальный репозиторий Docker и поставьте пакеты:

bash
sudo apt update
sudo apt install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

sudo tee /etc/apt/sources.list.d/docker.sources <<EOF
Types: deb
URIs: https://download.docker.com/linux/ubuntu
Suites: $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}")
Components: stable
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/docker.asc
EOF

sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Совет: на Debian команды те же — замените ubuntu на debian в двух местах: в URL GPG-ключа (.../linux/ubuntu/gpg) и в строке URIs: файла репозитория.

Официальный репозиторий: AlmaLinux и Rocky Linux

Обе системы RHEL-совместимы, поэтому подходит официальный репозиторий Docker для RHEL:

bash
sudo dnf -y install dnf-plugins-core
sudo dnf config-manager --add-repo https://download.docker.com/linux/rhel/docker-ce.repo
sudo dnf install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo systemctl enable --now docker

При установке dnf спросит подтверждение GPG-ключа репозитория — сверьте показанный отпечаток с указанным на официальной странице docs.docker.com/engine/install/rhel/ и только потом подтверждайте.

Проверьте: если dnf не находит пакеты по репозиторию .../linux/rhel/docker-ce.repo на вашей версии AlmaLinux/Rocky, попробуйте вариант для CentOS — https://download.docker.com/linux/centos/docker-ce.repo (тоже официальный, для RHEL-совместимых систем).

Быстрый способ: скрипт get.docker.com

Для теста или разработки Docker можно поставить одной командой — универсальным скриптом, который сам определяет дистрибутив:

bash
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
Важно: скрипт get.docker.com не рекомендован для продакшена — он ставит только последнюю стабильную версию без выбора конкретной, не умеет обновлять уже установленный Docker и не учитывает частные настройки окружения. Для боевого сервера используйте официальный репозиторий выше. Скрипты из интернета стоит сначала посмотреть — можно прогнать sudo sh get-docker.sh --dry-run, чтобы увидеть, что он сделает, не выполняя действий.

Шаг 2. Проверьте установку

bash
sudo systemctl status docker
sudo docker run hello-world

Если всё в порядке, docker run hello-world сообщит, что клиент Docker успешно связался с демоном, скачал тестовый образ и запустил его.

Готово: Docker Engine и Docker Compose установлены и работают.

Запуск без sudo (опционально)

По умолчанию управлять Docker может только root (или пользователь через sudo) — демон работает от root, а сокет /var/run/docker.sock доступен только ему и группе docker. Чтобы выполнять команды docker от обычного пользователя без sudo:

bash
sudo groupadd docker
sudo usermod -aG docker $USER
newgrp docker
docker run hello-world

(если группа docker уже существует — а после установки docker-ce через apt/dnf так обычно и есть — groupadd просто сообщит, что группа уже есть, это не ошибка)

Важно: группа docker фактически равнозначна правам root — любой пользователь в этой группе может смонтировать корень файловой системы хоста внутрь контейнера. Добавляйте в неё только тех, кому вы доверяете административный доступ к серверу.

Дальше по статье команды docker/docker compose для единообразия даны с sudo — если вы настроили доступ без пароля, как выше, sudo можно опустить.

Шаг 3. Запустите первый контейнер

Поднимите Nginx в фоне с проброшенным портом 80:

bash
sudo docker run -d --name web --restart unless-stopped -p 80:80 nginx:alpine
  • -d — запустить в фоне (detached).
  • --name web — имя контейнера, чтобы не запоминать случайный ID.
  • --restart unless-stopped — перезапускать контейнер автоматически, в том числе после перезагрузки сервера, пока вы явно не остановите его сами.
  • -p 80:80 — пробросить порт 80 хоста на порт 80 внутри контейнера.

Проверьте, что контейнер запущен, и откройте IP сервера в браузере:

bash
sudo docker ps
curl -I http://localhost
Важно: порт 80 должен быть открыт в firewall, иначе снаружи сервер будет недоступен. Проверьте и при необходимости откройте порт — см. статью «Настройка firewall: ufw».

Когда контейнер больше не нужен для примеров ниже, остановите и удалите его — иначе он займёт порт 80, который понадобится в следующем шаге:

bash
sudo docker rm -f web

Шаг 4. docker-compose.yml на практике

Compose описывает сразу несколько контейнеров одним файлом — вместо того чтобы вручную набирать docker run с десятком флагов для каждого сервиса.

Создайте каталог проекта и файл со статической страницей:

bash
mkdir -p ~/myapp/html && cd ~/myapp
echo "<h1>Hello from Docker Compose</h1>" > html/index.html

Создайте файл docker-compose.yml:

bash
nano docker-compose.yml
yaml
services:
  web:
    image: nginx:alpine
    container_name: web
    restart: unless-stopped
    ports:
      - "80:80"
    volumes:
      - ./html:/usr/share/nginx/html:ro
    depends_on:
      - db

  db:
    image: postgres:16
    container_name: db
    restart: unless-stopped
    environment:
      POSTGRES_DB: appdb
      POSTGRES_USER: appuser
      POSTGRES_PASSWORD: change_me
    volumes:
      - db_data:/var/lib/postgresql/data

volumes:
  db_data:

Что тут происходит:

  • services — список контейнеров проекта: web (Nginx) и db (PostgreSQL).
  • image — какой образ использовать; restart — политика перезапуска, как и в docker run.
  • ports — проброс портов хост:контейнер, как флаг -p.
  • volumes — у web это bind-монтирование каталога ./html с хоста внутрь контейнера, только для чтения (:ro); у db — именованный volume db_data, где PostgreSQL хранит данные отдельно от жизненного цикла контейнера.
  • environment — переменные окружения внутри контейнера.
  • depends_on — Compose запустит db раньше, чем web.
Важно: смените POSTGRES_PASSWORD: change_me на собственный пароль, прежде чем использовать этот файл на настоящем сервере.

Запустите проект:

bash
sudo docker compose up -d
sudo docker compose ps
Важно: если контейнер web из шага 3 всё ещё запущен, порт 80 уже занят — удалите его (sudo docker rm -f web) перед запуском Compose. И убедитесь, что порт 80 открыт в firewall — см. статью «Настройка firewall: ufw».

Посмотреть логи и остановить проект:

bash
sudo docker compose logs -f
sudo docker compose down
Совет: docker compose down останавливает и удаляет контейнеры и сеть, но именованный volume db_data остаётся — данные PostgreSQL не потеряются к следующему docker compose up -d. Чтобы удалить и данные тоже, используйте docker compose down -v — это необратимо.

Частые команды

Docker

  • docker pull <образ> — скачать образ без запуска.
  • docker images — список скачанных образов.
  • docker build -t <имя> . — собрать образ из Dockerfile в текущем каталоге.
  • docker ps — список запущенных контейнеров.
  • docker ps -a — список всех контейнеров, включая остановленные.
  • docker logs -f <контейнер> — логи контейнера в реальном времени.
  • docker exec -it <контейнер> sh — открыть shell внутри работающего контейнера (на образах Debian/Ubuntu вместо sh обычно доступен bash).
  • docker stop <контейнер> / docker start <контейнер> / docker restart <контейнер> — остановить / запустить / перезапустить.
  • docker rm <контейнер> — удалить остановленный контейнер (-f — принудительно, даже если он запущен).
  • docker rmi <образ> — удалить образ.
  • docker system prune — удалить неиспользуемые контейнеры, образы и сети, освободить место на диске.

Docker Compose

  • docker compose up -d — создать и запустить все сервисы проекта в фоне.
  • docker compose ps — статус сервисов текущего проекта.
  • docker compose logs -f — логи всех сервисов проекта в реальном времени.
  • docker compose stop / docker compose restart — остановить / перезапустить сервисы без удаления контейнеров.
  • docker compose down — остановить и удалить контейнеры и сеть проекта (volume’ы остаются).
  • docker compose exec <сервис> sh — shell внутри контейнера конкретного сервиса.
  • docker compose pull — обновить образы сервисов до актуальных версий.

Что дальше

Если вам не принципиален именно Docker и нужен просто готовый веб-стек (LAMP/LEMP) или конкретное приложение (Zabbix, Tomcat и другие) — возможно, для него уже есть готовый рецепт в VMmanager 6, который поставит всё в один клик: см. статью «Готовые рецепты VMmanager 6». Если контейнеры смотрят наружу — не забудьте про firewall: «Настройка firewall: ufw».