Установка Docker и запуск первого контейнера

Рейтинг: 77.2% · 13 голосов
Практический курс по Docker: образы, контейнеры, тома, сети, Compose и продакшен. Уроки по главам с обсуждением.
Ответить
Аватара пользователя
Marina_DevOps
Сообщения: 54
Зарегистрирован: 11 май 2026, 05:31

Установка Docker и запуск первого контейнера

Сообщение Marina_DevOps »

Оглавление курса (46)
  1. Что такое Docker и какие задачи он решает
  2. Установка Docker и запуск первого контейнера (вы здесь)
  3. Образы: слои, теги и реестр Docker Hub
  4. Пишем свой Dockerfile
  5. Тома и хранение данных: volumes и bind mounts
  6. Сети в Docker: связываем контейнеры между собой
  7. Переменные окружения и конфигурация контейнеров
  8. Docker Compose: поднимаем многоконтейнерное приложение
  9. Оптимизация образов: multi-stage сборка, размер и кэш слоёв
  10. Логи, отладка и мониторинг контейнеров
  11. Базовая безопасность контейнеров
  12. Подготовка к продакшену: что важно учесть
  13. Dockerfile глубже: ENTRYPOINT и CMD, HEALTHCHECK, .dockerignore, запуск не от root
  14. Реестры образов: приватные registry, push и pull, теги и digest, imagePullSecrets
  15. BuildKit и buildx: multi-arch сборки, секреты сборки, экспорт кэша
  16. Docker в CI/CD: автосборка, сканирование образов (Trivy, Docker Scout), публикация
  17. Итоговый проект и куда расти: от Dockerfile до прода, обзор оркестрации (Kubernetes, Podman, OCI)
  18. Архитектура Docker: dockerd, containerd, runc и OCI
  19. Как работает изоляция: namespaces и cgroups
  20. Образы изнутри: слои, OverlayFS и storage driver
  21. Жизненный цикл контейнера и политики перезапуска
  22. Отладка контейнеров: exec, attach, nsenter, debug
  23. Сети Docker глубже: bridge, overlay, macvlan и iptables
  24. Docker Compose глубже: profiles, healthcheck-зависимости, override
  25. Данные и тома глубже: драйверы, бэкап, права
  26. Секреты и конфигурация: как не светить пароли
  27. Ограничение ресурсов: CPU, память, OOM и cgroups
  28. Здоровье и автозапуск: HEALTHCHECK, init и сигналы
  29. Логирование контейнеров: драйверы, ротация, сбор
  30. Мониторинг контейнеров: stats, cAdvisor, Prometheus
  31. Безопасность глубже: rootless, user namespaces, seccomp, capabilities
  32. Supply chain: сканирование, SBOM и подпись образов
  33. Глубокая оптимизация образов: distroless, scratch, кэш
  34. Multi-arch и сборка под ARM: buildx и эмуляция
  35. Реестры в продакшене: Harbor и облачные registry
  36. Docker без Docker: Podman, containerd, nerdctl, Buildah
  37. От Compose к оркестрации: когда контейнеров становится много
  38. Docker Swarm: встроенная оркестрация
  39. Сборка образов в CI без демона: kaniko, BuildKit, Buildah
  40. Траблшутинг Docker: типичные ошибки и как чинить
  41. Производительность и эксплуатация Docker-хоста
  42. Docker Desktop, WSL2 и альтернативы на Windows и Mac
  43. Контейнеризация приложений: бэкенд, фронтенд, БД
  44. Docker и Kubernetes: containerd, миграция, kompose
  45. Лучшие практики и антипаттерны Docker
  46. Сквозной проект: production-ready стек и путь дальше
Зачем вообще ставить Docker правильно

В прошлой главе мы разобрали, что такое контейнер и чем он отличается от виртуалки. Теперь руки на клавиатуру. И тут начинается первая боль: люди ставят Docker как попало - из старого пакета дистрибутива, через snap, через какой-то скрипт с форума - а потом удивляются, почему compose v2 не работает, BuildKit ругается, а образ не тянется. Грязная установка - это часы отладки на ровном месте.

Поэтому docker установка - это не "копипастни команду", а понимание, что именно ты ставишь и куда оно ложится. Docker Engine - это не один бинарник. Это демон dockerd, клиент docker (CLI), низкоуровневый рантайм containerd и runc под ним, плюс плагины buildx и compose. Когда ты пишешь docker run, CLI шлёт HTTP-запрос демону через Unix-сокет /var/run/docker.sock, демон через containerd создаёт контейнер, а runc уже дёргает namespaces и cgroups ядра. Запомни эту цепочку - она объяснит половину будущих ошибок.

Разберём docker install на трёх фронтах: Linux (основной, продакшен), Windows и Mac (Docker Desktop, разработка), и отдельно RU-реалии с зеркалами и RED OS. Потом запустим первый контейнер по шагам и разберём жизненный цикл руками.

Изображение

Docker на Ubuntu: правильный путь через apt

Самая частая связка - docker ubuntu. И первое, что нужно сделать, - снести то, что могло прилететь из коробки. В репах Ubuntu есть пакеты docker.io, docker-doc, podman-docker и старый containerd - они конфликтуют с официальным Docker CE и обычно отстают на версию-другую.

Код: Выделить всё

for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do
  sudo apt-get remove -y $pkg
done
Дальше подключаем официальный репозиторий Docker. Логика такая: добавить GPG-ключ (чтобы apt доверял пакетам) и прописать источник под твою архитектуру и кодовое имя релиза.

Код: Выделить всё

sudo apt-get update
sudo apt-get install -y 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

echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] \
  https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

sudo apt-get update
Обрати внимание на $(dpkg --print-architecture) - оно подставит amd64 или arm64 (актуально для серверов на ARM и для Apple Silicon в Linux-VM). И на $VERSION_CODENAME - это noble для 24.04, на свежих релизах будет своё. Если кодового имени ещё нет в репе Docker (вышел новый Ubuntu, а Docker не успел) - подставь предыдущее LTS-имя вручную, пакеты совместимы.

Теперь сама установка. Ставим пять пакетов - это и есть полный Docker Engine:

Код: Выделить всё

sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
  • docker-ce - демон dockerd, мозг всей системы.
  • docker-ce-cli - клиент docker, тот самый, в который ты печатаешь команды. Его можно ставить и без демона, чтобы рулить удалённым хостом.
  • containerd.io - высокоуровневый рантайм. Это он реально держит контейнеры. Кстати, его же использует Kubernetes напрямую - и именно поэтому k8s выпилил dockershim (об этом ниже).
  • docker-buildx-plugin - современная сборка на BuildKit, мультиплатформенные образы.
  • docker-compose-plugin - тот самый compose v2, команда docker compose (через пробел, не дефис).
На дистрибутивах с dnf (Fedora, RHEL, RED OS) логика идентична, только вместо apt-репозитория подключаешь dnf config-manager на download.docker.com и ставишь те же пять пакетов через sudo dnf install. Версии на момент 2026 - Docker CE из ветки 29.x и containerd 2.2.x, это твой ориентир в docker version.

Официальный скрипт, post-install и rootless

Если лень руками - есть get.docker.com:

Код: Выделить всё

curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
Скрипт сам определит дистрибутив и сделает всё вышеописанное. Удобно для одноразового тестового стенда или CI. Но в продакшене я его не люблю: он непрозрачен, тянет последнюю версию без пиннинга, и в автоматизации лучше явно прописать репозиторий и версию пакета. Правило простое: ручной стенд - скрипт можно, инфраструктура как код - только репозиторий и зафиксированная версия.

После установки демон запущен, но работать с ним пока можно только через sudo. Причина в том самом сокете /var/run/docker.sock - он принадлежит группе docker, а тебя в ней нет. Post-install шаг:

Код: Выделить всё

sudo usermod -aG docker $USER
newgrp docker   # или просто перелогинься
docker run hello-world   # теперь без sudo
Важная оговорка по безопасности. Группа docker - это фактически root. Любой её член может смонтировать корень хоста в контейнер и получить полный доступ. Не добавляй туда кого попало. На многопользовательских серверах это реальная дыра, а не формальность.

Отсюда вытекает альтернатива - rootless Docker. Демон запускается от обычного пользователя, без root вообще, через user namespaces. Ставится отдельным пакетом:

Код: Выделить всё

sudo apt-get install -y docker-ce-rootless-extras
dockerd-rootless-setuptool.sh install
В rootless демон, контейнеры и данные живут в домашней папке (~/.local/share/docker), а сокет - в /run/user/UID/docker.sock. Это серьёзно снижает поверхность атаки: даже пробой из контейнера упрётся в права обычного юзера. Платишь за это ограничениями - сложнее проброс привилегированных портов ниже 1024, нюансы с сетью и хранилищем. Для CI-раннеров, дев-окружений и paranoid-продакшена - то, что нужно. Здесь, кстати, виден общий тренд 2026: Podman изначально rootless и демонless, и Docker в этом направлении его догоняет.

Docker Desktop на Windows и Mac: лицензия и WSL2

На сервере ты ставишь Engine. А вот docker windows и docker на Mac - это почти всегда Docker Desktop. Важно понимать: ядро Linux в Windows и macOS нет, поэтому Docker Desktop поднимает легковесную Linux-виртуалку, и контейнеры крутятся внутри неё. На Windows эта VM работает через WSL2 (Windows Subsystem for Linux 2 - полноценное Linux-ядро от Microsoft), на Mac - через свой гипервизор.

Установка docker desktop проста: качаешь инсталлятор с docker.com, на Windows он сам включит WSL2 и компоненты виртуализации (нужны включённые в BIOS VT-x/AMD-V и Hyper-V/WSL). После старта в трее появляется кит, а в терминале начинают работать docker и docker compose.

Про лицензию - это ловушка, на которой горят компании. Сам Docker Engine на Linux полностью бесплатен и open source (Apache 2.0). А вот Docker Desktop по состоянию на 2026 требует платной подписки (Pro/Team/Business) для коммерческого использования в организациях больше 250 сотрудников ИЛИ с годовой выручкой больше 10 млн долларов. Для личного использования, обучения, опенсорса и малого бизнеса - бесплатно. Юридический нюанс: платно именно приложение Desktop (GUI плюс та самая VM-обвязка), а не движок.

Что делать большой компании, не желающей платить за каждое место? Самый частый обход - поставить Docker Engine прямо внутрь WSL2-дистрибутива (например, в Ubuntu из Microsoft Store) ровно теми же apt-командами, что мы разбирали выше. Engine лицензией Desktop не покрывается, и ты получаешь честный бесплатный Docker на Windows. Минус - нет графики и удобных интеграций Desktop, всё руками. Для DevOps это обычно не проблема. Альтернативы Desktop, набравшие силу к 2026: Podman Desktop, Rancher Desktop, nerdctl поверх containerd - все бесплатные.

Проверка установки: docker version, info и демон

Первое, что делаешь после установки, - убеждаешься, что клиент и демон видят друг друга:

Код: Выделить всё

docker version

Код: Выделить всё

Client: Docker Engine - Community
 Version:           29.4.0
 API version:       1.51
 Go version:        go1.24.x
Server: Docker Engine - Community
 Engine:
  Version:          29.4.0
  API version:      1.51 (minimum version 1.24)
 containerd:
  Version:          2.2.2
 runc:
  Version:          1.2.x
Разбираем по полям. Два блока - Client и Server - это и есть та самая клиент-серверная архитектура. Если Server-блока нет и вылетает ошибка "Cannot connect to the Docker daemon at unix:///var/run/docker.sock" - значит демон не запущен (sudo systemctl start docker) или у тебя нет прав на сокет (вернись к шагу с группой docker). API version - протокол между клиентом и сервером; старый клиент к новому серверу обычно подключится, наоборот - не всегда. И обрати внимание на строки containerd и runc - вот они, те самые слои под капотом, не выдумка из учебника.

Глубже копнуть состояние демона:

Код: Выделить всё

docker info
В выводе ищи поля: Storage Driver (на современных системах overlay2 - это драйвер, который и собирает слои образа в единую файловую систему), Cgroup Version (на 2026-системах почти везде 2 - это влияет на лимиты ресурсов), Default Runtime (runc), и Registry - адрес реестра по умолчанию. Если поднимал rootless, в info будет помечено rootless: true. Это твоя приборная панель: когда что-то идёт не так с лимитами или хранилищем, диагностику начинаешь отсюда.

Первый контейнер: docker run hello-world по шагам

Классика - docker run hello-world. Команда крошечная, а под капотом происходит вся магия:

Код: Выделить всё

docker run hello-world

Код: Выделить всё

Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
c1ec31eb5944: Pull complete
Digest: sha256:...
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.
Что здесь произошло, шаг за шагом:
  • Unable to find image locally - демон поискал образ в локальном кеше (/var/lib/docker), не нашёл.
  • Pulling from library/hello-world - полез в реестр. По умолчанию это Docker Hub, а library - неймспейс официальных образов. Тег latest подставился сам, потому что мы его не указали.
  • Pull complete + Digest - слой скачан, digest sha256 - это криптографический отпечаток образа, гарантия, что ты получил ровно те байты. На этом digest потом строится supply chain: подпись cosign, проверка в Scout/Trivy.
  • Hello from Docker! - демон создал контейнер из образа, запустил единственный процесс, тот напечатал текст и завершился. Контейнер тут же остановился - он живёт ровно столько, сколько живёт его главный процесс. Это фундаментальное правило: нет процесса - нет контейнера.
Жизненный цикл: ps, run, stop, rm и флаги

hello-world умер сразу. Возьмём что-то живущее - nginx - и пройдём весь цикл с реальными флагами.

Код: Выделить всё

docker run -d -p 8080:80 --name web nginx
Разбор флагов, без них дальше никуда:
  • -d (detached) - запустить в фоне, вернуть управление терминалу. Без него консоль "залипнет" на логах контейнера.
  • -p 8080:80 - проброс порта: порт 8080 хоста на порт 80 контейнера. Слева хост, справа контейнер - частая путаница. Теперь curl localhost:8080 достучится до nginx внутри.
  • --name web - человекочитаемое имя. Без него Docker выдаст случайное вроде "nostalgic_turing", и обращаться к контейнеру придётся по ID.
Смотрим, что бежит:

Код: Выделить всё

docker ps

Код: Выделить всё

CONTAINER ID   IMAGE     COMMAND                  STATUS         PORTS                  NAMES
a1b2c3d4e5f6   nginx     "/docker-entrypoint.…"   Up 12 seconds  0.0.0.0:8080->80/tcp   web
Поля по делу: STATUS показывает Up - контейнер жив; PORTS - наш проброс 0.0.0.0:8080->80/tcp, то есть слушает на всех интерфейсах хоста. docker ps без флагов показывает только запущенные; docker ps -a покажет и остановленные (включая тот hello-world - он никуда не делся, лежит мёртвым).

Ещё пара флагов, которые понадобятся сразу:
  • -it - это два флага: -i держит stdin открытым, -t выделяет псевдотерминал. Вместе дают интерактивную сессию. docker run -it ubuntu bash кинет тебя внутрь контейнера в шелл - почувствуй, что внутри своя файловая система, свои процессы, свой hostname.
  • -v - проброс данных (том или bind-mount): docker run -v /home/user/site:/usr/share/nginx/html nginx подсунет nginx твою папку с сайтом. Без -v всё, что контейнер пишет, исчезнет при удалении - контейнеры эфемерны по природе. Тома - это отдельная большая тема следующих глав, тут просто запомни флаг.
Останавливаем и убираем:

Код: Выделить всё

docker stop web
docker rm web
docker stop шлёт процессу SIGTERM и ждёт (по умолчанию 10 секунд), даёт корректно завершиться; если не успел - добивает SIGKILL. Это graceful shutdown, важная вещь для баз данных. docker rm удаляет уже остановленный контейнер. Хочешь снести живой - docker rm -f web (форс, остановит и удалит разом). А чтобы контейнер сам удалялся после завершения, добавляй --rm при запуске - удобно для одноразовых задач.

Грабли и антипаттерны новичка
  • docker compose vs docker-compose. Дефисная версия v1 на Python мертва и убрана. Если в твоих гайдах docker-compose через дефис - они устарели. Только docker compose через пробел.
  • Запуск всего под sudo. Это симптом того, что ты пропустил post-install с группой. И помни: членство в группе docker = root, не раздавай налево.
  • Путаница в портах и томах. И в -p, и в -v формат "хост:контейнер". Перепутал стороны - сервис не отвечает или монтируется не туда. 0.0.0.0 в выводе ps значит "доступно извне" - на проде иногда хочешь 127.0.0.1:8080:80, чтобы наружу не торчало.
  • Накопление мусора. Остановленные контейнеры, висячие образы и тома жрут диск в /var/lib/docker, пока он не кончится в самый неподходящий момент. docker system df покажет аппетит, docker system prune подчистит. Не запускай prune вслепую на проде - снесёт нужное.
  • RU-реалии с Docker Hub. Прямой pull с Docker Hub из России бывает нестабилен или режется лимитами. Решение - зеркала и российские реестры: Yandex Container Registry, VK Cloud, корпоративные Nexus/Harbor. Зеркало прописывается в /etc/docker/daemon.json в поле registry-mirrors, после чего sudo systemctl restart docker. Это не теория, а ежедневная боль локального DevOps.
Мини-лаба: пройди руками
  • Поставь Docker по официальному репозиторию (или get.docker.com на тестовой машине). Сделай post-install с группой docker и проверь docker run hello-world без sudo.
  • Выполни docker version и найди в выводе версии Server, containerd и runc. Объясни себе, почему блоков именно два.
  • Запусти docker run -d -p 8080:80 --name web nginx, открой http://localhost:8080, убедись, что отвечает. Глянь docker ps и прочитай поле PORTS.
  • Останови docker stop web, проверь docker ps (пусто) и docker ps -a (контейнер есть, но Exited). Удали docker rm web.
  • Зайди внутрь чистого контейнера: docker run -it --rm ubuntu bash. Внутри выполни hostname, ps aux, ls / - сравни с хостом. Выйди через exit и убедись, что контейнер удалился сам (--rm).
Контрольные вопросы
  • Из каких компонентов состоит Docker Engine и как docker (CLI) общается с dockerd?
  • Чем docker stop отличается от docker rm и docker rm -f, и что происходит с сигналами процессу?
  • Почему добавление в группу docker эквивалентно выдаче прав root и когда стоит выбрать rootless?
  • В чём разница лицензий Docker Engine и Docker Desktop и как легально получить бесплатный Docker на Windows для большой компании?
Итог

Ты поставил Docker осознанно: знаешь, что demon, CLI, containerd и runc - это разные слои одной цепочки, понимаешь post-install и зачем нужен rootless, не попадёшь на лицензию Docker Desktop и не растеряешься на RU-реалиях с зеркалами. Ты прогнал первый контейнер от pull до exit и прошёл полный жизненный цикл run-ps-stop-rm с флагами -d -it -p -v --name. Это фундамент - дальше строим образы и разбираем слои.
👍3 ❤️2 🔥4 😄 🤔1
✔ Лучший ответ сформирован автоматически — ymstar
Marina_DevOps писал(а):выйдите из сессии и зайдите снова перелогиниваться не обязательно, в том же терминале можно выполнить newgrp docker и группа подхватится сразу. действует правда только в текущей сессии, но чтобы быстро проверить установку хватает
Перейти к ответу →
Аватара пользователя
ymstar
Сообщения: 1
Зарегистрирован: 12 май 2026, 11:40

Re: Установка Docker и запуск первого контейнера

Сообщение ymstar »

✔ Лучший ответ — сформирован автоматически
Marina_DevOps писал(а):выйдите из сессии и зайдите снова
перелогиниваться не обязательно, в том же терминале можно выполнить newgrp docker и группа подхватится сразу. действует правда только в текущей сессии, но чтобы быстро проверить установку хватает
👍 ❤️ 🔥1 😄 🤔
Аватара пользователя
joel
Сообщения: 2
Зарегистрирован: 22 май 2026, 13:13

Re: Установка Docker и запуск первого контейнера

Сообщение joel »

а на windows 10 home все это заведется? помню пару лет назад docker desktop требовал именно pro из-за hyper-v. upd: поставил, с wsl2 работает и на home, hyper-v не понадобился
👍1 ❤️1 🔥 😄 🤔
Аватара пользователя
paffelt
Сообщения: 2
Зарегистрирован: 15 май 2026, 02:20

Re: Установка Docker и запуск первого контейнера

Сообщение paffelt »

спасибо за docker ps -a, я неделю не мог понять куда утекает место на vps за 350 руб. оказалось там полсотни мертвых контейнеров от моих же экспериментов, docker container prune разом все вычистил
👍3 ❤️ 🔥 😄 🤔
Аватара пользователя
vimninja
Сообщения: 1
Зарегистрирован: 21 май 2026, 16:37

Re: Установка Docker и запуск первого контейнера

Сообщение vimninja »

Marina_DevOps писал(а):port is already allocated
у меня эта ошибка была не из-за другого контейнера, а из-за томката на хосте, который сидел на 8080. так что если docker ps пустой, а порт занят, смотрите ss -tlnp, кто его реально держит
👍 ❤️3 🔥 😄 🤔
Ответить
← Предыдущая глава
Что такое Docker и какие задачи он решает
Следующая глава →
Образы: слои, теги и реестр Docker Hub

Все главы курса «Docker: контейнеризация от основ до продакшена»

Поделиться темой: ✈ Telegram VK
Похожие запросы: что такое docker hub и как им пользоватьсякак собрать docker образ из dockerfiledocker compose up как запустить контейнерылучшие практики написания dockerfileкак удалить docker контейнер и образterraform для kubernetes в yandex cloud

Вернуться в «Docker с нуля»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 1 гость