Skip to main content

Лекция 1. Введение в Docker и контейнеризацию

Лекция 1. Введение в Docker и контейнеризацию

Дисциплина: системное администрирование. Редакция от 8 октября 2026 года.

Docker помогает упаковывать приложения, переносить их окружение и управлять запуском. В этой лекции основные понятия рассматриваются на примере небольшого веб-сервиса: от скачивания готового образа до сборки собственной версии сайта.

Результаты изучения

После изучения материала необходимо уметь:

  • Объяснять различие между образом, контейнером и виртуальной машиной.
  • Создавать, останавливать, повторно запускать и удалять контейнер.
  • Проверять его состояние, читать логи и выполнять диагностическую команду.
  • Объяснять запись публикации порта и выбирать адрес доступа.
  • Определять, какие данные сохраняются после удаления контейнера.
  • Собирать простой образ по Dockerfile и заменять контейнер новой версией.

Рабочая среда Docker на Windows: основные определения

Docker Desktop — приложение, которое предоставляет среду запуска Docker на рабочем компьютере, интерфейс управления и интеграцию с Windows. Docker Engine — система, которая создаёт контейнеры, управляет их запуском, сетями и хранилищами. Её фоновая служба называется Docker daemon: она продолжает работать, когда окно терминала закрыто.

Docker CLI — клиент командной строки, запускаемый командой docker. CLI отправляет запросы Engine через API, программный интерфейс управления. Поэтому установленная команда docker и работающий Engine — разные части системы. Термин «хост» далее означает среду, относительно которой выполняется действие: для опубликованного порта Desktop это компьютер Windows, а для Linux-процессов и их ядра — Linux-среда Desktop.

ПонятиеНазначениеУчебный пример
ТерминалОкно для ввода и отображения текстаWindows Terminal
Оболочка — shellРазбирает введённую строку и запускает командыPowerShell в Windows; sh внутри Alpine
CLIКлиент для обращения к Docker Enginedocker ps запрашивает список контейнеров
DaemonФоновая служба, исполняющая запросы управленияСоздаёт контейнер по запросу run
WSL 2Среда Windows для запуска Linux с настоящим Linux-ядром в управляемой виртуализированной средеDocker Desktop может использовать backend WSL 2; Ubuntu для Bash устанавливается отдельно
Студент
   ↓ ввод команды
Windows Terminal → PowerShell → Docker CLI
                                  ↓ запрос API
                          Docker Engine / daemon
                                  ↓ запуск
                 Linux-контейнер в среде Docker Desktop

Нажатие кнопки в Docker Desktop и ввод команды CLI являются разными способами управления объектами Docker. В этой практике команды позволяют явно видеть имя объекта и параметры операции. Выбор backend, доступность Engine и место выполнения команды проверяются в следующем разделе.

Для самопроверки: Почему закрытие PowerShell обычно не останавливает контейнер, запущенный с -d? Какой компонент продолжает им управлять?

Windows и Docker Desktop: выбор среды работы

Учебные примеры запускают Linux-контейнеры через Docker Desktop на Windows. Windows-контейнеры — другой режим; образы nginx:alpine и alpine относятся к Linux. В терминале проверяются доступ к Engine и выбранный режим:

На хосте: PowerShell или Bash.

docker version
docker context show
docker info --format '{{.OSType}}'

Ожидается ответ linux. При ошибке соединения сначала проверяется, что Docker Desktop запущен. Windows Terminal — приложение терминала: открытая вкладка может содержать PowerShell или Bash Ubuntu, и это определяет синтаксис команд.

Место выполненияЧто запускаетсяПример пути
PowerShell в WindowsDocker CLI и команды PowerShellC:\Users\student\docker-lesson1
Ubuntu в WSL 2 с интеграцией Docker DesktopDocker CLI и Bash-команды/home/student/docker-lesson1
Оболочка внутри контейнераLinux-команды контейнерного окружения/data, /usr/share/nginx/html

Для Bash-примеров используется терминал пользовательского дистрибутива WSL 2, а не системный дистрибутив docker-desktop. В Docker Desktop включается интеграция выбранного дистрибутива: Settings → Resources → WSL Integration. Наличие backend WSL 2 само по себе не означает наличие Ubuntu с рабочей интеграцией. В PowerShell Docker можно использовать без Ubuntu. Подробнее: Docker Desktop и WSL 2.

PowerShell- и Bash-варианты выполняются на выбор. При обращении к одному Docker Engine они используют общие контейнеры, сети и тома: повторное выполнение второго варианта может вызвать конфликт имён. В этих примерах Windows-папка и отдельная папка /home в WSL содержат разные наборы файлов. Через /mnt/c или /mnt/f WSL может обращаться к той же Windows-папке; это не новая копия проекта. Основной маршрут практики ниже — PowerShell и папки Windows. Bash-блоки показывают альтернативный синтаксис. При выборе Bash необходимые папки и файлы также готовятся заранее: Windows-проект можно открыть через /mnt/c или /mnt/f, а отдельный Linux-проект — через Проводник по пути \\wsl.localhost к своему дистрибутиву и редактор. Для сборки терминал должен быть открыт в папке соответствующего Dockerfile; путь Windows C:\… нельзя вставлять в Bash как Linux-путь. Docker context show показывает выбранный контекст, а docker info — сведения о сервере. Имена контекстов в Windows и WSL могут отличаться даже при обращении к одному Engine; совпадение имени контекста само по себе также не доказывает совпадение серверов.

Как читать блоки команд

ДействиеBash / WSLPowerShell
Перенос командыОбратная косая черта \ в конце строкиОдна строка либо обратный апостроф `; после него не должно быть пробелов
HTTP-запросcurl URLcurl.exe URL — явный запуск утилиты, независимо от алиаса curl
Создание каталогаВ Linux-примере каталог готовится заранееСоздать папку в Проводнике
Просмотр файлаcat FILEGet-Content FILE
Паузаsleep 10Start-Sleep -Seconds 10
Текущий каталог$PWD(Get-Location).Path
Подготовка файловСодержимое сохраняется в указанном файлеСоздать файл в редакторе и сохранить в папке проекта

Команды Dockerfile и исходный код программы не являются командами PowerShell. В блоках с пометкой «внутри контейнера» сохраняется Linux-синтаксис: например, после docker exec -it … sh команды cat, ps и exit выполняются контейнерной оболочкой. Строка после docker … sh -c также обрабатывается Linux-оболочкой внутри контейнера, даже если Docker CLI запущен из PowerShell.

В PowerShell 5.1 символы && и || вне строки аргумента не поддерживаются как Bash-операторы. Встроенные двойные кавычки в аргументах внешних программ тоже могут передаваться иначе, чем в PowerShell 7. Ниже PowerShell-примеры используют простые аргументы; сложные Bash-блоки выполняются в WSL, а не копируются без изменений в PowerShell.

Подготовка папок и файлов средствами Windows

Папки создаются в Проводнике. В нужной папке выбирается «Открыть в терминале» и вкладка PowerShell; если терминал открылся в другом месте, расположение проверяется через Get-Location. Dockerfile, .dockerignore, HTML и исходники создаются в обычном редакторе и сохраняются в указанную папку. Команды создания папок и записи файлов PowerShell в этой лекции не требуются.

В Проводнике включается показ расширений: файл должен называться Dockerfile, а не Dockerfile.txt, и .dockerignore, а не .dockerignore.txt. В редакторе выбирается UTF-8; для скриптов и конфигурации предпочтительно без BOM. Если Блокнот добавляет .txt, при сохранении выбирается тип «Все файлы» и проверяется итоговое имя в Проводнике. Для Linux shell-скриптов также выбирается LF; иначе возможны ошибки /bin/sh^M или not found. Перед сохранением учебного примера проверяется, что файл не содержит чужой работы.

1. Зачем нужна контейнеризация

При переносе приложения с компьютера разработчика на сервер требуется воспроизвести его окружение. Приложению могут понадобиться конкретная версия языка, библиотеки, системные пакеты и конфигурация. На сервере уже могут работать другие программы с несовместимыми зависимостями. В результате одни и те же исходные файлы ведут себя по-разному в разработке, тестировании и эксплуатации.

Окружение можно устанавливать вручную или описывать средствами управления конфигурацией, например Ansible. Другой способ — выделять приложениям отдельные виртуальные машины. Контейнеризация решает задачу упаковки иначе: файлы приложения и его пользовательские зависимости включаются в образ, а приложение запускается в изолированном окружении.

Контейнеризация — способ запуска приложений в изолированных окружениях на основе механизмов операционной системы. Linux-контейнеры используют ядро Linux среды, в которой они запущены.

Образ помогает воспроизводить пользовательское окружение, но сам по себе не гарантирует одинаковую работу всей системы. Значение имеют параметры запуска, права доступа, внешние базы данных, сеть, архитектура процессора и совместимость ядра. Например, пароль к базе данных и её адрес задаются для конкретной среды, а не обязательно входят в образ.

Для администратора контейнеризация полезна при развёртывании сервисов, создании тестовых окружений, разделении зависимостей и автоматизации доставки новых версий приложения.

2. Образ, контейнер и реестр

Для первого запуска достаточно различать три основных объекта.

ОбъектЗначениеПример
Образ — imageНеизменяемый шаблон файловой системы и параметров запускаnginx:alpine
Контейнер — containerСозданный из образа экземпляр со своей конфигурацией, состоянием и записываемым слоемlesson1-web
Реестр — registryСервис хранения и распространения образовDocker Hub

Образ содержит файлы приложения, библиотеки и метаданные. Он не является работающим процессом. Из одного образа можно создать несколько контейнеров с разными именами, сетевыми параметрами и хранилищами. Контейнер остаётся объектом Docker и после остановки главного процесса, пока не будет удалён.

Образ задаёт основу окружения. Контейнер — конкретный экземпляр, созданный из этой основы. Скачивание образа, создание контейнера и запуск процесса являются отдельными действиями.

В имени nginx:alpine часть nginx обозначает репозиторий образа, а alpine — тег варианта. В обычной конфигурации полное имя — docker.io/library/nginx:alpine. Репозиторий группирует варианты образа внутри реестра. Если тег не указан, используется latest; это обычная метка, которая не гарантирует последнюю версию приложения.

Тег — изменяемая метка для выбора образа. Digest — идентификатор содержимого, обычно записанный как sha256:…; в ссылке на образ он указывается после @. Image ID из локального списка и digest ссылки на образ не следует считать одним полем. Для фиксации проверенного выпуска выбирают ссылку с digest, а для учебных сборок далее используются понятные теги версий.

Теги могут указывать на новое содержимое со временем. Для контролируемых выпусков выбирают проверенные версии, а для фиксации конкретного содержимого используют digest. В учебных примерах nginx:alpine выбран как компактный образ знакомого HTTP-сервера.

3. Контейнер и виртуальная машина

Виртуальная машина получает виртуальное оборудование и запускает собственную гостевую ОС с собственным ядром. Контейнер изолирует процессы и их окружение средствами операционной системы. Его файловая система может содержать пользовательское окружение Alpine или Ubuntu, но отдельное ядро Linux в обычном контейнере не загружается.

СвойствоВиртуальная машинаLinux-контейнер
Основа изоляцииВиртуальный компьютерПроцессы и их окружение
ЯдроСобственное гостевое ядроОбщее ядро среды запуска
ЗапускВключает загрузку гостевой ОСВключает подготовку окружения и запуск процесса
ПрименениеОтдельные серверные ОС и инфраструктурные границыУпаковка, запуск и замена приложений

Контейнеры обычно быстрее запускаются и требуют меньше дополнительных ресурсов, поскольку каждому не нужна отдельная гостевая ОС. Это не означает, что само приложение расходует меньше памяти или CPU. Контейнер и ВМ предоставляют разные границы изоляции; выбор зависит от задачи.

Эти технологии часто используют вместе: на виртуальном сервере устанавливают Docker Engine и запускают контейнеры. Для Linux-контейнеров через Docker Desktop на Windows или macOS ядро предоставляет виртуализированная Linux-среда. Поэтому «ядро хоста контейнера» не обязательно означает ядро компьютера, на котором открыт терминал Docker CLI.

4. Первый запуск веб-сервиса

Для начала запускается Docker Desktop. В выбранном терминале проверяются docker version и docker info --format '{{.OSType}}'. Ожидается linux. Требования установки проверяются по официальной инструкции Docker Desktop. Наличие приложения не требует устанавливать отдельный Docker Engine в Ubuntu WSL.

Порядок работы с практическими разделами

Каждый эксперимент проходит семь шагов: определить понятия → объяснить задачу на примере → подготовить папки и файлы → выполнить команды → проверить ожидаемый результат → объяснить причину результата → ответить на вопрос для самопроверки. Подготовка выполняется Проводником и редактором; команды Docker вводятся в указанной оболочке. Практика продолжается после проверки предыдущего шага, а не после простого копирования блока.

Если результат отличается, фиксируются команда, текст ошибки, состояние контейнера и выбранная среда. Затем используется соответствующий диагностический раздел. Для отчёта достаточно сохранить команды, существенную часть вывода и объяснение: какой объект изменился и почему.

Программа, процесс и сервис

Программа — исполняемый код и необходимые ему файлы. Процесс — запущенный экземпляр программы со своим состоянием, памятью и идентификатором PID. Один файл программы может использоваться несколькими процессами. Наличие программы в образе ещё не означает, что она выполняется.

Сервис — программа или согласованная группа процессов, предоставляющая функцию другим программам или пользователям. Веб-сервис обычно остаётся запущенным и ждёт запросов. Главный процесс контейнера должен продолжать работу: если он завершится, контейнер остановится. Принцип foreground означает, что основной процесс остаётся активным, а не запускается в фоне из оболочки, которая сразу заканчивает работу. Параметр Docker -d отделяет терминал клиента от контейнера; он не требует переводить приложение внутри контейнера в background.

В примерах используется nginx — веб-сервер. Он получает запрос по HTTP, протоколу обмена между клиентом и веб-сервером, и отдаёт файл страницы. HTML — язык разметки этой страницы; браузер отображает её, а curl.exe выводит полученное содержимое в терминал. Nginx может создавать несколько процессов, поэтому «один сервис» не означает строго «один процесс».

Образ содержит программу nginx и файлы страницы
   ↓ docker run
В контейнере работают процессы nginx
   ↓ запрос браузера или curl.exe
Nginx возвращает HTML-страницу

Для самопроверки: Почему скачанный образ nginx сам по себе не обслуживает HTTP-запросы? Чем -d отличается от завершения главного процесса?

4.1. Условия выполнения

Учебная среда — Windows с запущенным Docker Desktop в режиме Linux containers. Команды выполняются в PowerShell либо Bash в интегрированном WSL. Для скачивания образов нужен доступ к реестру. Sudo относится к отдельной серверной установке Linux и не добавляется перед docker в PowerShell.

Команды Docker выполняются в выбранном терминале Windows или WSL, кроме блока, явно обозначенного как работа внутри контейнера. Примеры этой лекции образуют последовательность. Перед началом проверяется, что имя lesson1-web и порт 8080 свободны. Ранее созданные объекты с важными данными не удаляются ради выполнения примера.

На хосте: PowerShell или Bash.

docker version
docker info
docker ps -a

Ожидаемый результат: docker version выводит сведения о клиенте и сервере; docker info показывает параметры Docker Engine. В docker ps -a не должно быть прежнего контейнера lesson1-web. Наличие команды docker само по себе не означает доступность демона.

Как читать команду Docker и имена объектов

Командная строка читается слева направо. После docker выбирается действие. Для run параметры Docker находятся перед именем образа; после образа могут идти команда контейнера и её аргументы. Параметр — именованная настройка операции; аргумент — переданное ей значение. Кавычки объединяют текст с пробелами в один аргумент. Следующая запись — схема синтаксиса: IMAGE заменяется именем образа, а квадратные скобки обозначают необязательные части и не вводятся буквально в терминал.

docker run [параметры Docker] IMAGE [COMMAND] [ARGUMENTS]
Часть учебной командыЗначение
docker runСоздать новый контейнер и запустить его
--name lesson1-webДать контейнеру имя lesson1-web
-dПродолжить работу контейнера без удержания текущего терминала
-p 127.0.0.1:8080:80Настроить публикацию порта
nginx:alpineВыбрать образ; это не имя контейнера

Запись nginx:alpine обозначает репозиторий и тег образа. lesson1-web — выбранное имя конкретного контейнера. Container ID — идентификатор, который Docker присваивает контейнеру; он изменяется при создании нового экземпляра. Image ID — идентификатор образа. Команды start, stop, logs и exec обычно получают имя или ID контейнера, а run и build работают с образами в соответствии со своим назначением. Для ясности учебные команды используют полные имена контейнеров.

Например, в строке docker run --rm alpine echo done параметры --rm относятся к Docker, alpine — образ, echo — программа контейнера, done — её аргумент. После имени образа строка уже не разбирается как набор параметров Docker. Готовый образ nginx задаёт собственную команду запуска, поэтому она не повторяется в первом run.

Для самопроверки: Какой объект получает имя lesson1-web и какой выбирается записью nginx:alpine? Что изменит повторный run, а что делает start?

4.2. Скачивание образа

На хосте: PowerShell или Bash.

docker pull nginx:alpine
docker image ls nginx

Ожидаемый результат: Docker скачивает необходимые слои либо сообщает, что образ актуален. В списке образов появляется nginx с тегом alpine. Колонки REPOSITORY и TAG описывают имя, IMAGE ID — локальный идентификатор. Контейнер на этом шаге ещё не создаётся.

Запуск и готовность — разные шаги. Команды выполняются последовательно, с проверкой результата каждого шага. Ответ docker run -d или docker start ещё не означает, что приложение готово принимать HTTP. При первом Connection refused нужно подождать несколько секунд и повторить запрос. Если ответ не появляется, проверяются docker ps -a и docker logs для этого контейнера. Для образа с HEALTHCHECK ожидается healthy, а не только running; проверка состояния повторяется через inspect. Сетевой запрос проверяет именно указанный адрес и порт.

IP-адрес, порт и localhost

IP-адрес определяет сетевой адрес назначения. Порт позволяет выбрать приложение или точку приёма соединений на этом адресе. Порт относится к транспортному протоколу: TCP и UDP имеют отдельные пространства портов. В учебном nginx-примере используется HTTP через TCP. Слушающий процесс ожидает подключения к выбранному адресу и порту.

Loopback — сетевой путь обратно в ту же среду. Адрес 127.0.0.1 — IPv4 loopback; имя localhost обычно указывает на loopback-адрес, включая IPv6 ::1. Далее используется явный IPv4-адрес, чтобы адрес запроса совпадал с адресом публикации. Localhost внутри контейнера относится к этому контейнеру, а в браузере Windows — к компьютеру Windows.

Браузер Windows или curl.exe
   ↓ HTTP-запрос к 127.0.0.1:8080
Публикация порта Docker Desktop
   ↓ передача запроса на TCP 80 контейнера
Процесс nginx
   ↓ чтение index.html и HTTP-ответ
Клиент получает HTML

В записи -p 127.0.0.1:8080:80 слева находится адрес и порт Windows-хоста, справа — порт приложения внутри контейнера. Публикация не перенастраивает nginx слушать 8080. Если приложение не запущено или не слушает порт 80, одна публикация не создаст работоспособный сервис.

Для самопроверки: Почему в адресе браузера используется 8080, а nginx внутри контейнера продолжает слушать 80? Почему localhost другого контейнера не ведёт к nginx?

4.3. Создание контейнера и публикация порта

Bash / WSL:

docker run --name lesson1-web -d \
  -p 127.0.0.1:8080:80 nginx:alpine
docker ps --filter name=lesson1-web
curl http://127.0.0.1:8080

PowerShell:

docker run --name lesson1-web -d  -p 127.0.0.1:8080:80 nginx:alpine
docker ps --filter name=lesson1-web
curl.exe http://127.0.0.1:8080

docker run создаёт новый контейнер и запускает его. --name задаёт имя, -d запускает контейнер в фоне. В записи -p 127.0.0.1:8080:80 адрес 127.0.0.1 относится к хосту, 8080 — порт хоста, 80 — порт nginx внутри контейнера.

Ожидаемый результат: run выводит идентификатор контейнера; в docker ps виден статус Up; curl возвращает HTML стандартной страницы nginx. В колонке PORTS отражается публикация 127.0.0.1:8080->80/tcp.

При удалённом подключении к серверу curl выполняется на этом сервере. Адрес 127.0.0.1 в браузере личного компьютера относится к самому компьютеру. Наличие контейнера на удалённом сервере не меняет значение localhost.

Docker Desktop на Windows. Опубликованный порт открывается из Windows-браузера по http://127.0.0.1:8080. Внутри контейнера localhost означает сам контейнер. Для обращения из контейнера к сервису Windows-хоста используется host.docker.internal и порт этого сервиса. Для связи контейнеров используются их сетевые имена. Bridge и veth принадлежат Linux-среде Docker Desktop, а не обычным интерфейсам Windows. IP контейнера не является основным адресом доступа из Windows. Документация сети.

Для самопроверки: Какой путь прошёл HTTP-запрос после первого запуска? Какие команды помогут отличить недоступный Engine от работающего контейнера с неготовым nginx?

4.4. Первые сообщения об ошибках

СимптомЧто проверить
Cannot connect to the Docker daemonЗапущен ли демон и к какому Engine обращается клиент
Permission denied при доступе к Docker socketРазрешён ли пользователю доступ; для обычной серверной установки — запуск через sudo
Имя контейнера уже используетсяdocker ps -a: остановленный контейнер тоже сохраняет имя
Порт уже занятДругой сервис или контейнер на хосте может использовать 8080
curl не получает ответСтатус контейнера, логи, публикацию порта и правильный адрес хоста

5. Диагностика, остановка и удаление

Ввод, вывод и чтение результатов диагностики

ПотокОпределениеПример
stdin — стандартный вводДанные, передаваемые процессу на входКоманды, вводимые в интерактивную оболочку
stdout — стандартный выводОбычный вывод процессаТекст результата или сообщения о работе
stderr — стандартный вывод ошибокОтдельный поток диагностических сообщенийПредупреждение или сообщение об ошибке

stdout и stderr обычно отображаются в одном окне терминала, но являются разными потоками. Запись сообщения в stderr сама по себе не означает остановку процесса. Лог — последовательность сообщений о событиях; Docker может собирать stdout/stderr контейнера через настроенный драйвер. Файл журнала внутри контейнера не обязательно автоматически появляется в docker logs.

Для диагностики сравниваются состояние объекта, конфигурация и сообщения приложения. Следующая строка — учебный пример вывода docker ps; ID и длительность на каждом компьютере будут другими.

CONTAINER ID   IMAGE          STATUS          PORTS                    NAMES
abc123def456   nginx:alpine   Up 20 seconds   127.0.0.1:8080->80/tcp   lesson1-web
КолонкаЧто она сообщает
CONTAINER IDИдентификатор конкретного контейнера
IMAGEОбраз, из которого он создан
STATUSСостояние и время работы; это не доказательство успешного HTTP-ответа
PORTSПубликации портов и сведения о контейнерных портах
NAMESИмена контейнеров

docker ps по умолчанию перечисляет работающие контейнеры, docker ps -a — также остановленные. Полный JSON из inspect — структурированные сведения в форме пар «поле — значение». На первом этапе в нём ищутся State, Config и NetworkSettings, а не запоминается весь вывод. Код завершения — числовой результат закончившейся команды или процесса — подробно рассматривается во второй лекции.

Для самопроверки: Если в logs есть сообщение об ошибке, как проверить, остановился ли контейнер? Доказывает ли статус Up доступность страницы?

5.1. Логи и конфигурация

На хосте: PowerShell или Bash.

docker logs --tail 20 lesson1-web
docker inspect lesson1-web
docker port lesson1-web

Ожидаемый результат: logs показывает сообщения запуска и обработки запросов; inspect выводит JSON с состоянием, образом, сетью и точками подключения; port показывает адрес и порт публикации. Конкретные сообщения зависят от версии образа.

docker logs читает доступный журнал stdout и stderr с учётом используемого драйвера логирования. Для наблюдения за новыми строками используется docker logs -f lesson1-web. Выход по Ctrl+C прекращает наблюдение и оставляет контейнер работающим.

5.2. Дополнительный процесс внутри контейнера

На хосте: PowerShell или Bash.

docker exec -it lesson1-web sh

exec запускает дополнительный процесс в работающем контейнере. -i оставляет ввод открытым, -t выделяет псевдотерминал. В данном образе используется оболочка sh.

Следующий блок выполняется внутри контейнера:

hostname
cat /etc/os-release
ps
exit

Ожидаемый результат: видны имя контейнерного окружения, сведения об Alpine и процессы, доступные внутри контейнера. exit завершает добавленную оболочку; основной процесс nginx продолжает работать. Файл /etc/os-release описывает пользовательское окружение образа, а не отдельное ядро контейнера.

5.3. Остановка и повторный запуск

Bash / WSL:

docker stop lesson1-web
docker ps --filter name=lesson1-web
docker ps -a --filter name=lesson1-web
docker start lesson1-web
curl http://127.0.0.1:8080

PowerShell:

docker stop lesson1-web
docker ps --filter name=lesson1-web
docker ps -a --filter name=lesson1-web
docker start lesson1-web
curl.exe http://127.0.0.1:8080

Ожидаемый результат: после stop контейнер исчезает из обычного docker ps, но остаётся в docker ps -a со статусом Exited. start запускает тот же контейнер с прежней конфигурацией; сайт снова отвечает.

run создаёт новый контейнер. start запускает существующий остановленный контейнер. stop завершает работу, сохраняя объект контейнера. rm удаляет этот объект.

5.4. Удаление

На хосте: PowerShell или Bash.

docker stop lesson1-web
docker rm lesson1-web
docker ps -a --filter name=lesson1-web
docker image ls nginx

Ожидаемый результат: контейнера больше нет, но образ nginx:alpine остаётся локально. Имя lesson1-web освободилось. Оно будет использовано далее для контейнера собственного сайта.

Для одноразовых задач применяется --rm: Docker автоматически удаляет контейнер после завершения процесса. Этот параметр не удаляет исходный образ. Принудительное rm -f не заменяет корректную остановку сервисов, которым нужно завершить запись данных.

При работе из Windows docker exec … uname -a показывает Linux-ядро среды Docker Desktop. Команда uname -a непосредственно в PowerShell может отсутствовать и не является способом проверить ядро Windows.

6. Как Docker выполняет команды

Docker — платформа и набор инструментов для сборки, распространения образов и управления контейнерами. Docker Engine включает демон, API и клиент командной строки. При выполнении docker ps клиент обращается к API, а демон возвращает сведения о контейнерах.

Основная схема управления: Docker CLI → Docker API → Docker daemon. Клиент может обращаться к локальному или удалённому Docker Engine.

При запуске контейнера dockerd координирует нижележащие компоненты, включая containerd и OCI runtime, обычно runc. Результат — процесс с подготовленным окружением и ограничениями. Подробности этих компонентов относятся к внутреннему устройству платформы; для базовой диагностики прежде всего нужно различать клиент и доступный ему демон.

Linux предоставляет два ключевых механизма. Namespaces изменяют представление процесса о ресурсах: например, о дереве процессов, сети и точках монтирования. Cgroups учитывают и ограничивают потребление ресурсов группами процессов, включая память и CPU.

МеханизмОсновной вопросПример
NamespacesКакие ресурсы видит процесс?Контейнер видит собственную таблицу процессов
CgroupsКакие ресурсы он может потреблять?Контейнер получает ограничение памяти

Перечень возможностей Linux не означает, что все пространства имён одинаково используются в любой конфигурации. Например, сопоставление пользователей через user namespaces настраивается отдельно; модели rootful, userns-remap и rootless имеют различия.

По умолчанию контейнеру не выделяется фиксированная доля ресурсов. Если лимиты не заданы, он конкурирует с другими процессами за ресурсы среды запуска. Docker предоставляет параметры ограничения, например --memory и --cpus.

Работа контейнера связана с его главным процессом, обычно PID 1 внутри PID namespace. Завершение главного процесса останавливает контейнер. При docker stop сначала посылается сигнал корректного завершения, а после истечения времени ожидания при необходимости применяется принудительное завершение. Подробная обработка сигналов рассматривается во второй лекции.

7. Сетевая доступность сервиса

Процесс nginx слушает порт 80 внутри контейнера. Этот факт не создаёт автоматическую публикацию порта на хосте. Сетевой доступ задаётся отдельно. Инструкция EXPOSE в образе документирует предполагаемый порт и сама по себе не заменяет -p.

ПараметрЗначение
-p 127.0.0.1:8080:80Порт контейнера доступен через localhost Docker-хоста
-p 8080:80Порт публикуется на всех адресах хоста по умолчанию; фактический доступ зависит от сети и фильтрации
-p 80:8080Порт 80 хоста направляется на порт 8080 контейнера; это не соответствует стандартному слушателю nginx на 80

В первом примере выбран loopback-адрес, поскольку изучение команд не требует открывать сервис во внешнюю сеть. Для удалённых пользователей нужен другой способ предоставления доступа, выбранный с учётом конфигурации сервера.

В пользовательской bridge-сети контейнеры могут обращаться друг к другу по именам без публикации их портов на хосте. Подробные примеры сетей, DNS и взаимодействия нескольких сервисов приведены во второй лекции.

Пути Windows и Linux. Источник bind mount в PowerShell — существующий Windows-путь, например C:\Users\student\docker-lesson1\bind-site. Назначение в контейнере остаётся Linux-путём /data или /usr/share/nginx/html. В WSL путь /mnt/c обозначает диск C:, а /home — Linux-файловую систему дистрибутива. Docker Desktop предоставляет контейнерам доступ к файлам Windows. Named volume управляется Docker, его не следует искать как обычную папку проекта в Проводнике. Bind mounts.

8. Данные и жизненный цикл контейнера

Изменения файлов в обычных каталогах контейнера попадают в его записываемый слой — writable layer. Остановка и повторный запуск сохраняют этот слой. Удаление контейнера удаляет слой: новый контейнер из прежнего образа не получает старые изменения.

Место храненияНазначениеПосле удаления контейнера
Writable layerИзменения конкретного экземпляраУдаляется вместе с контейнером
Named volumeПостоянное хранилище, управляемое DockerСохраняется, пока том не удалён отдельно
Bind mountПодключение конкретного пути Docker-хостаФайлы остаются по пути хоста

Для проверки постоянства создаётся отдельный учебный том. Перед началом имя lesson1-data должно быть свободно. Команды выполняются на хосте:

Bash / WSL:

docker volume create lesson1-data
docker run --rm \
  --mount type=volume,src=lesson1-data,dst=/data \
  alpine sh -c 'echo lesson 1 data > /data/note.txt'
docker run --rm \
  --mount type=volume,src=lesson1-data,dst=/data,ro \
  alpine cat /data/note.txt

PowerShell:

docker volume create lesson1-data
docker run --rm  --mount type=volume,src=lesson1-data,dst=/data  alpine sh -c 'echo lesson 1 data > /data/note.txt'
docker run --rm  --mount type=volume,src=lesson1-data,dst=/data,ro  alpine cat /data/note.txt

Ожидаемый результат: второй контейнер выводит lesson 1 data. Первый контейнер к этому моменту уже удалён благодаря --rm, но файл сохранён в именованном томе. Оба временных контейнера удаляются; том остаётся до завершающей очистки.

Bind mount используется, когда контейнеру нужен конкретный файл или каталог хоста, например конфигурация. Если запись не требуется, подключение задаётся только для чтения. Выбор типа хранения и права доступа подробно рассматриваются во второй лекции.

Постоянные данные отделяют от заменяемого контейнера. Наличие volume не является резервной копией: удаление или повреждение данных внутри тома требует отдельной защиты и восстановления.

9. Собственный образ статического сайта

Dockerfile, исходные файлы, образ и слои

Исходные файлы проекта — материалы, из которых готовится приложение: в этом примере index.html. Dockerfile — текстовое описание действий сборки, а не готовый образ и не команда PowerShell. Сборка создаёт образ по этому описанию и доступным входным файлам. Контекст сборки — набор файлов, доступный сборщику; точка в команде build означает текущую папку.

Папка docker-lesson1
  Dockerfile + index.html
          ↓ docker build
  Образ lesson1-site:1.0
          ↓ docker run
  Контейнер lesson1-web с процессами nginx

Слой образа описывает изменения файловой системы относительно предыдущих слоёв: добавление, изменение или удаление файлов. Базовый nginx-образ уже содержит программу и её окружение. COPY добавляет учебную страницу. Docker объединяет слои в доступную контейнеру файловую систему и предоставляет отдельный записываемый слой экземпляра.

Записываемый слой контейнера — изменения данного экземпляра
----------------------------------------------------------
Слой с index.html, добавленный при сборке учебного образа
----------------------------------------------------------
Слои базового nginx-образа — nginx, библиотеки, окружение

Не каждая инструкция Dockerfile добавляет файловый слой: часть инструкций задаёт метаданные запуска. Редактирование файла в контейнере не переписывает исходный Dockerfile или образ. Редактирование index.html в папке проекта тоже не меняет готовый образ до новой сборки. В разделе о выпуске версии эти различия проверяются на одном сайте. Образы и слои в документации Docker.

Для самопроверки: Что нужно повторить после изменения исходного index.html, чтобы новый контейнер получил обновлённую страницу? Почему старая страница может оставаться в уже запущенном контейнере?

9.1. Подготовка файлов

Dockerfile описывает сборку образа. Для простого сайта достаточно выбрать базовый nginx-образ и добавить index.html. Для подготовки файлов используются Проводник и редактор. Используется отдельный учебный каталог; если он уже существует с другими файлами, для примера выбирается новый путь.

Windows: в Проводнике создать папку docker-lesson1 в удобном месте. В ней редактором создать index.html и Dockerfile. После сохранения файлов открыть PowerShell в этой папке.

Файл index.html: создать или открыть в редакторе, сохранить следующее содержимое.

<h1>Docker: first site</h1>

Файл Dockerfile: создать или открыть в редакторе, сохранить следующее содержимое.

FROM nginx:alpine
COPY index.html /usr/share/nginx/html/index.html

Ожидаемый результат: в выбранной папке docker-lesson1 должны находиться два файла: index.html и Dockerfile. FROM задаёт базовый образ, COPY добавляет страницу в каталог nginx.

9.2. Сборка и запуск

Bash / WSL:

docker build -t lesson1-site:1.0 .
docker run --name lesson1-web -d \
  -p 127.0.0.1:8080:80 lesson1-site:1.0
curl http://127.0.0.1:8080

PowerShell:

docker build -t lesson1-site:1.0 .
docker run --name lesson1-web -d  -p 127.0.0.1:8080:80 lesson1-site:1.0
curl.exe http://127.0.0.1:8080

Сборка выполняется из каталога, где подготовлены Dockerfile и index.html. Точка обозначает текущий каталог как контекст сборки — набор файлов, доступных builder. lesson1-site:1.0 — имя и тег нового образа.

Ожидаемый результат: сборка завершается успешно, новый контейнер получает имя lesson1-web, а curl выводит страницу Docker: first site. Контейнер с этим именем из раздела 5 уже удалён; сейчас создаётся другой экземпляр из собственного образа.

9.3. Выпуск новой версии

Шаг 1 — редактор Windows: изменить index.html и сохранить страницу.

Файл index.html: создать или открыть в редакторе, сохранить следующее содержимое.

<h1>Docker: updated site</h1>

Шаг 2 — терминал в той же папке: собрать образ и заменить контейнер.

docker build -t lesson1-site:1.1 .
curl.exe http://127.0.0.1:8080
docker stop lesson1-web
docker rm lesson1-web
docker run --name lesson1-web -d -p 127.0.0.1:8080:80 lesson1-site:1.1
curl.exe http://127.0.0.1:8080

Ожидаемый результат: сразу после новой сборки работающий контейнер всё ещё отдаёт первую страницу. Только после его замены контейнером из lesson1-site:1.1 появляется Docker: updated site. Изменение файлов на хосте и сборка образа сами по себе не обновляют уже созданный контейнер.

Этот пример иллюстрирует воспроизводимое обновление: изменить исходники, собрать образ, создать новую версию контейнера. Ручная правка через docker exec не входит в исходный образ и теряется при пересоздании. Для реального сервиса также планируются перерыв в работе, проверка новой версии и возможность отката.

RUN, CMD, ENTRYPOINT, кеш сборки, .dockerignore и многоэтапные сборки подробно рассматриваются во второй лекции. На этом этапе важно различать сборку образа и запуск контейнера.

Для самопроверки: Какие действия изменили исходники, какие создали новый образ, а какие заменили контейнер? Почему сборка версии 1.1 не обновила работающую версию 1.0 автоматически?

10. Базовые правила безопасной эксплуатации

  • Запускать образы из проверенных источников и управлять их обновлением.
  • Публиковать только необходимые порты; для локальных примеров выбирать loopback.
  • Отделять постоянные данные от writable layer и планировать резервное копирование.
  • Не выдавать --privileged и запись в каталоги хоста без обоснованной необходимости.
  • Защищать Docker daemon и не передавать его socket недоверенным приложениям.
  • По возможности запускать приложение непривилегированным пользователем и ограничивать ресурсы.

На отдельном Linux-сервере в обычной rootful-конфигурации доступ к Docker daemon предоставляет широкие возможности управления этим сервером. Членство в Linux-группе docker следует рассматривать как привилегированный доступ. Для Docker Desktop на Windows группа docker из Linux-инструкции не является способом настройки Windows-учётной записи; доступ к Desktop и подключённым каталогам управляется средствами Windows и Docker Desktop. Контейнерная изоляция не устраняет уязвимости приложения и не заменяет управление правами.

Завершение учебного сценария

Следующие команды выполняются после всех примеров и удаляют только созданные ими объекты. Удаление lesson1-data уничтожает учебный файл note.txt. Исходные файлы сайта остаются в каталоге docker-lesson1.

На хосте: PowerShell или Bash.

docker stop lesson1-web
docker rm lesson1-web
docker volume rm lesson1-data
docker image rm lesson1-site:1.0 lesson1-site:1.1
docker ps -a --filter name=lesson1-web
docker volume ls --filter name=lesson1-data

Ожидаемый результат: контейнер, учебный том и два собственных образа удалены. Готовые базовые образы nginx и alpine могут оставаться локально. Общая очистка Docker-хоста для завершения этого сценария не требуется.

11. Задания для самопроверки

Задание 1. После docker stop lesson1-web команда docker ps не показывает контейнер. Нужно ли снова выполнять docker run? Какая команда позволит проверить, сохранился ли контейнер?

Ответ. Состояние проверяется через docker ps -a. Остановленный контейнер запускается командой docker start. Повторный run создавал бы новый объект и при прежнем имени вызвал бы конфликт.

Задание 2. Один файл записан в writable layer, второй — в named volume. Контейнер остановлен, затем удалён. Какие данные сохранятся на каждом шаге?

Ответ. После остановки сохраняются оба файла. После удаления контейнера записываемый слой удаляется, а файл в именованном томе остаётся. Отдельное удаление тома уничтожит и этот файл.

Задание 3. Nginx слушает порт 80 внутри контейнера. Требуется доступ только с Docker-хоста через порт 8080. Правильна ли запись -p 80:8080?

Ответ. Нет. Нужна запись -p 127.0.0.1:8080:80. Слева задаются адрес и порт хоста, справа — порт контейнера.

Задание 4. Образ сайта пересобран с новой страницей. Почему уже работающий контейнер продолжает отдавать старую страницу?

Ответ. Контейнер создан из прежнего образа. Новая сборка не меняет его автоматически. Для обновления создаётся контейнер из новой версии образа.

Задание 5. Внутри контейнера /etc/os-release сообщает Alpine. Доказывает ли это наличие отдельного ядра Alpine?

Ответ. Нет. Файл описывает пользовательское окружение. Системные вызовы обслуживает ядро Linux среды запуска контейнера.

12. Краткий конспект и переход к следующей лекции

  • Образ — шаблон файлов и параметров запуска; контейнер — созданный из него экземпляр.
  • Linux-контейнеры разделяют ядро среды запуска; виртуальная машина имеет гостевое ядро.
  • run создаёт и запускает; stop останавливает; start повторно запускает; rm удаляет.
  • ps, logs, inspect и exec помогают определить состояние и причины проблем.
  • Публикация порта задаётся отдельно от порта, который слушает приложение.
  • Постоянные данные сохраняются в отдельных хранилищах, а не только в writable layer.
  • Новая версия приложения оформляется новой сборкой образа и заменой контейнера.
  • Namespaces изолируют представление ресурсов, cgroups учитывают и ограничивают их использование.

Во второй лекции рассматриваются пользовательские сети и DNS, типы хранения и права доступа, структура Dockerfile, кеш сборки, PID 1, сигналы, проверки работоспособности и автоматический перезапуск. Основой этих тем служит выполненный здесь жизненный цикл одного сервиса.

Приложение. Docker Engine на отдельном Ubuntu Server

К Windows с Docker Desktop этот способ установки не относится. Apt, systemctl и usermod ниже выполняются на отдельном Linux-сервере. В PowerShell они не используются, а в интегрированном WSL для учебных примеров не требуется второй Docker Engine.

Установка через официальный apt-репозиторий включает удаление конфликтующих пакетов, добавление ключа и источника пакетов, установку компонентов и проверку запуска. Пример предназначен для учебной Ubuntu Server; перед применением проверяется поддержка версии ОС в официальной инструкции Docker.

Сначала удаляют конфликтующие пакеты, если они были установлены из других источников:

sudo apt remove $(dpkg --get-selections docker.io docker-compose docker-compose-v2 docker-doc docker-buildx podman-docker containerd runc | cut -f1)

Добавление официального ключа и репозитория Docker:

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/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 > /dev/null <<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

Установка Docker Engine, CLI, containerd и плагинов Buildx и Compose:

sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Проверка службы и запуск тестового контейнера:

sudo systemctl status docker
sudo docker run hello-world

Для выполнения docker без sudo в обычной rootful-конфигурации пользователя можно добавить в группу docker. Членство в этой группе предоставляет привилегии, сопоставимые с root-доступом к хосту, поэтому такое изменение требует осознанного управления доступом.

sudo usermod -aG docker $USER
# затем требуется новый вход в сеанс пользователя

Для серверов с повышенными требованиями безопасности следует отдельно изучить rootless mode и модель прав Docker daemon.

Источники и дополнительная литература

Официальная документация Docker и спецификации OCI раскрывают понятия и команды, рассмотренные в лекции. Инструкция установки, параметры запуска и положения безопасности проверены по документации при подготовке этой редакции.

Примечание об актуальности

Установочные инструкции, поддерживаемые версии ОС и параметры Docker со временем обновляются. Для установки и обновления используется официальная документация соответствующей версии продукта. Основные термины лекции согласованы с моделью Docker Engine и OCI.

Документация для Windows