Технологии

Docker для начинающих: что это такое и как пользоваться

Статей про Docker много не бывает. В этом материале мы разберём базу: что такое Docker, как он работает и зачем нужен, а затем пошагово пройдём путь от установки до запуска первого контейнера. С подготовкой статьи помог: Андрей Хомутов Эксперт-разработчик в Ростелеком ИТ, дипломный руководитель в Нетологии (Python, JS), эксперт в ИТ–школе Ростелекома (DevOps) Для навигации: Что такое Docker простыми словами При разработке приложений часто возникает одна и та же проблема: у каждого разработчика своё окружение. Разные версии библиотек, интерпретаторов, системных зависимостей. В результате код, который стабильно работает на одном компьютере, может не запуститься на другом. Docker решает эту проблему — он создаёт единый и воспроизводимый способ запускать приложения. Основная идея: Docker — это платформа контейнеризации. Она позволяет упаковать приложение вместе со всеми зависимостями в изолированную среду — контейнер. Такой контейнер можно запустить где угодно: на локальной машине, сервере или в облаке, и результат всегда будет одинаковым. Чем отличается виртуализация от контейнеризации До появления Docker основным способом изоляции приложений были виртуальные машины. Каждая виртуальная машина имитировала полноценный компьютер: со своей ОС, драйверами и файловой системой. Для управления ими использовался гипервизор — программный слой, который распределяет ресурсы хоста между несколькими виртуальными машинами. Подход надёжный, но тяжёлый. Каждая ВМ занимала сотни мегабайт или гигабайты памяти, запускалась медленно и требовала отдельного обслуживания. Docker работает иначе. Он использует подход OS-level virtualization — контейнеризацию на уровне операционной системы. Вместо того чтобы поднимать отдельную ОС под каждое приложение, Docker создаёт изолированные контейнеры, которые делят ядро хостовой системы, но имеют собственное пространство процессов, файлов и сетей. Если упрощённо: виртуальная машина изолирует железо и поднимает целую операционную систему; контейнер изолирует процессы в рамках одной ОС. Как это выглядит на схеме: 5 причин, зачем нужен Docker 1. Стабильное окружение. Docker гарантирует, что приложение будет работать одинаково везде — на ноутбуке разработчика, тестовом сервере или в продакшене. Всё, что нужно для запуска, уже собрано в контейнер, поэтому код не зависит от различий в системах и настройках. 2. Лёгкость и скорость. Контейнеры используют общее ядро операционной системы и не создают отдельную копию ОС. За счёт этого они занимают меньше места и запускаются за секунды. Один сервер может без труда обслуживать десятки контейнеров. 3. Масштабирование. При росте нагрузки можно просто запустить дополнительные контейнеры — система быстро увеличит мощность и перераспределит ресурсы без изменения кода. 4. Изоляция процессов. Каждый контейнер работает независимо от других. Если в одном произойдёт сбой или утечка памяти, это не затронет другие контейнеры и систему в целом. 5. Удобная интеграция в CI/CD. Контейнеры уже стали стандартом в современных пайплайнах. Приложение можно собрать, протестировать и запустить в одинаковой среде — от локальной машины до продакшена. Благодаря этому меньше неожиданных багов, а релизы проходят быстрее и спокойнее. Архитектура Docker: как он устроен и как работает В основе Docker лежит Docker Engine — система, которая управляет контейнерами, образами, сетями и томами. Она состоит из трёх ключевых компонентов: CLI (Command Line Interface) — интерфейс командной строки. Docker Daemon (dockerd) — фоновый процесс, который выполняет все реальные действия: создаёт, запускает и удаляет контейнеры. REST API — интерфейс, который предоставляет Docker Daemon для управления. В локальной установке CLI общается с демоном напрямую через сокет, но API следует REST-архитектуре. Когда вы вводите команду вроде docker run , клиент CLI отправляет запрос в dockerd через сокет. Фоновый процесс получает эту команду, проверяет наличие нужного образа, готовит окружение, настраивает сеть, монтирует тома и запускает контейнер. Вся работа по созданию и управлению контейнерами происходит именно внутри демона (Docker Daemon) — он оркестрирует остальные части системы. Внутри dockerd используются вспомогательные среды: containerd отвечает за жизненный цикл контейнеров — создание, запуск, остановку и удаление runc делает сам запуск контейнера: изолирует процессы и использует механизмы ядра Linux которые отвечают за изоляцию и контроль ресурсов ( namespaces ,cgroups и другие). О них поговорим дальше. Обе следуют стандартам OCI (Open Container Initiative) — это набор правил, которые определяют формат контейнеров и способы их запуска. Благодаря этому Docker совместим с другими инструментами контейнеризации и предсказуемо работает в разных средах. При этом работающие контейнеры не зависят от dockerd : если демон перезапустить, они продолжат работу — за них отвечает containerd . Вся эта цепочка выглядит так: CLI → Docker Daemon (dockerd ) → containerd → runc → процессы контейнера. Docker Desktop Архитектура Docker отличается в зависимости от операционной системы. На Linux Docker Engine устанавливается напрямую и работает как системная служба (systemd ). Об этом писали выше. На Windows и macOS контейнеризация не встроена в ядро, поэтому Docker запускается через Docker Desktop. Это настольное приложение, которое устанавливает Docker Engine внутри лёгкой виртуальной машины (в Windows — через WSL 2, в macOS — через HyperKit или Apple Virtualization Framework) и предоставляет удобный интерфейс для управления контейнерами, образами и настройками. Docker Desktop объединяет всё в единую среду: внутри работает Linux с установленным Docker Engine; снаружи доступны привычный CLI и графический интерфейс; настройки сети, проброс портов, управление томами и обновления выполняются автоматически. Для новичков это самый удобный способ начать работу — установить Docker Desktop и сразу перейти к практике, без ручной настройки окружения. Как Docker работает с образами Контейнеры запускаются из образов (image) — шаблонов, в которых уже собраны все зависимости, библиотеки и настройки, нужные приложению. Образ состоит из слоёв, и каждый слой — это отдельный шаг сборки: установка пакета, копирование файлов, настройка окружения. Как устроены слои и почему это эффективно При сборке Docker складывает слои в определённом порядке и объединяет их в единую файловую систему с помощью драйвера overlay2. Он накладывает слои друг на друга так, что контейнер видит их как один диск, хотя физически это отдельные части. Главное преимущество такого подхода — повторное использование слоёв. Если два образа используют один и тот же базовый слой, Docker хранит его на диске только один раз. Например, слой ubuntu:20.04 — это минимальная версия Ubuntu, собранная специально для Docker. В нём нет лишних программ, только базовая файловая система Linux. Его используют сотни тысяч других образов, но на диске у разработчика этот слой лежит в единственном экземпляре, и Docker просто ссылается на него. Это экономит место и ускоряет работу: если слой уже есть, Docker не скачивает его повторно. Как работает кэширование слоёв при сборке образа Когда Docker собирает образ из Dockerfile, он проходит инструкции сверху вниз и создаёт слой для каждой из них. Если какая-то инструкция уже выполнялась раньше и её входные данные не изменились, Docker берёт слой из кэша — это быстрее, чем пересобирать его заново. Из-за этого порядок инструкций в Dockerfile критически важен: то, что меняется редко (установка системных пакетов, базовые настройки), лучше размещать выше; то, что меняется часто (исходный код приложения), — ниже. Например: FROM python:3.11-slim WORKDIR /app COPY requirements.txt . RUN pip install -r requirements.txt COPY . . Если изменился только код, Docker пересоберёт только последний слой, а установку зависимостей возьмёт из кэша. Как Docker использует слои при запуске контейнера Docker монтирует все слои образа в режиме «Только чтение» и добавляет поверх них записываемый слой. В нём появляются временные файлы, кэш, логи и любые изменения, которые происходят во время работы приложения. Когда контейнер удаляют, этот слой также исчезает, а образ остаётся неизменным — именно поэтому один и тот же образ можно запускать многократно и получать одинаковый результат. Чтобы данные не пропадали между перезапусками, Docker хранит их вне контейнера, но с доступом к ним изнутри. Делается это двумя способами: С помощью томов (volumes) — Docker создаёт отдельные области на диске и управляет ими. Контейнер может читать данные из тома и записывать их в него, а при удалении контейнера том остаётся. С помощью монтирований (bind mounts) — к контейнеру подключается папка на хостовой системе. Например, можно смонтировать локальный каталог с кодом, чтобы контейнер работал с ним напрямую. Хранилища образов: Docker Hub и Registry Docker хранит образы в реестрах (registries) — это серверы, которые принимают, хранят и отдают образы по запросу. Работают они по простому принципу: при сборке образа команда docker build сохраняет его локально, а при публикации (docker push ) отправляет копию в выбранный реестр (как если бы вы выкладывали проект в GitHub). Позже этот же образ можно скачать (docker pull) на другой машине и запустить как контейнер. Самый известный и используемый реестр — Docker Hub. В нём размещаются миллионы готовых образов: как официальные (от Docker и разработчиков языков или фреймворков), так и пользовательские. Например, образы nginx, Redis, Python, PostgreSQL — все они загружаются именно оттуда. Hub также поддерживает приватные репозитории, если образ должен оставаться внутри команды. Для корпоративных сценариев Docker предлагает установить собственный Docker Registry. Он разворачивается локально или в облаке, работает по тому же API, что и Hub, и поддерживает аутентификацию, разграничение прав и контроль версий образов. Это полезно, когда образы содержат закрытый код или конфигурации, которые нельзя выкладывать в публичный доступ. Жизненный цикл Docker-образа: Каждый образ в реестре состоит из манифеста и набора слоёв. Манифест — это файл-описание, в котором указано, какие слои входят в образ и как их собрать. Сами слои хранятся отдельно — как архивы, каждый со своим уникальным идентификатором (sha256 ). При загрузке или скачивании Docker проверяет, не были ли повреждены файлы образа. Каждый слой имеет свою контрольную сумму (sha256 ), и система сверяет их перед установкой. Если хотя бы один байт отличается от ожидаемого, хэш не совпадает — и такой образ не принимается. Так Docker гарантирует, что загруженные данные точно совпадают с оригиналом. У каждого образа есть тег — вроде latest , v1.0 или dev . Тег — это просто метка, которая указывает на конкретную версию образа. Но за этой меткой всегда стоит digest — уникальный хэш (sha256 ), по которому Docker определяет точный набор слоёв. Даже если тег изменится, digest остаётся прежним — и Docker понимает, какой именно образ нужно использовать. Сеть контейнеров При запуске Docker автоматически подключает контейнер к внутренней виртуальной сети. По умолчанию используется bridge-сеть — изолированная среда, где каждый контейнер получает свой IP-адрес и может обмениваться данными с другими участниками этой сети. С точки зрения контейнера это выглядит как отдельная машина с полноценным сетевым интерфейсом, маршрутизацией и DNS. Bridge-сеть создаётся на стороне хоста: Docker поднимает виртуальный интерфейс, назначает подсеть и настраивает NAT, чтобы контейнеры могли выходить в интернет. Как контейнеры находят друг друга внутри сети В пользовательских bridge-сетях Docker поднимает встроенный DNS-сервер. Благодаря этому контейнеры могут обращаться друг к другу по имени, а не по IP-адресу. Например, если в одной сети запущены два контейнера — web и db , — то приложение внутри web может подключиться к базе по адресу db:5432 . Docker сам сопоставит имя контейнера с его текущим IP-адресом, так что вручную настраивать адреса не нужно. Доступ к контейнеру снаружи Если приложению нужно принимать запросы извне, при запуске указывают флаг -p , чтобы пробросить порт хоста внутрь контейнера (например, -p 8080:80 делает порт 80 контейнера доступным по адресу 8080 на хосте). Кроме стандартной сети есть и другие режимы: host — контейнер работает в сетевом пространстве хоста и использует его IP-адрес и интерфейсы. Режим без изоляции, зато с максимальной производительностью. Подходит, если сервису нужен прямой доступ к сети. none — сеть полностью отключена. Контейнер не получает IP, не выходит в интернет и не принимает входящие запросы. Подходит для задач, которые работают изолированно и не используют сеть. overlay — объединяет контейнеры, запущенные на разных машинах, в одну виртуальную сеть. Такой тип используется, когда приложение развёрнуто на нескольких серверах и между ними нужно наладить связь. macvlan — каждому контейнеру назначается собственный MAC-адрес, и в локальной сети он виден как отдельное устройство. Это удобно для тестирования сетевых сервисов или если контейнер должен работать наравне с другими машинами. Сетью управляет Docker Daemon: он создаёт интерфейсы, подключает контейнеры и автоматически настраивает сетевые правила.Благодаря этому контейнеры остаются изолированными друг от друга, но при этом могут безопасно взаимодействовать через чётко заданные правила. Логи и события Все процессы внутри контейнера работают так же, как в обычной системе Linux. Всё, что они выводят в стандартные потоки (stdout и stderr ), Docker перенаправляет в драйвер логирования — систему, которая отвечает за сбор и хранение логов. По умолчанию используется драйвер json-file: логи записываются на хосте в файл в формате JSON. Это удобно для локальной отладки и просмотра через команду docker logs . В продакшене часто выбирают другие драйверы: journald — чтобы писать логи в системный журнал Linux; syslog — для отправки логов на внешний сервер; fluentd — для сбора и анализа данных в распределённых системах. Для каждого контейнера можно задать свои параметры: выбрать драйвер, ограничить размер файлов, включить ротацию (автоматическую замену старых логов новыми). Помимо логов Docker фиксирует события — всё, что происходит в системе: запуск или остановка контейнера, создание или удаление, загрузка образа, подключение тома. Эти данные доступны через API или команду docker events . На практике события используют для мониторинга и интеграций: например, CI/CD-система может автоматически запускать тесты при создании контейнера или отправлять уведомления о сбоях. Благодаря этой системе Docker остаётся прозрачным: всегда можно узнать, что происходит с каждым контейнером и когда именно, не заходя внутрь вручную. Безопасность Docker использует несколько уровней защиты, чтобы контейнеры оставались изолированными и не мешали друг другу. Основу этой модели составляют механизмы ядра Linux — namespaces и cgroups. Namespaces Отвечают за изоляцию. Они создают для каждого контейнера отдельное пространство процессов, пользователей, сети и файловой системы. Контейнер видит только свои процессы и каталоги и не может напрямую взаимодействовать с хостом. Например, процесс с PID 1 внутри контейнера не имеет ничего общего с системным PID 1 на хосте. То же и с сетью: у контейнера свой IP и таблицы маршрутов, и он не видит соседей, пока их явно не объединят в одну сеть. Cgroups (control groups) Отвечают за контроль ресурсов. Они задают, сколько CPU, оперативной памяти и дисковых операций контейнер может использовать. Если приложение начнёт потреблять слишком много, cgroups ограничат его, не давая перегрузить систему или повлиять на другие контейнеры. Помимо этого, Docker использует дополнительные механизмы безопасности: Capabilities — система тонкой настройки прав. Она ограничивает возможности root-пользователя внутри контейнера. Например, процесс может записывать файлы, но не может менять сетевые настройки. AppArmor и SELinux — инструменты контроля доступа. Они определяют, какие файлы и операции разрешены процессам контейнера. seccomp — фильтр системных вызовов, который блокирует потенциально опасные обращения к ядру, например попытки загрузить модули или изменить сетевые интерфейсы. Все эти уровни работают вместе и создают прочную изоляцию. Даже если приложение внутри контейнера окажется уязвимым, оно не сможет повредить хост или получить доступ к другим контейнерам. Для дополнительной защиты Docker можно запустить в rootless-режиме — тогда контейнеры работают не от имени администратора, а под обычным пользователем. Функциональности чуть меньше, зато риск для хоста минимален. На чём написан Docker Docker написан на Go — простом и быстром языке, удобном для создания системных инструментов. На нём легко работать с потоками и собирать программы, которые запускаются без внешних библиотек. На Go построены все основные части Docker: dockerd — демон, который принимает команды и управляет контейнерами; containerd — служба, отвечающая за запуск и работу контейнеров; runc — утилита, которая создаёт изолированные процессы в Linux; BuildKit — инструмент для сборки образов. Docker использует стандарты OCI (Open Container Initiative). Они описывают, из чего состоит контейнер и как его запускать. Поэтому образы, собранные в Docker, можно использовать и в других системах — например, в Podman или CRI-O. Исходный код Docker открыт и распространяется по лицензии Apache 2.0. Она разрешает использовать код в любых целях — в личных, учебных или коммерческих проектах. Можно изменять исходники, собирать собственные версии Docker и включать его части в другие продукты. Единственное требование — сохранять уведомление об авторских правах, текст лицензии и указывать, если вносились изменения. Имя и логотип Docker использовать без разрешения нельзя. Основные понятия Docker: краткий справочник Мы уже разобрались, как устроен Docker и из чего он состоит. Теперь соберём ключевые термины в одном месте, чтобы было проще ориентироваться, когда перейдём к практике. Образ (Image) Это шаблон, из которого запускаются контейнеры. В нём уже есть всё, что нужно приложению: системные библиотеки, зависимости, код и настройки. Образ не меняется — Docker использует его как основу и добавляет поверх слой, куда попадают изменения, сделанные во время работы. Так один и тот же образ можно использовать многократно, не затрагивая исходное содержимое. Контейнер (Container) Это изолированная среда, в которой работает приложение. Контейнер можно запускать, останавливать и удалять, не затрагивая исходный образ. Когда он удаляется, его данные исчезают — поэтому для постоянного хранения используется следующий механизм. Том (Volume) Это место для данных, которые должны сохраняться между перезапусками. Тома подключаются к контейнерам как внешние диски: всё, что записано в них, остаётся даже после удаления контейнера. Так обычно хранят базы данных, логи и другие важные файлы. Сеть (Network) Отвечает за взаимодействие контейнеров между собой и с внешним миром. Docker автоматически создаёт bridge-сеть, где каждый контейнер получает свой IP-адрес. Можно объединять контейнеры в собственные сети или, наоборот, изолировать их, если требуется полная автономность. Реестр (Registry) Реестр — это место, где хранятся Docker-образы. Публичный вариант — Docker Hub, в нём размещены миллионы готовых сборок, включая официальные (nginx, Redis, Python). Если образы должны оставаться внутри компании, разворачивают собственный Docker Registry — тот же сервер хранения, но с ограниченным доступом. Практика: установка и первые команды Чтобы начать работать с Docker, нужно установить Docker Engine. В него входят фоновый процесс dockerd , интерфейс командной строки и набор инструментов для работы с образами и сетями. На macOS и Windows установка выполняется через приложение Docker Desktop. Скачайте его с официального сайта. На Linux Docker устанавливается из официальных репозиториев пакетов. Для Debian и Ubuntu команда выглядит так: sudo apt update sudo apt install docker-ce docker-ce-cli containerd.io Подробные инструкции для других дистрибутивов есть в документации Docker. Проверка установки После установки убедитесь, что Docker работает корректно. Для этого выполните команду: docker version Docker выведет информацию о клиенте и сервере. Пример вывода может выглядеть так: Client: Version: 28.4.0 API version: 1.51 Go version: go1.25.1 Git commit: d8eb465f86 OS/Arch: linux/amd64 Server: Engine: Version: 28.4.0 API version: 1.51 (minimum version 1.24) Go version: go1.25.1 containerd: Version: v2.1.4 runc: Version: 1.3.1 Главное, чтобы в выводе присутствовали обе части: Client и Server, что означает, что dockerd запущен и Docker Engine работает. Первый тест Для проверки можно запустить тестовый контейнер, который выводит приветственное сообщение. Используйте команду: docker run hello-world Docker загрузит с Hub тестовый образ и запустит контейнер, который выведет сообщение Hello from Docker! — это значит, что система установлена правильно и демон отвечает на запросы. Запуск первого контейнера Когда Docker установлен, можно сразу попробовать запустить приложение. Например, веб-сервер Nginx — лёгкий, стабильный и идеально подходит для первого теста. Выполните команду: docker run -d -p 8080:80 nginx Что здесь происходит: docker run — создаёт контейнер из указанного образа (в данном случаеnginx );если образа нет локально, Docker автоматически скачает его с Docker Hub; флаг -d запускает контейнер в фоновом режиме (detached);-p 8080:80 пробрасывает порт 80 внутри контейнера на порт 8080 вашей машины. После запуска Docker создаст контейнер и выведет его идентификатор. Теперь можно открыть http://localhost:8080 и увидеть стандартную стартовую страницу Nginx. Чтобы убедиться, что контейнер работает, выполните: docker ps В списке будет строка с именем nginx и статусом Up , который означает, что сервер запущен. Интерактивный запуск контейнера Иногда нужно не просто запустить контейнер, а зайти внутрь него ― посмотреть файлы, проверить окружение, выполнить команды. Для этого используют флаг -it . Например: docker run -it ubuntu bash Что делает эта команда: -i — оставляет стандартный ввод открытым,-t — выделяет псевдотерминал,ubuntu — образ, который нужно запустить,bash — команда, которая будет выполнена внутри контейнера. После запуска вы попадёте в оболочку контейнера и сможете выполнять обычные Linux-команды. Чтобы выйти, используйте: exit Важно: если нужно зайти в уже работающий контейнер, используется другая команда: docker exec -it bash Как следить за контейнерами Когда контейнер запущен, Docker продолжает отслеживать его состояние. В любой момент можно посмотреть, что происходит, не прерывая работу приложения. Для этого используем уже знакомую команду: docker ps Она покажет список активных контейнеров: их идентификаторы, образы, статус и открытые порты. Если добавить флаг -a , отобразятся и завершённые контейнеры — это помогает найти старые тестовые сборки или понять, почему что-то остановилось. Чтобы узнать подробнее, как запущен контейнер и какие у него настройки, выполните: docker inspect Она выводит полное описание: от сетевых параметров до переменных окружения и точной команды запуска. Если нужно быстро понять, что происходит внутри контейнера, не заходя в него вручную (например, просмотреть вывод приложения), используйте команду: docker logs Но если всё-таки нужно заглянуть внутрь, например, проверить файлы или конфигурацию, — можно открыть интерактивную консоль: docker exec -it /bin/bash Если в образе нет Bash (например, в Alpine), вместо него используют: docker exec -it /bin/sh Так вы попадёте в среду контейнера, где доступны обычные Linux-команды. Управление контейнерами Контейнеры можно запускать, останавливать и удалять — так же просто, как обычные процессы в системе. Если контейнер нужно приостановить, используйте: docker stop Docker отправит сигнал завершения процессу внутри контейнера и аккуратно его остановит. Контейнер останется в списке и при желании его можно снова запустить командой: docker start Когда контейнер больше не нужен, его можно удалить: docker rm Важно: если попытаться удалить запущенный контейнер, Docker выдаст ошибку, чтобы не потерять данные. Для принудительного удаления (остановка и удаление одной командой) используйте флаг -f : docker rm -f Помимо контейнеров, система хранит образы, из которых они создаются. Посмотреть список локальных образов можно так: docker images А удалить ненужные с помощью команды: docker rmi Чтобы быстро очистить всё, что не используется (остановленные контейнеры, старые образы, неактивные сети), есть команда: docker system prune Она освободит место на диске и оставит только то, что нужно для работы. Создание своего образа: работа с Dockerfile Готовые образы покрывают большинство задач. Но в реальных проектах почти всегда нужно что-то своё: добавить зависимости, конфигурации или сам код приложения. Для этого в Docker используется Dockerfile — текстовый файл, в котором по шагам описано, как собрать образ. Пример простого Dockerfile: FROM python:3.11-slim WORKDIR /app COPY . . RUN pip install -r requirements.txt CMD ["python", "app.py"] Что здесь происходит: FROM — задаёт базовый образ, от которого наследуется ваш;WORKDIR — создаёт рабочую директорию внутри контейнера;COPY — копирует файлы проекта с компьютера в образ;RUN — выполняет команды при сборке (например, установка библиотек);CMD — указывает, что делать при запуске контейнера. Важно: когда контейнер запускается, процессы внутри него по умолчанию работают с правами root. Для обучения или экспериментов этого вполне достаточно. Но в продакшене такое поведение создаёт лишние риски: если приложение внутри контейнера уязвимо, злоумышленник получает те же привилегии, что и root-процесс. Чтобы снизить эти риски, в Dockerfile часто добавляют собственного пользователя и запускают приложение уже от его имени. Сделать это можно буквально в пару строк: RUN useradd -m appuser USER appuser ENTRYPOINT: второй способ задать команду запуска В Dockerfile есть две инструкции, которые определяют, что выполняется при старте контейнера — CMD и ENTRYPOINT. Чем отличаются: CMD — это команда по умолчанию. Если при запуске контейнера ( docker run ) вы передаёте свои аргументы, Docker заменяет CMD на то, что вы указали.ENTRYPOINT — это фиксированная основа команды. Она всегда выполняется, а аргументы из docker run просто добавляются к ней. Пример: ENTRYPOINT ["python", "app.py"] CMD ["--port", "8000"] ENTRYPOINT задаёт программу, которую контейнер запускает всегда — в нашем случае это python app.py . CMD добавляет аргументы по умолчанию. То есть Docker склеивает их и при обычном запуске выполнит: python app.py --port 8000 Если при запуске указать свои параметры: docker run myapp --port 9000 Docker возьмёт ENTRYPOINT и добавит ваши аргументы, заменив CMD: python app.py --port 9000 ENTRYPOINT используют, когда контейнер всегда должен запускать одно и то же приложение — веб-сервер, скрипт, обработчик. Пользователь может менять только параметры. CMD используют как набор аргументов по умолчанию. Если при запуске передать свои параметры, CMD полностью заменится. Разобрались с основами, а теперь перейдём к практике. Практический пример Разберём, как создать и запустить свой первый контейнер. Сначала в папке проекта должны лежать три файла: myapp/ ├─ app.py ├─ requirements.txt └─ Dockerfile В app.py напишем простейшее приложение на Python. Оно будет показывать строку "Hello from Docker!", когда вы откроете страницу в браузере: from http.server import HTTPServer, BaseHTTPRequestHandler class Handler(BaseHTTPRequestHandler): def do_GET(self): self.send_response(200) self.end_headers() self.wfile.write(b"Hello from Docker!") if __name__ == "__main__": HTTPServer(("0.0.0.0", 8000), Handler).serve_forever() Файл requirements.txt нужен, чтобы перечислить зависимости проекта. Если их нет — можно оставить его пустым. Собираем образ Теперь откройте терминал, перейдите в папку myapp и выполните: docker build -t myapp . Флаг -t задаёт имя образа, а точка в конце указывает путь к контексту сборки — папке, где лежит Dockerfile и файлы проекта. После выполнения команды Docker по шагам прочитает Dockerfile и соберёт новый образ. Запускаем контейнер Мы уже пробовали запускать контейнер с Nginx. Теперь сделаем то же самое, но с собственным образом: docker run -d -p 8000:8000 myapp Docker создаст контейнер и запустит внутри него ваш app.py . Откройте http://localhost:8000, и вы увидите сообщение: "Hello from Docker!". Вы только что собрали собственный образ, запустили контейнер и проверили, что приложение работает. В реальных проектах таких образов может быть несколько — для тестов, продакшена или разных версий кода. Чтобы их различать, Docker использует теги — о них поговорим дальше. Зачем нужны теги Тег — это просто метка версии. Если его не указать, Docker присвоит latest , но лучше явно обозначать версии: docker build -t myapp:1.0 . Так проще поддерживать несколько вариантов образа — например, стабильный (1.0 ) и тестовый (dev ). Передача и хранение образов После сборки Docker сохраняет образ локально — он доступен только на вашем компьютере. Если нужно поделиться им с коллегами или перенести на другой компьютер, проще всего воспользоваться Docker Hub. 1. Создайте репозиторий на Docker Hub Зайдите в свой аккаунт на https://hub.docker.com и вручную создайте новый репозиторий — так же, как создают новый проект на GitHub. Название репозитория должно совпадать с тем, что вы будете использовать в команде docker push . Это важный шаг: Docker не создаёт репозитории автоматически. 2. Переименуйте образ Перед загрузкой образ нужно оформить в правильном формате: username/repository:tag где: username — ваш логин на Docker Hub,repository — имя проекта,tag — версия образа (например,1.0 ). Пример: docker tag myapp:1.0 username/myapp:1.0 3. Войдите в Docker Hub Авторизуйтесь через команду: docker login Docker попросит ввести логин и пароль от вашего аккаунта. После успешного входа появится сообщение вроде Login Succeeded . 4. Отправьте образ в репозиторий Выполните команду: docker push username/myapp:1.0 Docker начнёт загружать образ в ваш репозиторий на Docker Hub. Когда загрузка закончится, образ появится в вашем профиле и станет доступен другим (если репозиторий публичный). 5. Загрузите образ на другом компьютере Чтобы использовать тот же образ на другой машине, выполните: docker pull username/myapp:1.0 Docker скачает только нужные слои — если часть уже есть локально, она не будет загружаться заново. После этого образ можно запустить как обычно: docker run -d -p 8000:8000 username/myapp:1.0 Docker Compose: что это и зачем нужно Когда проект растёт, одного контейнера уже не хватает. Помимо основного приложения появляются база данных, кэш, очередь сообщений. Все они работают в отдельных контейнерах, и запускать их вручную неудобно. Docker Compose позволяет описать все нужные контейнеры и их настройки в одном файле — docker-compose.yml . После этого весь проект можно запустить одной командой. Пример простого docker-compose.yml : services: web: build: . ports: - "8000:8000" redis: image: redis:alpine Что здесь происходит: services — список контейнеров, которые нужно запустить;web — наш основной сервис, собирается из текущей директории (build: . ) и открывает порт 8000;redis — дополнительный контейнер, разворачивается из готового образаredis:alpine . Как это работает Сохраните файл и выполните команду: docker compose up Docker соберёт образы, создаст контейнеры, подключит сеть и запустит всё вместе. Чтобы остановить проект, выполните команду: docker compose down Что изучать дальше Следующие шаги зависят от того, что вы хотите делать дальше: Для разработки — попробуйте написать собственный Dockerfile для своего проекта и оптимизировать его размер. Изучите многоэтапную сборку (multi-stage build) и работу с кэшем.Для деплоя — посмотрите, как запускать контейнеры на сервере: настройка автозапуска через systemd , передача переменных окружения, управление логами.Для продакшена — изучите оркестраторы: Docker Swarm или Kubernetes. Они позволяют управлять десятками контейнеров и масштабировать сервисы. Для безопасности — разберитесь с rootless-режимом, настройкой прав доступа и сканированием образов на уязвимости (например, с помощью docker scan ).Для автоматизации — посмотрите, как Docker используется в CI/CD-сценариях: тестирование, сборка и публикация образов через GitHub Actions или GitLab CI. Ну, вот и всё. Теперь у вас уже есть рабочая база Docker: вы понимаете, как устроены образы и контейнеры, умеете собирать собственные образы и запускать сервисы через Compose. Этого достаточно, чтобы уверенно продолжать и постепенно подключать более сложные вещи. Чтобы расти, нужно выйти из привычной зоны и сделать шаг к переменам. Можно изучить новое, начав с бесплатных занятий: записи вебинара «Секретный рецепт DevSecOps, или почему его используют 90% компаний» совместно с НИУ ВШЭ; мастер-класса «Искусственный интеллект в разработке»; вводного курса магистратуры МФТИ «Разработка IT-продукта». Или можно стать востребованным сотрудником и открыть открыть бóльшие перспективы в карьере с профессиональным обучением: на программе «Системный администратор»; на курсе «DevOps-инженер» для действующих специалистов; на расширенном курсе «Python-разработчик» с изучением ИИ.

Фильтры и сортировка