Docker: от установки до воспроизводимого запуска
Docker упаковывает приложение с его пользовательским окружением в образ. Из одного образа можно создать несколько контейнеров: для разработки, проверки или демонстрации. В этой инструкции пройдём весь путь — установим Docker, соберём маленький сайт, запустим его обычной командой и через Compose, разберём данные, диагностику и очистку.
Все примеры — учебное локальное окружение. Команды в блоках можно копировать; подписи Bash и PowerShell показывают, в какой оболочке их выполнять. Команды очистки приведены для самостоятельного запуска и здесь не выполняются. Для первого прохода достаточно Docker, редактора файлов и браузера.
Образ, контейнер, Dockerfile и Compose
Образ (image) — шаблон файловой системы и настроек запуска. Контейнер (container) — экземпляр образа со своим процессом и записываемым слоем. Остановка сохраняет контейнер; удаление уничтожает его записываемый слой. Сам образ от этого не исчезает.
Dockerfile описывает сборку образа. Registry, например Docker Hub, хранит образы для скачивания и публикации. Volume хранит данные отдельно от контейнера. Compose описывает сервисы, сети, порты и тома проекта в YAML. Современная команда — docker compose, с пробелом.
Контейнеры используют ядро хоста. На Linux Docker Engine работает непосредственно в системе; на Windows Linux-контейнеры обычно работают через Linux-окружение WSL 2 в Docker Desktop. Образ Linux нельзя запустить как Windows-контейнер простым изменением команды. Архитектура процессора, например amd64 или arm64, тоже имеет значение.

Установка на Linux: Ubuntu, Debian и Fedora
Для Linux-сервера и локальной разработки подойдёт Docker Engine с плагинами Buildx и Compose. Ниже установка из официального репозитория. Сначала проверьте дистрибутив командой cat /etc/os-release. Если Docker уже установлен, посмотрите docker version; не удаляйте работающую установку вслепую. Конфликтующие пакеты из репозитория дистрибутива нужно убрать по инструкции Docker для вашей ОС.
Ubuntu и Debian: подключаем репозиторий
Следующий блок подходит для Ubuntu и Debian: он выбирает адрес репозитория по ID из os-release. Для производных дистрибутивов, например Linux Mint, используйте инструкцию базовой ОС и её кодовое имя. Каждую многострочную команду копируйте целиком.
. /etc/os-release
sudo apt update
sudo apt install -y ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL "https://download.docker.com/linux/$ID/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 > /dev/null <<EOF
Types: deb
URIs: https://download.docker.com/linux/$ID
Suites: ${UBUNTU_CODENAME:-$VERSION_CODENAME}
Components: stable
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/docker.asc
EOF
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo systemctl enable --now docker
sudo docker run --rm hello-world
sudo docker compose version
Fedora: установка через dnf
sudo dnf install -y dnf-plugins-core
sudo dnf config-manager addrepo --from-repofile https://download.docker.com/linux/fedora/docker-ce.repo
sudo dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo systemctl enable --now docker
sudo docker run --rm hello-world
Если получено сообщение Hello from Docker!, клиент скачал тестовый образ, сервер создал контейнер и выполнил процесс. Флаг --rm удаляет этот контейнер после завершения; скачанный образ остаётся.
Как выполнять команды без sudo
sudo usermod -aG docker "$USER"
# Выйдите из пользовательской сессии и войдите заново.
# После повторного входа:
docker version
docker compose version
Группа docker предоставляет привилегии уровня root. Добавляйте только доверенных пользователей; для другой модели доступа изучите rootless mode. До повторного входа выполняйте команды этой статьи с sudo docker. Не исправляйте доступ к сокету через chmod 666.
Установка на Windows: Docker Desktop и WSL 2
Этот маршрут предназначен для Linux-контейнеров на поддерживаемой Windows 10/11. Проверьте актуальные требования Docker Desktop по ссылке в источниках, включите аппаратную виртуализацию в BIOS/UEFI. Для Windows Server используйте отдельную серверную инструкцию: Docker Desktop для него не предназначен.
Откройте PowerShell от администратора. Установите WSL, обновите его и проверьте версию. Если установщик запросит перезагрузку — перезагрузите компьютер; при первом запуске Ubuntu создайте пользователя Linux.
wsl --install -d Ubuntu
wsl --update
wsl --version
wsl --list --verbose
В выводе списка дистрибутивов нужна версия 2. Если у уже установленного Ubuntu версия 1, выполните wsl --set-version Ubuntu 2. Затем скачайте Docker Desktop с официального сайта, установите с backend WSL 2 и запустите приложение. Дождитесь готовности Engine.
В Docker Desktop откройте Settings → General → Use the WSL 2 based engine, затем Resources → WSL Integration и включите свой дистрибутив. Если пункта интеграции нет, проверьте, что выбран режим Linux containers. Отдельный Engine внутри того же WSL-дистрибутива для этого маршрута устанавливать не нужно.
docker version
docker compose version
docker run --rm hello-world
Клиент должен показать разделы Client и Server. Для разработки из WSL храните исходники в Linux-файловой системе, например ~/projects/docker-demo, и выполняйте команды там: bind mount из /mnt/c может работать медленнее. Условия коммерческого использования Docker Desktop проверяйте на официальной странице подписки.
Первый контейнер из готового образа
docker pull nginx:stable-alpine
docker run -d --name docker-demo -p 127.0.0.1:8090:80 nginx:stable-alpine
docker ps
docker logs --tail 30 docker-demo
Откройте http://localhost:8090/: появится стартовая страница nginx. -d запускает контейнер в фоне; --name задаёт имя; -p 127.0.0.1:8090:80 связывает порт 8090 вашего компьютера с портом 80 контейнера. Привязка к 127.0.0.1 оставляет пример доступным только локально. EXPOSE в Dockerfile сам по себе порт не публикует.
docker stop docker-demo
docker start docker-demo
# Удаляем только учебный контейнер перед следующим шагом:
docker stop docker-demo
docker rm docker-demo
docker run каждый раз создаёт новый контейнер; docker start запускает существующий. Повторный run с занятым именем выдаст конфликт. Удаление этого учебного контейнера не удалит nginx-образ.
Собираем собственный образ: три файла
Создайте каталог docker-demo и в нём три файла из обозревателя ниже. Имена важны: Dockerfile без расширения и с заглавной D; .dockerignore начинается с точки. В index.html находится содержимое сайта, в Dockerfile — рецепт сборки, в .dockerignore — исключения из контекста.
Dockerfile
FROM nginx:stable-alpine
COPY index.html /usr/share/nginx/html/index.html
EXPOSE 80
index.html
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Мой Docker-сайт</title>
</head>
<body>
<h1>Работает в контейнере.</h1>
<p>Один образ. Повторяемый запуск.</p>
</body>
</html>
.dockerignore
.git
.env
.env.*
node_modules
*.log
docker build -t docker-demo:1.0 .
docker image ls
docker run -d --name docker-demo -p 127.0.0.1:8090:80 docker-demo:1.0
Точка в конце build — контекст сборки: файлы, доступные инструкции COPY. Флаг -t назначает имя и тег образа. Откройте localhost:8090: теперь увидите собственный сайт. Изменение index.html на компьютере не меняет уже собранный образ. Пересоберите его, удалите старый контейнер и создайте новый из обновлённого образа.
docker build -t docker-demo:1.1 .
docker stop docker-demo
docker rm docker-demo
docker run -d --name docker-demo -p 127.0.0.1:8090:80 docker-demo:1.1
Docker кеширует слои сборки. Для проекта с зависимостями сначала копируют lock-файлы и устанавливают пакеты, затем копируют меняющийся код. docker build --pull проверяет обновление базового образа, а --no-cache отключает кеш инструкций; это разные задачи. Секреты нельзя записывать в Dockerfile или копировать в образ: .dockerignore — дополнительная защита, а для сборочных секретов нужен механизм BuildKit secrets.

Compose: запуск проекта одной командой
Добавьте рядом compose.yml. Здесь один сервис web, собираемый из текущего каталога. Имя проекта задаём явно, чтобы оно не зависело от имени папки. Устаревшее верхнеуровневое поле version не требуется.
compose.yml
name: docker-demo
services:
web:
build: .
image: docker-demo:local
ports:
- "127.0.0.1:8090:80"
restart: unless-stopped
Перед Compose освободите порт, остановив контейнер из предыдущего шага. Дальше выполняйте команды в каталоге с compose.yml.
docker stop docker-demo
docker rm docker-demo
docker compose config --quiet
docker compose up -d --build
docker compose ps
docker compose logs --tail 50 web
up -d --build собирает образ и приводит контейнеры к описанному состоянию. После изменения кода повторите эту команду. restart только перезапускает существующий контейнер и не применяет новый образ или изменённые переменные окружения. Для другого файла используйте docker compose -f compose.dev.yml up -d.
docker compose logs -f --tail 50 web
# Ctrl+C завершает просмотр логов; контейнер продолжает работать.
docker compose exec web sh
# Внутри контейнера: exit
docker compose stop
docker compose start
# Удалить контейнеры и сеть проекта, сохранив именованные тома:
docker compose down
Данные, тома, настройки и сеть
Записываемый слой контейнера исчезает при его удалении. Базу данных, загруженные файлы и другие постоянные данные храните в именованных томах. Bind mount связывает каталог хоста с путём контейнера — это удобно для редактирования исходников. Монтирование скрывает прежнее содержимое целевого пути в образе.
compose.storage.yml
name: docker-storage-demo
services:
storage:
image: alpine:3.22
command: ["sh", "-c", "echo started >> /data/starts.log; sleep infinity"]
volumes:
- demo_data:/data
volumes:
demo_data:
compose.dev.yml
name: docker-demo
services:
web:
image: nginx:stable-alpine
ports:
- "127.0.0.1:8090:80"
volumes:
- ./index.html:/usr/share/nginx/html/index.html:ro
Первый файл — отдельная демонстрация постоянного тома. Второй — самостоятельный вариант сайта для разработки без сборки: изменения index.html видны после обновления страницы. Он использует тот же порт, поэтому сначала выполните down предыдущего web-проекта. На Fedora bind mount может потребовать SELinux-метку :ro,Z для приватного каталога.
docker compose -f compose.storage.yml up -d
docker compose -f compose.storage.yml exec storage cat /data/starts.log
docker compose -f compose.storage.yml down
docker compose -f compose.storage.yml up -d
docker compose -f compose.storage.yml exec storage cat /data/starts.log
После повторного создания контейнера в файле останутся прежние записи. Том — не резервная копия: перед миграцией БД нужен согласованный дамп средствами самой СУБД и проверка восстановления. Копирование файлов работающей БД может дать неконсистентный результат.
Compose создаёт сеть проекта. Сервисы в ней обращаются друг к другу по имени сервиса и внутреннему порту: например, приложение использует db:5432 для PostgreSQL. Внутри контейнера localhost — сам контейнер. В Docker Desktop доступ к сервису на хосте обычно идёт через host.docker.internal; на Linux Engine такое имя нужно настраивать отдельно.
Файл .env рядом с Compose используется для подстановки значений ${VARIABLE}; переменные не попадают в контейнер автоматически. Для передачи нужны environment или env_file. Не коммитьте реальные пароли; храните .env.example с именами параметров. Значения могут быть видны в inspect и выводе compose config, поэтому не публикуйте их без проверки.

Базовые команды: короткая шпаргалка
docker version # Клиент и сервер
docker info # Состояние Engine
docker context ls # Доступные окружения
docker ps # Работающие контейнеры
docker ps -a # Все контейнеры
docker image ls # Локальные образы
docker volume ls # Тома
docker network ls # Сети
docker system df # Занятое место
# Замените CONTAINER именем или ID из docker ps -a.
docker logs --tail 100 CONTAINER
docker logs -f CONTAINER
docker inspect CONTAINER
docker stats --no-stream
docker exec -it CONTAINER sh
docker cp CONTAINER:/etc/nginx/nginx.conf ./nginx.conf
docker stop CONTAINER
docker start CONTAINER
docker restart CONTAINER
docker rm CONTAINER
Не каждый образ содержит bash, поэтому для Alpine-примеров используется sh. Exec работает только с запущенным контейнером. Для остановленного контейнера сначала смотрите logs и inspect. Команда docker cp полезна для диагностики, но не заменяет изменение Dockerfile: ручные исправления внутри контейнера не делают образ воспроизводимым.
docker pull nginx:stable-alpine
docker image inspect nginx:stable-alpine
# Замените YOUR_USER своим именем в Docker Hub:
docker tag docker-demo:1.1 YOUR_USER/docker-demo:1.1
docker login
docker push YOUR_USER/docker-demo:1.1
Публикуйте только образ, который действительно хотите передать в registry: предварительно проверьте, что внутри нет ключей, .env и приватных файлов. Для скачивания вашего образа на другой машине используется docker pull YOUR_USER/docker-demo:1.1. Registry и права доступа определяют, кто сможет его получить.
Если не запускается: сначала причина, потом перезапуск
Cannot connect to the Docker daemon. На Windows запустите Docker Desktop и дождитесь готовности. На Linux проверьте sudo systemctl status docker. Командой docker context ls убедитесь, что выбран нужный Engine. Permission denied при доступе к сокету требует настройки прав пользователя, а не пересборки приложения.
Port is already allocated. Порт хоста занят. Найдите старый контейнер через docker ps или измените левую часть привязки, например на 127.0.0.1:8091:80. Контейнер сразу завершился. Проверьте код выхода и логи: основной процесс должен работать в foreground, а не уходить в фон внутри контейнера.
COPY failed / файл не найден. Проверьте текущий каталог, контекст сборки и .dockerignore. No matching manifest. Проверьте ОС и архитектуру образа; наличие тега не гарантирует поддержку вашего процессора. Изменения не видны. Пересоберите образ и пересоздайте контейнер либо проверьте bind mount. База ещё не готова. Порядок запуска не равен готовности: нужен healthcheck и зависимость с condition: service_healthy, а приложению полезны повторные подключения.
Как очистить Docker: от мусора до полного сброса
Сначала выполните docker context show, docker ps -a, docker volume ls и docker system df. Очистка действует на выбранный Docker Engine: это может быть удалённый сервер. Команды ниже — справочные; запускайте только выбранный уровень очистки, а не все блоки подряд.
1. Убрать неиспользуемые ресурсы
docker container prune
# Удаляет остановленные контейнеры и их записываемые слои.
docker image prune
# Удаляет dangling-образы.
docker builder prune
# Удаляет неиспользуемый кеш текущего builder.
docker network prune
# Удаляет неиспользуемые пользовательские сети.
docker system prune
# Вместе: остановленные контейнеры, unused-сети,
# dangling-образы и неиспользуемый кеш сборки.
Обычный system prune не удаляет тома, но удаляет остановленные контейнеры: несохранённые в том данные будут потеряны. Флаг -a добавляет все образы, не связанные ни с одним контейнером. docker system prune -a --volumes дополнительно очищает неиспользуемые анонимные тома; именованные тома этой командой не удаляются.
2. Сбросить один Compose-проект вместе с данными
# Выполнять только после проверки каталога и резервных копий.
docker compose down --volumes --remove-orphans --rmi all
Эта команда останавливает проект, удаляет его контейнеры и сети, тома из секции volumes и присоединённые анонимные тома, а также пытается удалить используемые сервисами образы. External-тома и external-сети не удаляются. Bind mount не очищает файлы на хосте. Для storage-примера укажите -f compose.storage.yml. Если нужны данные, используйте down без –volumes.
3. Удалить все контейнеры и неиспользуемые ресурсы выбранного Engine
Разрушительный сброс всех проектов на выбранном Engine. Остановятся и удалятся все контейнеры, затем образы, кеш текущего builder, пользовательские сети и все неиспользуемые локальные тома, включая именованные. Сделайте резервные копии нужных данных. Bash и PowerShell имеют разный синтаксис перебора — выберите свой блок.
docker ps -aq | while IFS= read -r id; do
docker rm -f "$id" || break
done
docker system prune -a
docker volume prune -a
docker system df
docker ps -aq | ForEach-Object {
docker rm -f $_
if ($LASTEXITCODE -ne 0) { throw "Не удалось удалить контейнер" }
}
docker system prune -a
docker volume prune -a
docker system df
Удаление контейнеров выполняется без дополнительного вопроса из-за rm -f; prune затем запрашивает подтверждение. Эти команды не удаляют Docker, исходники bind mount, содержимое registry и кеши других Buildx builders. Их список смотрят через docker buildx ls, а кеш выбранного builder — через docker buildx prune --builder NAME. Docker Desktop может не сразу вернуть освобождённое место виртуального диска Windows.
4. Удалить сам Docker
На Ubuntu/Debian пакеты Engine удаляются следующей командой. Она не удаляет автоматически данные Docker и containerd. Не стирайте /var/lib/docker вручную, пока не проверили резервные копии и реальное расположение data-root. На Windows Docker Desktop удаляется через «Установленные приложения»; перед удалением экспортируйте нужные данные. Troubleshoot → Clean / Purge data в Desktop предназначен для удаления локальных данных, а Reset to factory defaults также сбрасывает настройки.
sudo apt purge docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin docker-ce-rootless-extras
Что делает запуск действительно воспроизводимым
Сам Dockerfile — только начало. Храните рядом код, compose.yml, .dockerignore, lock-файлы зависимостей, .env.example и README с командами запуска и проверки. Фиксируйте версию приложения и базовых образов. В учебном примере nginx:stable-alpine удобен для первого запуска, но это плавающий тег; для точного повторения фиксируйте digest вида nginx@sha256:…. Реальный digest можно увидеть через docker image inspect, поле RepoDigests. Не вставляйте многоточие в рабочий Dockerfile.
Контролируемо обновляйте digest и зависимости, затем повторяйте проверки. Секреты передавайте отдельно. Укажите поддерживаемую архитектуру, порты и способ резервного копирования. Подготовьте сценарий приёмки: чистый checkout, заполненный .env, compose config –quiet, up -d –build, проверка страницы и логов, down и повторный up с сохранением данных. Для БД дополнительно проверьте восстановление дампа.
Перед передачей проекта другой человек должен запустить его по README без файлов с вашего компьютера и устных подсказок. Именно это превращает «у меня работает» в проверяемый результат. Локальная Compose-конфигурация при этом не заменяет production-настройки: TLS, доступы, ограничения ресурсов, обновления и мониторинг требуют отдельного решения.
Документация и следующие шаги
Первоисточники для проверки команд и требований:

