vaspvort
Ночной дозор
Команда форума
Модератор
ПРОВЕРЕННЫЙ ПРОДАВЕЦ
Private Club
Старожил
Migalki Club
Меценат💎
Статей про Docker много не бывает.
В этом материале мы разберём базу: что такое Docker, как он работает и зачем нужен, а затем пошагово пройдём путь от установки до запуска первого контейнера.
Docker решает эту проблему — он создаёт единый и воспроизводимый способ запускать приложения.
Основная идея: Docker — это платформа контейнеризации. Она позволяет упаковать приложение вместе со всеми зависимостями в изолированную среду — контейнер.
Такой контейнер можно запустить где угодно: на локальной машине, сервере или в облаке, и результат всегда будет одинаковым.
Каждая виртуальная машина имитировала полноценный компьютер: со своей ОС, драйверами и файловой системой. Для управления ими использовался гипервизор — программный слой, который распределяет ресурсы хоста между несколькими виртуальными машинами.
Подход надёжный, но тяжёлый. Каждая ВМ занимала сотни мегабайт или гигабайты памяти, запускалась медленно и требовала отдельного обслуживания.
Docker работает иначе. Он использует подход OS-level virtualization — контейнеризацию на уровне операционной системы. Вместо того чтобы поднимать отдельную ОС под каждое приложение, Docker создаёт изолированные контейнеры, которые делят ядро хостовой системы, но имеют собственное пространство процессов, файлов и сетей.
Если упрощённо:
Источник
2. Лёгкость и скорость. Контейнеры используют общее ядро операционной системы и не создают отдельную копию ОС. За счёт этого они занимают меньше места и запускаются за секунды. Один сервер может без труда обслуживать десятки контейнеров.
3. Масштабирование. При росте нагрузки можно просто запустить дополнительные контейнеры — система быстро увеличит мощность и перераспределит ресурсы без изменения кода.
4. Изоляция процессов. Каждый контейнер работает независимо от других. Если в одном произойдёт сбой или утечка памяти, это не затронет другие контейнеры и систему в целом.
5. Удобная интеграция в CI/CD. Контейнеры уже стали стандартом в современных пайплайнах. Приложение можно собрать, протестировать и запустить в одинаковой среде — от локальной машины до продакшена. Благодаря этому меньше неожиданных багов, а релизы проходят быстрее и спокойнее.
Внутри dockerd используются вспомогательные среды:
При этом работающие контейнеры не зависят от dockerd: если демон перезапустить, они продолжат работу — за них отвечает containerd.
Вся эта цепочка выглядит так: CLI → Docker Daemon (dockerd) → containerd → runc → процессы контейнера.
На Linux Docker Engine устанавливается напрямую и работает как системная служба (systemd). Об этом писали выше.
На Windows и macOS контейнеризация не встроена в ядро, поэтому Docker запускается через Docker Desktop.
Это настольное приложение, которое устанавливает Docker Engine внутри лёгкой виртуальной машины (в Windows — через WSL 2, в macOS — через HyperKit или Apple Virtualization Framework) и предоставляет удобный интерфейс для управления контейнерами, образами и настройками.
Docker Desktop объединяет всё в единую среду:
Образ состоит из слоёв, и каждый слой — это отдельный шаг сборки: установка пакета, копирование файлов, настройка окружения.
Главное преимущество такого подхода — повторное использование слоёв. Если два образа используют один и тот же базовый слой, Docker хранит его на диске только один раз.
Например, слой ubuntu:20.04 — это минимальная версия Ubuntu, собранная специально для Docker. В нём нет лишних программ, только базовая файловая система Linux. Его используют сотни тысяч других образов, но на диске у разработчика этот слой лежит в единственном экземпляре, и Docker просто ссылается на него.
Это экономит место и ускоряет работу: если слой уже есть, Docker не скачивает его повторно.
Источник
Если какая-то инструкция уже выполнялась раньше и её входные данные не изменились, Docker берёт слой из кэша — это быстрее, чем пересобирать его заново.
Из-за этого порядок инструкций в Dockerfile критически важен:
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
Если изменился только код, Docker пересоберёт только последний слой, а установку зависимостей возьмёт из кэша.
Когда контейнер удаляют, этот слой также исчезает, а образ остаётся неизменным — именно поэтому один и тот же образ можно запускать многократно и получать одинаковый результат.
Чтобы данные не пропадали между перезапусками, Docker хранит их вне контейнера, но с доступом к ним изнутри. Делается это двумя способами:
Работают они по простому принципу: при сборке образа команда docker build сохраняет его локально, а при публикации (docker push) отправляет копию в выбранный реестр (как если бы вы выкладывали проект в GitHub). Позже этот же образ можно скачать (docker pull) на другой машине и запустить как контейнер.
Самый известный и используемый реестр — Docker Hub. В нём размещаются миллионы готовых образов: как официальные (от Docker и разработчиков языков или фреймворков), так и пользовательские. Например, образы nginx, Redis, Python, PostgreSQL — все они загружаются именно оттуда.
Hub также поддерживает приватные репозитории, если образ должен оставаться внутри команды.
Для корпоративных сценариев Docker предлагает установить собственный Docker Registry. Он разворачивается локально или в облаке, работает по тому же API, что и Hub, и поддерживает аутентификацию, разграничение прав и контроль версий образов. Это полезно, когда образы содержат закрытый код или конфигурации, которые нельзя выкладывать в публичный доступ.
Жизненный цикл Docker-образа:
Схема показывает, как образ собирается из Dockerfile, сохраняется локально, загружается в реестр (push), скачивается обратно (pull) и запускается как контейнер. Источник
Каждый образ в реестре состоит из манифеста и набора слоёв.
Манифест — это файл-описание, в котором указано, какие слои входят в образ и как их собрать. Сами слои хранятся отдельно — как архивы, каждый со своим уникальным идентификатором (sha256).
При загрузке или скачивании Docker проверяет, не были ли повреждены файлы образа.
Каждый слой имеет свою контрольную сумму (sha256), и система сверяет их перед установкой. Если хотя бы один байт отличается от ожидаемого, хэш не совпадает — и такой образ не принимается. Так Docker гарантирует, что загруженные данные точно совпадают с оригиналом.
У каждого образа есть тег — вроде latest, v1.0 или dev. Тег — это просто метка, которая указывает на конкретную версию образа. Но за этой меткой всегда стоит digest — уникальный хэш (sha256), по которому Docker определяет точный набор слоёв.
Даже если тег изменится, digest остаётся прежним — и Docker понимает, какой именно образ нужно использовать.
С точки зрения контейнера это выглядит как отдельная машина с полноценным сетевым интерфейсом, маршрутизацией и DNS.
Bridge-сеть создаётся на стороне хоста: Docker поднимает виртуальный интерфейс, назначает подсеть и настраивает NAT, чтобы контейнеры могли выходить в интернет.
Например, если в одной сети запущены два контейнера — web и db, — то приложение внутри web может подключиться к базе по адресу db:5432. Docker сам сопоставит имя контейнера с его текущим IP-адресом, так что вручную настраивать адреса не нужно.
Кроме стандартной сети есть и другие режимы:
По умолчанию используется драйвер json-file: логи записываются на хосте в файл в формате JSON. Это удобно для локальной отладки и просмотра через команду docker logs.
В продакшене часто выбирают другие драйверы:
Помимо логов Docker фиксирует события — всё, что происходит в системе: запуск или остановка контейнера, создание или удаление, загрузка образа, подключение тома. Эти данные доступны через API или команду docker events.
На практике события используют для мониторинга и интеграций: например, CI/CD-система может автоматически запускать тесты при создании контейнера или отправлять уведомления о сбоях.
Благодаря этой системе Docker остаётся прозрачным: всегда можно узнать, что происходит с каждым контейнером и когда именно, не заходя внутрь вручную.
Например, процесс с PID 1 внутри контейнера не имеет ничего общего с системным PID 1 на хосте.
То же и с сетью: у контейнера свой IP и таблицы маршрутов, и он не видит соседей, пока их явно не объединят в одну сеть.
Если приложение начнёт потреблять слишком много, cgroups ограничат его, не давая перегрузить систему или повлиять на другие контейнеры.
Помимо этого, Docker использует дополнительные механизмы безопасности:
Для дополнительной защиты Docker можно запустить в rootless-режиме — тогда контейнеры работают не от имени администратора, а под обычным пользователем. Функциональности чуть меньше, зато риск для хоста минимален.
На Go построены все основные части Docker:
Исходный код Docker открыт и распространяется по лицензии Apache 2.0. Она разрешает использовать код в любых целях — в личных, учебных или коммерческих проектах. Можно изменять исходники, собирать собственные версии Docker и включать его части в другие продукты. Единственное требование — сохранять уведомление об авторских правах, текст лицензии и указывать, если вносились изменения.
Имя и логотип Docker использовать без разрешения нельзя.
Теперь соберём ключевые термины в одном месте, чтобы было проще ориентироваться, когда перейдём к практике.
Образ не меняется — Docker использует его как основу и добавляет поверх слой, куда попадают изменения, сделанные во время работы. Так один и тот же образ можно использовать многократно, не затрагивая исходное содержимое.
Когда он удаляется, его данные исчезают — поэтому для постоянного хранения используется следующий механизм.
Так обычно хранят базы данных, логи и другие важные файлы.
Можно объединять контейнеры в собственные сети или, наоборот, изолировать их, если требуется полная автономность.
Публичный вариант — Docker Hub, в нём размещены миллионы готовых сборок, включая официальные (nginx, Redis, Python). Если образы должны оставаться внутри компании, разворачивают собственный Docker Registry — тот же сервер хранения, но с ограниченным доступом.
На 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 run -d -p 8080:80 nginx
Что здесь происходит:
Чтобы убедиться, что контейнер работает, выполните:
docker ps
В списке будет строка с именем nginx и статусом Up, который означает, что сервер запущен.
Интерактивный запуск контейнера
Иногда нужно не просто запустить контейнер, а зайти внутрь него ― посмотреть файлы, проверить окружение, выполнить команды. Для этого используют флаг -it.
Например:
docker run -it ubuntu bash
Что делает эта команда:
Чтобы выйти, используйте:
exit
Важно: если нужно зайти в уже работающий контейнер, используется другая команда:
docker exec -it <id> bash
Для этого используем уже знакомую команду:
docker ps
Она покажет список активных контейнеров: их идентификаторы, образы, статус и открытые порты. Если добавить флаг -a, отобразятся и завершённые контейнеры — это помогает найти старые тестовые сборки или понять, почему что-то остановилось.
Чтобы узнать подробнее, как запущен контейнер и какие у него настройки, выполните:
docker inspect <id>
Она выводит полное описание: от сетевых параметров до переменных окружения и точной команды запуска.
Если нужно быстро понять, что происходит внутри контейнера, не заходя в него вручную (например, просмотреть вывод приложения), используйте команду:
docker logs <id>
Но если всё-таки нужно заглянуть внутрь, например, проверить файлы или конфигурацию, — можно открыть интерактивную консоль:
docker exec -it <id> /bin/bash
Если в образе нет Bash (например, в Alpine), вместо него используют:
docker exec -it <id> /bin/sh
Так вы попадёте в среду контейнера, где доступны обычные Linux-команды.
Если контейнер нужно приостановить, используйте:
docker stop <id>
Docker отправит сигнал завершения процессу внутри контейнера и аккуратно его остановит.
Контейнер останется в списке и при желании его можно снова запустить командой:
docker start <id>
Когда контейнер больше не нужен, его можно удалить:
docker rm <id>
Важно: если попытаться удалить запущенный контейнер, Docker выдаст ошибку, чтобы не потерять данные.
Для принудительного удаления (остановка и удаление одной командой) используйте флаг -f:
docker rm -f <id>
Помимо контейнеров, система хранит образы, из которых они создаются. Посмотреть список локальных образов можно так:
docker images
А удалить ненужные с помощью команды:
docker rmi <image>
Чтобы быстро очистить всё, что не используется (остановленные контейнеры, старые образы, неактивные сети), есть команда:
docker system prune
Она освободит место на диске и оставит только то, что нужно для работы.
Пример простого Dockerfile:
FROM python:3.11-slim
WORKDIR /app
COPY . .
RUN pip install -r requirements.txt
CMD ["python", "app.py"]
Что здесь происходит:
Для обучения или экспериментов этого вполне достаточно. Но в продакшене такое поведение создаёт лишние риски: если приложение внутри контейнера уязвимо, злоумышленник получает те же привилегии, что и root-процесс.
Чтобы снизить эти риски, в Dockerfile часто добавляют собственного пользователя и запускают приложение уже от его имени. Сделать это можно буквально в пару строк:
RUN useradd -m appuser
USER appuser
Чем отличаются:
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 нужен, чтобы перечислить зависимости проекта. Если их нет — можно оставить его пустым.
docker build -t myapp .
Флаг -t задаёт имя образа, а точка в конце указывает путь к контексту сборки — папке, где лежит Dockerfile и файлы проекта. После выполнения команды Docker по шагам прочитает Dockerfile и соберёт новый образ.
docker run -d -p 8000:8000 myapp
Docker создаст контейнер и запустит внутри него ваш app.py.
Откройте
Вы только что собрали собственный образ, запустили контейнер и проверили, что приложение работает. В реальных проектах таких образов может быть несколько — для тестов, продакшена или разных версий кода.
Чтобы их различать, Docker использует теги — о них поговорим дальше.
docker build -t myapp:1.0 .
Так проще поддерживать несколько вариантов образа — например, стабильный (1.0) и тестовый (dev).
Название репозитория должно совпадать с тем, что вы будете использовать в команде docker push.
Это важный шаг: Docker не создаёт репозитории автоматически.
username/repository:tag
где:
docker tag myapp:1.0 username/myapp:1.0
docker login
Docker попросит ввести логин и пароль от вашего аккаунта. После успешного входа появится сообщение вроде Login Succeeded.
docker push username/myapp:1.0
Docker начнёт загружать образ в ваш репозиторий на Docker Hub.
Когда загрузка закончится, образ появится в вашем профиле и станет доступен другим (если репозиторий публичный).
docker pull username/myapp:1.0
Docker скачает только нужные слои — если часть уже есть локально, она не будет загружаться заново.
После этого образ можно запустить как обычно:
docker run -d -p 8000:8000 username/myapp:1.0
Docker Compose позволяет описать все нужные контейнеры и их настройки в одном файле — docker-compose.yml. После этого весь проект можно запустить одной командой.
Пример простого docker-compose.yml:
services:
web:
build: .
ports:
- "8000:8000"
redis:
image: redis:alpine
Что здесь происходит:
docker compose up
Docker соберёт образы, создаст контейнеры, подключит сеть и запустит всё вместе.
Чтобы остановить проект, выполните команду:
docker compose down
Источник
В этом материале мы разберём базу: что такое Docker, как он работает и зачем нужен, а затем пошагово пройдём путь от установки до запуска первого контейнера.
Что такое 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-архитектуре.
Внутри dockerd используются вспомогательные среды:
- containerd отвечает за жизненный цикл контейнеров — создание, запуск, остановку и удаление
- runc делает сам запуск контейнера: изолирует процессы и использует механизмы ядра Linux которые отвечают за изоляцию и контроль ресурсов (namespaces, cgroups и другие). О них поговорим дальше.
При этом работающие контейнеры не зависят от 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 работает с образами
Контейнеры запускаются из образов (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-образа:
Схема показывает, как образ собирается из Dockerfile, сохраняется локально, загружается в реестр (push), скачивается обратно (pull) и запускается как контейнер. Источник
Каждый образ в реестре состоит из манифеста и набора слоёв.
Манифест — это файл-описание, в котором указано, какие слои входят в образ и как их собрать. Сами слои хранятся отдельно — как архивы, каждый со своим уникальным идентификатором (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-адрес, и в локальной сети он виден как отдельное устройство. Это удобно для тестирования сетевых сервисов или если контейнер должен работать наравне с другими машинами.
Логи и события
Все процессы внутри контейнера работают так же, как в обычной системе 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 открыт и распространяется по лицензии 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 вашей машины.
Для просмотра ссылки необходимо нажать
Вход или Регистрация
и увидеть стандартную стартовую страницу Nginx.Чтобы убедиться, что контейнер работает, выполните:
docker ps
В списке будет строка с именем nginx и статусом Up, который означает, что сервер запущен.
Интерактивный запуск контейнера
Иногда нужно не просто запустить контейнер, а зайти внутрь него ― посмотреть файлы, проверить окружение, выполнить команды. Для этого используют флаг -it.
Например:
docker run -it ubuntu bash
Что делает эта команда:
- -i — оставляет стандартный ввод открытым,
- -t — выделяет псевдотерминал,
- ubuntu — образ, который нужно запустить,
- bash — команда, которая будет выполнена внутри контейнера.
Чтобы выйти, используйте:
exit
Важно: если нужно зайти в уже работающий контейнер, используется другая команда:
docker exec -it <id> bash
Как следить за контейнерами
Когда контейнер запущен, Docker продолжает отслеживать его состояние. В любой момент можно посмотреть, что происходит, не прерывая работу приложения.Для этого используем уже знакомую команду:
docker ps
Она покажет список активных контейнеров: их идентификаторы, образы, статус и открытые порты. Если добавить флаг -a, отобразятся и завершённые контейнеры — это помогает найти старые тестовые сборки или понять, почему что-то остановилось.
Чтобы узнать подробнее, как запущен контейнер и какие у него настройки, выполните:
docker inspect <id>
Она выводит полное описание: от сетевых параметров до переменных окружения и точной команды запуска.
Если нужно быстро понять, что происходит внутри контейнера, не заходя в него вручную (например, просмотреть вывод приложения), используйте команду:
docker logs <id>
Но если всё-таки нужно заглянуть внутрь, например, проверить файлы или конфигурацию, — можно открыть интерактивную консоль:
docker exec -it <id> /bin/bash
Если в образе нет Bash (например, в Alpine), вместо него используют:
docker exec -it <id> /bin/sh
Так вы попадёте в среду контейнера, где доступны обычные Linux-команды.
Управление контейнерами
Контейнеры можно запускать, останавливать и удалять — так же просто, как обычные процессы в системе.Если контейнер нужно приостановить, используйте:
docker stop <id>
Docker отправит сигнал завершения процессу внутри контейнера и аккуратно его остановит.
Контейнер останется в списке и при желании его можно снова запустить командой:
docker start <id>
Когда контейнер больше не нужен, его можно удалить:
docker rm <id>
Важно: если попытаться удалить запущенный контейнер, Docker выдаст ошибку, чтобы не потерять данные.
Для принудительного удаления (остановка и удаление одной командой) используйте флаг -f:
docker rm -f <id>
Помимо контейнеров, система хранит образы, из которых они создаются. Посмотреть список локальных образов можно так:
docker images
А удалить ненужные с помощью команды:
docker rmi <image>
Чтобы быстро очистить всё, что не используется (остановленные контейнеры, старые образы, неактивные сети), есть команда:
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-процесс.
Чтобы снизить эти риски, в 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.
Откройте
Для просмотра ссылки необходимо нажать
Вход или Регистрация
, и вы увидите сообщение: "Hello from Docker!".Вы только что собрали собственный образ, запустили контейнер и проверили, что приложение работает. В реальных проектах таких образов может быть несколько — для тестов, продакшена или разных версий кода.
Чтобы их различать, Docker использует теги — о них поговорим дальше.
Зачем нужны теги
Тег — это просто метка версии. Если его не указать, Docker присвоит latest, но лучше явно обозначать версии:docker build -t myapp:1.0 .
Так проще поддерживать несколько вариантов образа — например, стабильный (1.0) и тестовый (dev).
Передача и хранение образов
После сборки Docker сохраняет образ локально — он доступен только на вашем компьютере. Если нужно поделиться им с коллегами или перенести на другой компьютер, проще всего воспользоваться Docker Hub.1. Создайте репозиторий на Docker Hub
Зайдите в свой аккаунт на
Для просмотра ссылки необходимо нажать
Вход или Регистрация
и вручную создайте новый репозиторий — так же, как создают новый проект на 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.
Источник







