Docker на Ubuntu: Полное руководство по установке и использованию
Docker — это платформа контейнеризации с открытым исходным кодом, которая упаковывает приложения и их зависимости в изолированные переносимые единицы, называемые контейнерами. В отличие от виртуальных машин, контейнеры используют ядро ОС хоста совместно, что делает их значительно легче, быстрее в запуске и эффективнее с точки зрения использования ресурсов — критически важное отличие для тех, кто запускает рабочие нагрузки в среде VPS Хостинга, где вычислительные ресурсы напрямую влияют на стоимость и производительность.
Это руководство охватывает полный процесс установки Docker на Ubuntu 20.04, 22.04 и 24.04 LTS, включая усиление безопасности после установки, рабочие процессы Docker Compose и производственно-релевантные шаблоны команд, которые большинство руководств упускают.
Предварительные требования и системные требования
Прежде чем выполнять какую-либо команду, проверьте следующее:
- Версия Ubuntu: 20.04 LTS (Focal), 22.04 LTS (Jammy) или 24.04 LTS (Noble). Команда `lsb_release -cs`, используемая при настройке репозитория, автоматически определит ваше кодовое имя.
- Архитектура: `amd64`, `arm64` или `armhf` — все поддерживаются официальным репозиторием Docker.
- Версия ядра: Docker требует ядро Linux версии 3.10 или выше. Выполните `uname -r` для проверки.
- Привилегии пользователя: `sudo` или root-доступ обязательны для установки и управления демоном.
- Дисковое пространство: Минимум 2 GB свободного места на разделе, где расположен `/var/lib/docker` — именно там Docker хранит образы, контейнеры, тома и кэш сборки. В производственных системах монтируйте этот каталог на отдельный раздел или том.
Критически важный шаг перед установкой: Если вы ранее устанавливали Docker из стандартного репозитория `apt` Ubuntu (пакет `docker.io`), сначала удалите его, чтобы избежать конфликтов с официальными пакетами Docker CE:
“`bash
sudo apt remove docker docker-engine docker.io containerd runc
“`
Шаг 1: Обновление системных пакетов
Обновите индекс пакетов и установленные пакеты до последних версий перед добавлением нового репозитория:
“`bash
sudo apt update
sudo apt upgrade -y
“`
Это гарантирует, что резолвер зависимостей `apt` работает с актуальными метаданными пакетов и что базовые системные библиотеки не устарели — распространённый источник скрытых ошибок времени выполнения в контейнеризованных приложениях.
Шаг 2: Установка Docker Engine из официального репозитория
Стандартные репозитории `apt` Ubuntu содержат пакет `docker.io`, который поддерживается Canonical и, как правило, отстаёт на несколько версий от официального релиза Docker. Для производственного использования всегда устанавливайте из собственного репозитория Docker.
2.1 Установка зависимостей для транспорта и верификации
“`bash
sudo apt install apt-transport-https ca-certificates curl software-properties-common gnupg lsb-release -y
“`
Зачем нужен `gnupg`? Начиная с Ubuntu 22.04, `gpg` не всегда присутствует по умолчанию. Явное его включение предотвращает скрытый сбой при импорте GPG-ключа.
2.2 Добавление официального GPG-ключа Docker
“`bash
sudo install -m 0755 -d /usr/share/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg –dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
sudo chmod a+r /usr/share/keyrings/docker-archive-keyring.gpg
“`
Шаг `chmod a+r` часто пропускается в руководствах, но необходим в системах, где `apt` работает в контексте ограниченного пользователя — без него менеджер пакетов не сможет прочитать связку ключей и выдаст ошибку `NO_PUBKEY` при выполнении `apt update`.
2.3 Добавление стабильного репозитория Docker
“`bash
echo
"deb [arch=$(dpkg –print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg]
https://download.docker.com/linux/ubuntu
$(lsb_release -cs) stable" |
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
“`
Подстановка `arch=$(dpkg –print-architecture)` необходима на серверах на базе ARM. Жёсткое указание `amd64` — распространённая ошибка, которая приводит к скрытым сбоям разрешения пакетов на ARM-экземплярах.
2.4 Установка Docker Engine, CLI и плагинов
“`bash
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y
“`
Описание пакетов:
| Пакет | Роль |
|---|
| — | — |
|---|
| `docker-ce` | Демон Docker Engine (`dockerd`) |
|---|
| `docker-ce-cli` | Клиентский CLI (команда `docker`) |
|---|
| `containerd.io` | Низкоуровневая среда выполнения контейнеров (совместимая с OCI) |
|---|
| `docker-buildx-plugin` | Расширенные возможности сборки (мультиплатформенность, BuildKit) |
|---|
| `docker-compose-plugin` | Compose V2, интегрированный как плагин Docker CLI |
|---|
Примечание о `containerd.io`: Это не то же самое, что пакет `containerd` в стандартном репозитории Ubuntu. `containerd.io` от Docker — это конкретная, протестированная версия среды выполнения containerd. Смешивание двух версий является известной причиной сбоев при запуске демона.
Шаг 3: Проверка установки
Убедитесь, что демон активен и настроен на запуск при загрузке:
“`bash
sudo systemctl status docker
sudo systemctl enable docker
“`
Проверьте установленную версию:
“`bash
sudo docker –version
sudo docker info
“`
`docker info` более информативен, чем `–version` — он показывает используемый драйвер хранилища (обычно `overlay2`), драйвер cgroup (`systemd` или `cgroupfs`), а также количество CPU и объём памяти, доступных Docker.
Запустите стандартный тест:
“`bash
sudo docker run hello-world
“`
При успешном выполнении выводится сообщение «Hello from Docker!», подтверждающее корректную работу демона Docker, загрузки образа из Docker Hub и выполнения контейнера.
Шаг 4: Настройка Docker для доступа без прав root
По умолчанию сокет Docker (`/var/run/docker.sock`) принадлежит `root` и группе `docker`. Любой пользователь, не входящий в группу `docker`, должен использовать `sudo` для каждой команды Docker.
“`bash
sudo usermod -aG docker $USER
“`
Примените членство в группе без выхода из системы:
“`bash
newgrp docker
“`
Проверьте:
“`bash
docker run hello-world
“`
Предупреждение безопасности: Членство в группе `docker` фактически эквивалентно `sudo` без пароля. Пользователь в группе `docker` может легко смонтировать файловую систему хоста в контейнер и обойти все средства контроля доступа на уровне файловой системы. В многопользовательских системах или на общих серверах рассмотрите использование rootless Docker:
“`bash
dockerd-rootless-setuptool.sh install
“`
Режим rootless запускает демон Docker и контейнеры в непривилегированном пространстве имён пользователя, значительно сокращая поверхность атаки. Это рекомендуемая конфигурация для любой среды, где несколько пользователей используют один хост.
Шаг 5: Справочник основных команд Docker
Управление образами
“`bash
Pull a specific image version from Docker Hub
docker pull nginx:1.27-alpine
List locally cached images
docker images
Remove a specific image
docker rmi nginx:1.27-alpine
Remove all dangling (untagged) images to reclaim disk space
docker image prune
Remove all unused images (not just dangling)
docker image prune -a
“`
Совет для продакшена: Всегда используйте версионированные теги (например, `nginx:1.27-alpine`), а не `latest` в любых автоматизированных или производственных рабочих процессах. Тег `latest` является изменяемым — он может указывать на другой образ после отправки в реестр, нарушая воспроизводимость.
Жизненный цикл контейнера
“`bash
Run a container interactively with a pseudo-TTY
docker run -it ubuntu:22.04 /bin/bash
Run a container in detached mode with port mapping and a name
docker run -d -p 8080:80 –name my-nginx nginx:1.27-alpine
List running containers
docker ps
List all containers (including stopped)
docker ps -a
Stop a running container gracefully (SIGTERM, then SIGKILL after timeout)
docker stop my-nginx
Start a stopped container
docker start my-nginx
Remove a stopped container
docker rm my-nginx
Force-remove a running container (sends SIGKILL immediately)
docker rm -f my-nginx
View real-time logs
docker logs -f my-nginx
Execute a command inside a running container
docker exec -it my-nginx /bin/sh
“`
Инспекция ресурсов и системы
“`bash
Display real-time resource usage statistics
docker stats
Inspect detailed container metadata (JSON)
docker inspect my-nginx
Display disk usage by Docker objects
docker system df
Remove all stopped containers, unused networks, dangling images, and build cache
docker system prune
“`
`docker system prune` — одна из наиболее важных команд обслуживания для долго работающих серверов. Без периодической очистки кэш сборки Docker и остановленные контейнеры могут занять десятки гигабайт на активном хосте разработки или CI.
Шаг 6: Docker Compose — оркестрация многоконтейнерных приложений
Docker Compose V2 (пакет `docker-compose-plugin`, установленный ранее) вызывается как `docker compose` (с пробелом), а не устаревший `docker-compose` (с дефисом). Оба синтаксиса работают при наличии установленного плагина, но V2 является текущим стандартом.
6.1 Понимание структуры файла Compose
Создайте каталог проекта и файл `compose.yml` (предпочтительное имя файла в Compose V2; `docker-compose.yml` поддерживается для обратной совместимости):
“`bash
mkdir ~/my-web-app && cd ~/my-web-app
nano compose.yml
“`
Реалистичный для продакшена пример с Nginx и серверным сервисом:
“`yaml
services:
web:
image: nginx:1.27-alpine
ports:
- "8080:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./html:/usr/share/nginx/html:ro
depends_on:
- app
restart: unless-stopped
app:
image: node:20-alpine
working_dir: /usr/src/app
volumes:
- ./app:/usr/src/app
command: node server.js
environment:
- NODE_ENV=production
restart: unless-stopped
“`
Пояснение ключевых директив Compose:
- `restart: unless-stopped` — Контейнер автоматически перезапускается после сбоя или перезагрузки системы, если только он не был явно остановлен оператором. Это правильная политика для долго работающих сервисов; `always` будет перезапускать даже намеренно остановленные контейнеры.
- `depends_on` — Управляет порядком запуска, но не ожидает готовности сервиса (например, базы данных, принимающей подключения). Для ожидания готовности используйте `healthcheck` в сочетании с `condition: service_healthy`.
- `volumes` с `:ro` — Монтирование файлов конфигурации в режиме только для чтения предотвращает изменение скомпрометированным процессом контейнера собственной конфигурации.
6.2 Команды рабочего процесса Compose
“`bash
Start all services in detached mode
docker compose up -d
View logs for all services
docker compose logs -f
View logs for a specific service
docker compose logs -f web
List running Compose services
docker compose ps
Scale a specific service to multiple replicas
docker compose up -d –scale app=3
Stop services without removing containers
docker compose stop
Stop and remove containers, networks, and volumes
docker compose down –volumes
Rebuild images before starting (useful after code changes)
docker compose up -d –build
“`
6.3 Проверка работающего сервиса
“`bash
curl -I http://localhost:8080
“`
Ответ `200 OK` подтверждает корректную работу Nginx. Для сервисов, работающих на удалённом экземпляре VPS Хостинга, замените `localhost` на публичный IP-адрес вашего сервера и убедитесь, что соответствующий порт открыт в брандмауэре (`ufw allow 8080/tcp`).
Шаг 7: Основы сетевого взаимодействия Docker
Понимание сетевой модели Docker необходимо для создания многоконтейнерных приложений, которые взаимодействуют безопасно.
Стандартные сетевые драйверы:
| Драйвер | Сценарий использования |
|---|
| — | — |
|---|
| `bridge` | По умолчанию для автономных контейнеров; изолированное сетевое пространство имён на хосте |
|---|
| `host` | Контейнер использует сетевой стек хоста; максимальная производительность, нулевая изоляция |
|---|
| `none` | Нет доступа к сети; полезно для пакетной обработки или рабочих нагрузок с повышенными требованиями к безопасности |
|---|
| `overlay` | Многохостовое сетевое взаимодействие для кластеров Docker Swarm |
|---|
| `macvlan` | Назначает MAC-адрес контейнеру; отображается как физическое устройство в сети |
|---|
Создание и использование пользовательской мостовой сети:
“`bash
Create an isolated network
docker network create my-app-network
Run containers attached to the custom network
docker run -d –name db –network my-app-network postgres:16-alpine
docker run -d –name api –network my-app-network my-api-image
Containers on the same custom bridge network can resolve each other by name
Inside 'api', you can connect to 'db' using the hostname 'db'
“`
Пользовательские мостовые сети обеспечивают автоматическое разрешение DNS между контейнерами по имени контейнера. Стандартная сеть `bridge` этого не делает — это критически важное отличие, которое приводит к ошибкам подключения, когда разработчики предполагают, что контейнеры в стандартной сети могут обращаться друг к другу по имени.
Шаг 8: Постоянное хранение данных с томами Docker
Контейнеры по своей природе являются эфемерными. Любые данные, записанные в файловую систему контейнера, теряются при его удалении. Для постоянного хранения используйте тома или монтирование привязкой.
“`bash
Create a named volume
docker volume create pgdata
Use the volume with a container
docker run -d
–name postgres-db
-e POSTGRES_PASSWORD=securepassword
-v pgdata:/var/lib/postgresql/data
postgres:16-alpine
List volumes
docker volume ls
Inspect a volume (shows mount point on host)
docker volume inspect pgdata
Remove unused volumes
docker volume prune
“`
Тома vs. монтирование привязкой:
| Характеристика | Именованный том | Монтирование привязкой |
|---|
| — | — | — |
|---|
| Управляется Docker | Да | Нет |
|---|
| Требуется путь на хосте | Нет | Да |
|---|
| Переносимость между хостами | Да (с драйверами томов) | Нет |
|---|
| Лучше всего подходит для | Данных баз данных, состояния приложения | Кода разработки, файлов конфигурации |
|---|
| Механизм резервного копирования | `docker run –volumes-from` | Стандартные инструменты файловой системы |
|---|
Шаг 9: Обновление Docker
Официальный репозиторий Docker обрабатывает обновления через стандартный механизм `apt`:
“`bash
sudo apt update
sudo apt upgrade -y
“`
Для обновления только пакетов, связанных с Docker, без обновления всей системы:
“`bash
sudo apt install –only-upgrade docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
“`
Перед обновлением до новых мажорных версий ознакомьтесь с примечаниями к релизу Docker, особенно в части изменений драйвера хранилища, обработки версий cgroup или устаревших версий API, которые могут повлиять на существующие файлы `compose.yml`.
Docker vs. альтернативные подходы к контейнеризации
| Характеристика | Docker Engine | Podman | LXC/LXD | containerd (автономный) |
|---|
| — | — | — | — | — |
|---|
| Архитектура демона | Централизованный демон | Без демона | На основе демона | На основе демона |
|---|
| Поддержка rootless | Да (v20+) | Нативная | Ограниченная | Да |
|---|
| Поддержка Docker Compose | Нативная | Через `podman-compose` | Нет | Нет |
|---|
| Соответствие OCI | Да | Да | Нет (формат LXC) | Да |
|---|
| Интеграция с Kubernetes | Через шим CRI-dockerd | Нативный CRI | Нет | Нативный CRI |
|---|
| Поддержка Windows/macOS | Docker Desktop | Ограниченная | Нет | Нет |
|---|
| Лучше всего подходит для | Общей разработки и продакшена | Ориентированных на безопасность, rootless | Системных контейнеров, виртуальных машин | Узлов Kubernetes |
|---|
Для команд, запускающих контейнеризованные рабочие нагрузки в масштабе на bare metal, среда Выделенных серверов даёт полный контроль над параметрами ядра, планированием дискового ввода-вывода и конфигурацией сети — всё это напрямую влияет на плотность контейнеров и производительность.
Контрольный список усиления безопасности для продакшена
Перед запуском Docker в производственной среде устраните следующие проблемы:
Конфигурация демона (`/etc/docker/daemon.json`):
“`json
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
},
"storage-driver": "overlay2",
"userns-remap": "default",
"live-restore": true,
"no-new-privileges": true
}
“`
- `log-opts` с `max-size` и `max-file`: Без ротации логов JSON-файлы логов Docker заполнят ваш диск. Это одна из наиболее распространённых причин неожиданных сбоев серверов на контейнеризованных хостах.
- `userns-remap: "default"`: Включает переназначение пространства имён пользователей, так что root контейнера (UID 0) сопоставляется с непривилегированным UID на хосте.
- `live-restore: true`: Позволяет контейнерам продолжать работу при сбое или перезапуске демона Docker во время обновления — критически важно для обслуживания без простоев.
- `no-new-privileges: true`: Предотвращает получение процессами контейнера дополнительных привилегий через бинарные файлы `setuid` или `setgid`.
Соображения по сети и брандмауэру:
Docker напрямую управляет `iptables` и по умолчанию обходит правила `ufw`. Контейнер с опубликованным портом (`-p 8080:80`) будет доступен из интернета, даже если установлена политика `ufw deny 8080`. Чтобы применить правила `ufw` поверх манипуляций Docker с `iptables`, добавьте `"iptables": false` в `daemon.json` и управляйте маршрутизацией вручную, или используйте `–network host` Docker с явными правилами `ufw`.
Для проектов, требующих терминирования HTTPS, сочетайте ваше контейнеризованное приложение с правильно настроенным обратным прокси (Nginx или Traefik) и действительным сертификатом. SSL-сертификаты являются обязательным условием для любого производственного веб-сервиса, работающего за контейнеризованным стеком.
Если ваша рабочая нагрузка включает инференс машинного обучения, обслуживание моделей или GPU-ускоренную обработку данных внутри контейнеров, NVIDIA Container Toolkit интегрируется напрямую с Docker Engine. GPU Хостинг обеспечивает необходимое аппаратное обеспечение для этих рабочих нагрузок.
Для команд, управляющих несколькими проектами с веб-интерфейсом управления контейнерами, VPS с cPanel предлагает среду управляемой панели управления, которая может дополнять развёртывания на основе Docker для более простых стеков приложений.
Ключевые технические выводы и матрица принятия решений
Когда использовать Docker на VPS, а когда на выделенном сервере:
- Используйте VPS для сред разработки, тестирования и производственных рабочих нагрузок с низким и средним трафиком, где плотность контейнеров составляет 10–50 контейнеров.
- Используйте выделенный сервер, когда плотность контейнеров превышает 50 экземпляров, когда требуется предсказуемая производительность ввода-вывода (без эффекта шумного соседа) или когда для вашей рабочей нагрузки необходима настройка параметров ядра (`sysctl`).
Операционный контрольный список перед запуском в продакшен:
- Настройте ротацию логов в `daemon.json` (`max-size`, `max-file`)
- Включите `live-restore` для выживания при перезапуске демона без простоя контейнеров
- Используйте именованные тома, а не монтирование привязкой, для данных сервисов с состоянием
- Закрепляйте версии образов во всех файлах `compose.yml` — никогда не используйте `latest` в продакшене
- Включите `userns-remap` или запускайте rootless Docker на многопользовательских хостах
- Проверьте правила `iptables` после установки Docker, чтобы убедиться, что политика брандмауэра не обходится
- Установите `restart: unless-stopped` для всех долго работающих сервисов
- Запускайте `docker system prune` по расписанию cron для предотвращения исчерпания диска
- Используйте пользовательские мостовые сети для всего межконтейнерного взаимодействия — никогда не полагайтесь на стандартный мост для обнаружения сервисов
Часто задаваемые вопросы
Использует ли Docker на Ubuntu `systemd` или `cgroupfs` в качестве драйвера cgroup по умолчанию?
Начиная с Docker Engine 20.10, драйвером cgroup по умолчанию в системах на основе `systemd` (включая все современные релизы Ubuntu LTS) является `systemd`. Это соответствует требованиям Kubernetes и позволяет избежать нестабильности, вызванной одновременной работой двух менеджеров cgroup. Проверить можно с помощью `docker info | grep -i cgroup`.
В чём разница между `docker compose down` и `docker compose stop`?
`docker compose stop` останавливает работающие контейнеры, но сохраняет их и связанные с ними сети. `docker compose down` останавливает контейнеры, а затем удаляет их вместе с сетями, созданными Compose. Добавление `–volumes` к `down` также удаляет именованные тома, определённые в файле Compose — используйте этот флаг с осторожностью в продакшене, так как он безвозвратно удаляет постоянные данные.
Почему Docker обходит правила брандмауэра `ufw` на Ubuntu?
Docker вставляет собственные правила `iptables` в цепочки `DOCKER` и `DOCKER-USER`, которые обрабатываются раньше правил цепочки `INPUT` `ufw`. Это означает, что порт, опубликованный с помощью `-p`, доступен из интернета независимо от политики `ufw`. Правильным решением является добавление правил непосредственно в цепочку `DOCKER-USER` или привязка опубликованных портов к конкретному интерфейсу (например, `-p 127.0.0.1:8080:80`), когда внешний доступ не требуется.
Как ограничить потребление CPU и памяти контейнером Docker?
Используйте флаги ограничения ресурсов во время выполнения: `docker run –memory="512m" –cpus="1.5" my-image`. В Compose задайте их в ключе `deploy.resources` (Compose V2) или в ключах верхнего уровня `mem_limit` и `cpus`. Без ограничений один вышедший из-под контроля контейнер может исчерпать ресурсы хоста и вывести из строя все остальные контейнеры на том же хосте.
Можно ли запустить Docker внутри контейнера Docker (Docker-in-Docker)?
Да, но это настоятельно не рекомендуется для производственного использования. Распространённый шаблон для CI-конвейеров — монтирование сокета Docker хоста (`-v /var/run/docker.sock:/var/run/docker.sock`) в CI-контейнер, что даёт контейнеру полный контроль над демоном Docker хоста — это существенный риск безопасности. Более безопасной альтернативой является использование флага `–allow security.insecure` BuildKit или специализированных инструментов, таких как Kaniko или Buildah, которые собирают OCI-образы без необходимости в демоне Docker.
