Docker — инструмент, который позволяет упаковать приложение вместе со всем необходимым окружением и запустить его одинаково на любой машине. Для бэкендера это означает конец вечной проблемы «на моей машине работает».
Проблема: «на моей машине работает»
Представьте: вы написали Spring Boot-приложение, протестировали локально — всё работает. Отдаёте коллеге — падает. Деплоите на сервер — снова проблема. Причина почти всегда одна: окружение отличается.
У вас Java 21, у коллеги — 17. На сервере другая версия библиотеки. Переменная окружения называется чуть иначе. Такие расхождения копятся и превращаются в непредсказуемые ошибки, которые сложно воспроизвести.
Раньше эту проблему решали виртуальными машинами: поднять отдельную ОС, настроить её вручную, передать образ диска на несколько гигабайт. Это работало, но было тяжело и медленно.
Docker предложил более лёгкий подход — контейнеры.
Что такое контейнер
Контейнер — изолированный процесс на хост-машине. Он видит только то, что ему разрешено: свою файловую систему, свои переменные окружения, свои сетевые интерфейсы.
Короткая формула: контейнер = изолированный процесс + своя файловая система.
Изоляция достигается средствами ядра Linux:
- namespaces — разделяют пространства имён процессов, сети, пользователей, файловой системы.
- cgroups (control groups) — ограничивают, сколько CPU и памяти может использовать контейнер.
Это принципиально отличает контейнер от виртуальной машины.
Контейнер vs виртуальная машина
| Виртуальная машина | Контейнер | |
|---|---|---|
| Ядро ОС | Своё (гостевое) | Общее с хостом |
| Запуск | Минуты | Секунды / доли секунды |
| Размер | Гигабайты | Десятки–сотни мегабайт |
| Изоляция | Полная (аппаратный уровень) | На уровне процессов |
Виртуальная машина эмулирует целый компьютер: у неё своё ядро, свои драйверы, своя ОС. Это даёт максимальную изоляцию, но требует значительных ресурсов.
Контейнер использует ядро хоста и добавляет изоляцию поверх него. Он не знает о соседних контейнерах и не видит файлов хоста — но процессы в нём запускаются почти без накладных расходов.
Для большинства задач бэкендера контейнеров вполне достаточно.
Образ и контейнер: класс и объект
Прежде чем запустить контейнер, нужен образ (image). Образ — это неизменяемый слепок файловой системы: все файлы приложения, зависимости, конфигурация, нужная версия Java.
Соотношение простое:
- Образ — шаблон (как класс в Java). Он неизменен, хранится на диске или в реестре.
- Контейнер — запущенный экземпляр образа (как объект). Их может быть несколько из одного образа.
Один образ myapp:1.0 можно запустить как один контейнер на ноутбуке разработчика, второй — на тестовом сервере, третий — в production. Каждый получает идентичное окружение.
Где это помогает бэкендеру
Одинаковое окружение везде. Dev, staging, production работают на одном образе. «На моей машине работает» перестаёт быть аргументом.
Быстрый старт и остановка. Контейнер с JVM стартует за несколько секунд. Это удобно как для разработки, так и для горизонтального масштабирования под нагрузкой.
Изоляция зависимостей. Два приложения требуют разные версии одной библиотеки — каждое запускается в своём контейнере без конфликтов.
Воспроизводимая сборка. Образ собирается по инструкции (Dockerfile) и воспроизводится одинаково на любой машине. Это основа надёжного CI/CD.
Первый взгляд на базовые команды
Ниже — обзорные примеры, как Docker выглядит на практике. Детали каждой команды разобраны в следующей статье.
# Запустить контейнер из образа eclipse-temurin:21-jre
docker run eclipse-temurin:21-jre java -version
# Посмотреть запущенные контейнеры
docker ps
# Остановить контейнер по его ID или имени
docker stop <container_id>
# Удалить остановленный контейнер
docker rm <container_id>
docker run скачивает образ из реестра (если его нет локально), создаёт контейнер и запускает указанную команду. docker ps показывает, что сейчас работает.
Реестр по умолчанию — Docker Hub (hub.docker.com). Там хранятся официальные образы: eclipse-temurin, postgres, nginx и сотни других.
Коротко
- Контейнер — изолированный процесс с собственной файловой системой; изоляция строится на
namespacesиcgroupsядра Linux. - Контейнер использует ядро хоста — он легче и быстрее виртуальной машины, но изолирует только на уровне процессов.
- Образ — неизменяемый шаблон; контейнер — запущенный экземпляр образа (один образ, много контейнеров).
- Docker решает проблему «на моей машине работает»: dev, staging и production работают из одного образа.
- Образ описывается файлом
Dockerfileи воспроизводим на любой машине. - Базовые операции:
docker run,docker ps,docker stop,docker rm.
Что почитать дальше
- Образы и Dockerfile — как устроены слои образа и как написать первый
Dockerfile. - Контейнеры: запуск и управление — флаги
docker run, переменные окружения, порты, жизненный цикл контейнера. - Spring Boot в контейнере — упакуем реальное Spring Boot-приложение в образ шаг за шагом.