Проблема: «у меня работает, у тебя нет»
Ты написал приложение на Python 3.11, используешь библиотеку версии 2.5 и Redis 7. На твоём ноутбуке всё работает. Коллега клонирует репозиторий — и ничего не запускается. У него Python 3.9, другая версия библиотеки и Redis 6.
Или другой сценарий: разрабатываешь на Windows, сервер работает на Linux. Код одинаковый — а поведение разное.
Это классическая проблема окружений. Docker решает её раз и навсегда.
Контейнер — это изолированный процесс
Представь себе обычную программу — браузер, веб-сервер, база данных. Когда ты её запускаешь, она работает как процесс в операционной системе. Этот процесс использует библиотеки, которые установлены на твоём компьютере, обращается к файлам, сети, другим программам.
Проблема: разные программы могут требовать разные версии одних и тех же библиотек. Или один сервис может мешать другому — занять порт, изменить конфиг.
Контейнер — это тот же процесс, но изолированный. Он работает так, будто у него есть собственная операционная система: своя файловая система, своя сеть, свои переменные окружения. При этом он не тяжёлый, как виртуальная машина — это просто хорошо огороженный процесс на том же Linux-ядре.
Что конкретно означает «изолированный»:
- Контейнер A запускает Python 3.9, контейнер B запускает Python 3.11 — они работают рядом и не мешают друг другу. Конфликта версий нет.
- Контейнер не видит файлы другого контейнера по умолчанию. У каждого своя файловая система. Случайно затереть чужие данные невозможно.
- У каждого контейнера своя сеть и своё пространство портов. Два контейнера могут оба «слушать» порт 8080 внутри себя — снаружи это разные порты. Пока ты явно не откроешь порт (
-p 8080:8080), он недоступен с хоста. - Если контейнер падает, хост и остальные контейнеры продолжают работать. Авария в одном контейнере не тянет за собой всё остальное.
Контейнер запускается за секунды и ведёт себя одинаково на ноутбуке разработчика, в CI-системе и на продакшен-сервере.
Образ — это упакованная коробка с приложением
Образ (Image) — это неизменяемый шаблон, из которого создаётся контейнер.
Образ — это как коробка с игрой. Внутри упаковано всё необходимое: сам код приложения, все его зависимости, нужная версия Python или Node.js, конфигурационные файлы. Ты «распаковываешь» образ — получаешь работающий контейнер.
Вот как это работает на практике:
- Разработчик создаёт образ — упаковывает приложение со всеми зависимостями в единый файл-шаблон.
- Образ отправляется в реестр (registry) — как закинуть коробку на почту. Главный публичный реестр — Docker Hub, там уже лежат тысячи готовых образов:
nginx,postgres,redis,python,node. - На сервере:
docker pull→docker run— сервер скачивает образ с реестра и запускает контейнер. Именно тот же самый образ, что и у разработчика. Гарантированно одинаковое окружение.
Образ nginx:latest → docker run → Контейнер nginx_1 (работает)
→ Контейнер nginx_2 (работает)
→ Контейнер nginx_3 (работает)
Один образ — сколько угодно контейнеров. Все они стартуют с одинакового состояния.
Имя образа и тег версии
Образ обычно записывается в виде ИМЯ:ТЕГ:
nginx:alpine
python:3.12-alpine
redis:7
Часть до двоеточия указывает на приложение или репозиторий образа. Часть после двоеточия - тег, то есть выбранный вариант или версия. Например, python:3.12-alpine содержит Python 3.12 в компактном окружении Alpine Linux.
Если тег не указан, Docker обычно использует latest. Это не означает «самая новая версия навсегда»: latest - обычная изменяемая метка. В рабочем проекте версию образа указывают явно, чтобы следующий запуск не получил неожиданно другое содержимое.
Посмотреть образы, уже загруженные на текущую машину, можно командой:
docker images
В выводе видны полное имя образа, его идентификатор и размер на диске. Наличие образа на машине означает, что Docker сможет создать из него контейнер без повторного скачивания. Если нужного образа нет, его можно загрузить командой docker pull, а docker run при необходимости тоже попробует сначала получить его из registry.
Важно различать образ и контейнер:
- образ - неизменяемый шаблон на диске;
- контейнер - созданный из этого образа экземпляр программы;
- из одного образа можно одновременно запустить несколько контейнеров с разными именами.
Контейнеры vs Виртуальные машины
Контейнеры часто сравнивают с виртуальными машинами, но это разные вещи:
| Контейнер | Виртуальная машина | |
|---|---|---|
| Что изолируется | Процесс (файловая система, сеть) | Полноценный компьютер |
| Размер образа | Десятки МБ | Гигабайты |
| Время запуска | Секунды | Минуты |
| Ядро ОС | Общее с хостом | Своё (гипервизор) |
| Потребление памяти | Минимальное | Значительное |
Виртуальная машина — это как полноценный компьютер внутри компьютера. Контейнер — это просто хорошо изолированный процесс.
Важно: контейнеры не заменяют виртуальные машины. В реальности контейнеры часто запускают внутри ВМ — например, в облаке (AWS, GCP, Azure) создаётся виртуальный сервер, а на нём уже работают контейнеры.
Архитектура Docker
- Docker Client (
docker) — CLI, с которым ты работаешь в терминале. Когда ты вводишьdocker run, эта команда уходит к демону. - Docker Daemon (
dockerd) — фоновый процесс, который реально управляет контейнерами и образами. - Docker Registry (Docker Hub) — удалённое хранилище образов. Откуда
docker pullскачивает образы.
Почему Docker используется в DevOps
- Воспроизводимость — одинаковое окружение на ноутбуке разработчика, в CI-системе и в продакшене
- Скорость — контейнер стартует за секунды, не минуты
- Изоляция — сервисы не мешают друг другу, независимо от версий зависимостей
- Масштабирование — нужно 10 копий одного сервиса? Запускаешь 10 контейнеров из одного образа
- Основа для Kubernetes — Kubernetes управляет именно контейнерами
Docker — это фундамент современного DevOps. Без него невозможен нормальный CI/CD и оркестрация.
