1. Основы контейнеризации и базовое управление жизненным циклом контейнеров
Основы контейнеризации и базовое управление жизненным циклом контейнеров
В 2013 году на конференции PyCon разработчик Соломон Хайкс представил инструмент, который навсегда изменил способ доставки программного обеспечения. Проблема «на моей машине всё работает» годами преследовала индустрию: различия в версиях библиотек, операционных систем и конфигураций серверов приводили к тому, что код, успешно прошедший тесты у программиста, «падал» при попытке запуска в продакшене. Docker предложил элегантное решение — упаковывать приложение вместе со всем его окружением в изолированный стандартный блок.
Почему контейнеры — это не виртуальные машины
Часто новички путают контейнеризацию с виртуализацией, однако разница между ними фундаментальна и кроется в способе взаимодействия с аппаратными ресурсами.
Традиционная виртуальная машина (ВМ) включает в себя полную копию операционной системы, приложение, необходимые библиотеки и драйверы. Гипервизор (например, VMware или VirtualBox) разделяет физические ресурсы сервера между несколькими ВМ. Каждая такая машина требует гигабайты дискового пространства и значительную часть оперативной памяти только для поддержания работы собственной гостевой ОС.
Контейнеры работают иначе. Они используют ядро хостовой операционной системы (Host OS) и изолируют процессы друг от друга на уровне операционной системы.
> Контейнеризация — это метод виртуализации на уровне ОС, позволяющий запускать несколько изолированных систем (контейнеров) на одном узле, используя единое общее ядро.
Представьте это как разницу между строительством отдельного частного дома для каждого жильца (виртуальная машина) и выделением отдельных квартир в одном многоквартирном доме (контейнеры). Жильцы квартир изолированы друг от друга, у каждого своя дверь, но фундамент, крыша и водопровод у них общие. Это делает контейнеры невероятно легкими: они запускаются за доли секунды и потребляют минимум ресурсов, так как им не нужно загружать целую ОС при каждом старте.
Архитектура Docker и первые шаги
Прежде чем переходить к практике, необходимо убедиться, что инструмент установлен корректно. Docker работает по клиент-серверной архитектуре. Когда вы вводите команду в терминале, вы используете Docker Client. Он отправляет запрос к Docker Daemon (службе dockerd), которая и выполняет всю тяжелую работу: сборку образов, запуск и остановку контейнеров.
Для проверки работоспособности системы используется команда:
docker version
Она выводит информацию о версии клиента и сервера. Если вы видите данные в обоих разделах, значит, демон запущен и готов к работе. Если же отображается только информация о клиенте с ошибкой доступа к сокету, вероятно, служба Docker не запущена или у вашего пользователя нет прав для взаимодействия с ней (в Linux это часто решается добавлением пользователя в группу docker или использованием sudo).
Первый запуск в мире Docker традиционно начинается с образа hello-world:
docker run hello-world
Что происходит в этот момент «под капотом»?
hello-world в локальном хранилище вашего компьютера.pull) образ из Docker Hub — публичного реестра образов.Образы и контейнеры: фундаментальное различие
Для глубокого понимания Docker крайне важно различать два понятия: Image (Образ) и Container (Контейнер).
Образ — это неизменяемый шаблон, «чертеж» или слепок файловой системы. Он содержит исполняемый код приложения, системные библиотеки, настройки и переменные окружения. Образы состоят из слоев, наложенных друг на друга. Вы не можете изменить запущенный образ — он доступен только для чтения.
Контейнер — это экземпляр образа, запущенный в изолированном окружении. Если образ — это рецепт пирога, то контейнер — это сам пирог. Вы можете испечь десять пирогов по одному рецепту. Точно так же вы можете запустить десять идентичных контейнеров на базе одного образа. Контейнер добавляет тонкий «записываемый слой» поверх неизменяемых слоев образа, что позволяет приложению сохранять временные файлы или изменять данные во время работы.
Для просмотра списка доступных на вашем компьютере образов используйте:
docker image ls
Эта команда покажет вам название репозитория, тег (версию), уникальный ID образа, дату создания и объем, который он занимает на диске.
Управление жизненным циклом: от запуска до удаления
Контейнер — это сущность временная. Его жизненный цикл состоит из нескольких стадий: создание, запуск, работа, остановка и удаление.
Просмотр активных процессов
Когда вы запустилиhello-world, он выполнил задачу и закрылся. Если вы введете:
docker ps
вы увидите пустую таблицу (или список только тех контейнеров, которые работают прямо сейчас). Чтобы увидеть вообще все контейнеры, когда-либо запущенные в системе и еще не удаленные, используйте флаг -a (all):
docker ps -aВ выводе этой команды обратите внимание на колонку STATUS. Там может быть написано Up (работает) или Exited (завершен).
Чтение логов
Часто приложения в контейнерах работают некорректно или мы просто хотим увидеть результат их деятельности после того, как они завершились. Для этого используется команда:docker logs <container_id_или_имя>Вам не обязательно вводить длинный ID контейнера целиком — Docker достаточно первых 3-4 уникальных символов. Логи — это стандартный вывод (stdout) и поток ошибок (stderr) процесса, запущенного внутри контейнера.
Остановка и принудительное завершение
Если контейнер «завис» или вы просто хотите прекратить его работу, есть два пути:docker stop — посылает процессу сигнал SIGTERM, давая ему время (обычно 10 секунд) на корректное завершение (сохранение данных, закрытие соединений).docker kill — посылает сигнал SIGKILL, мгновенно обрывая работу процесса. Это эквивалентно выдергиванию вилки из розетки. Используйте это только в крайних случаях.Интерактивный режим и терминал
Иногда нам нужно попасть «внутрь» контейнера, чтобы проверить состояние файлов или выполнить отладочные команды. Для этого при запуске используются флаги-i (interactive) и -t (tty). Обычно они объединяются в -it.Например, запуск контейнера с ОС Ubuntu и немедленный вход в его консоль:
docker run -it ubuntu bash
Теперь ваш терминал — это терминал внутри изолированной системы Ubuntu. Вы можете устанавливать пакеты, создавать файлы, но как только вы выйдете (exit), контейнер остановится. Если же контейнер уже запущен в фоновом режиме, и вы хотите подключиться к нему, используется команда exec:
docker exec -it <name> bash
Разница в том, что run создает новый контейнер, а exec выполняет команду в уже существующем.
Гигиена системы и очистка
Docker очень быстро «съедает» дисковое пространство. Каждый запущенный тест, каждый скачанный образ и каждый остановленный контейнер оставляют след. Остановленные контейнеры не удаляются автоматически — они продолжают хранить свой записываемый слой на диске, ожидая, что вы захотите их снова запустить.
Для удаления конкретного контейнера используется:
docker rm <container_id>
Для удаления образа:
docker rmi <image_id> (или docker image rm)
Однако вручную удалять десятки контейнеров неудобно. Для массовой очистки существует мощная команда prune. Например, чтобы удалить все остановленные контейнеры одним махом:
docker container prune
Будьте осторожны: эта команда не спрашивает подтверждения для каждого объекта, она просто стирает всё, что в данный момент не активно.
Типичные ошибки новичков
Одной из самых частых проблем является путаница с именами образов и тегами. По умолчанию Docker ищет тег latest. Если вы пытаетесь запустить my-app, а в системе есть только my-app:v1, Docker попытается скачать my-app:latest из интернета, не найдет его и выдаст ошибку manifest for my-app:latest not found. Всегда проверяйте соответствие имен и тегов через docker image ls.
Вторая ошибка — попытка запустить приложение, требующее взаимодействия с пользователем, без флагов -it. В таком случае контейнер может запуститься и тут же закрыться, так как процесс внутри решит, что терминала нет, и ему некуда выводить данные или не откуда их ждать.
Третий нюанс касается фонового режима. Разработчики часто запускают веб-серверы или базы данных. Если вы запустите их просто через docker run, ваш терминал будет заблокирован выводом логов этого сервера. Чтобы запустить контейнер «в фоне», используйте флаг -d (detached):
docker run -d nginx
Docker выведет полный ID запущенного контейнера и вернет вам управление консолью.
Контейнеризация — это не просто удобная обертка, это смена парадигмы. Мы перестаем думать о сервере как о «питомце», которого нужно лелеять и настраивать годами. Сервер и окружение становятся «скотом»: если что-то сломалось, мы просто удаляем контейнер и запускаем новый из того же образа. Это обеспечивает идентичность окружения на этапе разработки, тестирования и эксплуатации.