← назад к разделу

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-приложение в образ шаг за шагом.