Docker: зачем он нужен и почему это не «магия контейнеров»

Docker: зачем он нужен и почему это не «магия контейнеров»

Docker нужен, чтобы перестать играть в игру «у меня работает». Контейнер - это упакованное окружение:

  • твоя версия Node/Go
  • зависимости
  • настройки
  • команда запуска

И всё это воспроизводимо на любом компьютере и сервере.

Проблема: «у меня работает»

Знакомая история: ты написал приложение, запустил локально - всё отлично. Коллега клонирует репу - не работает. На сервере - другая ошибка. Причины всегда одни и те же:

  • Разные версии - у тебя Go 1.22, на сервере 1.19
  • Разные зависимости ОС - libpq не установлена, openssl другой версии
  • Разные переменные окружения - .env забыли, порт занят
  • Разные ОС - macOS vs Ubuntu vs Windows, пути к файлам, line endings

Docker решает это: образ содержит всё нужное, и запускается одинаково везде, где есть Docker.

Контейнер vs виртуальная машина

Container vs VM: VM везёт свой kernel на каждое приложение, контейнеры делят kernel хоста

<ComparisonTable title="Контейнер vs VM" headers={["", "Виртуальная машина", "Контейнер"]} rows={[ ["Ядро ОС", "Своё (гостевая ОС)", "Общее с хостом"], ["Размер", "Гигабайты (Ubuntu ~2 ГБ)", "Мегабайты (Alpine ~5 МБ)"], ["Запуск", "Минуты", "Секунды"], ["Изоляция", "Полная (гипервизор)", "Процессная (namespaces, cgroups)"], ["Overhead", "Высокий (RAM под гостевую ОС)", "Минимальный"], ["Пример", "VirtualBox, VMware", "Docker, Podman"] ]} />

VM - это квартира с отдельным фундаментом. Контейнер - комната в общежитии: своя дверь, свои вещи, но стены и крыша общие. Контейнеры - это процессы Linux, изолированные через namespaces.

Архитектура Docker

Docker состоит из трёх частей:

Архитектура Docker: CLI → Daemon → containerd, OCI как общий стандарт

  • Docker CLI - команды, которые ты вводишь (docker run, docker build)
  • Docker Daemon (dockerd) - фоновый процесс, управляет контейнерами
  • Container Runtime (containerd) - собственно запускает и изолирует процессы
Open Container Initiative определяет стандарт на формат образов и runtime. Docker - не единственный: Podman, containerd, CRI-O тоже работают с OCI-образами. Ты учишь не «Docker», а индустриальный стандарт.

Образ vs контейнер

Образ (image) - это рецепт и ингредиенты. Контейнер - это запущенное блюдо.

# Скачиваем образ (рецепт)
docker pull nginx:alpine

# Запускаем контейнер (блюдо)
docker run -d --name web nginx:alpine

# Из одного образа можно запустить сколько угодно контейнеров
docker run -d --name web2 nginx:alpine
docker run -d --name web3 nginx:alpine

Образ - read-only, его можно версионировать и хранить в registry (Docker Hub, GitLab Registry). Контейнер - это образ + тонкий writable-слой для данных процесса.

Docker Registry

Registry - хранилище образов. Как GitHub для кода, только для Docker-образов.

  • Docker Hub - публичный по умолчанию (nginx, postgres, golang)
  • GitLab Container Registry - приватный, встроен в GitLab
  • GitHub Container Registry (ghcr.io) - приватный, привязан к GitHub
# Скачать публичный образ
docker pull postgres:16-alpine

# Залить свой образ в registry
docker tag myapp:latest registry.gitlab.com/user/myapp:v1.0
docker push registry.gitlab.com/user/myapp:v1.0

Где Docker поможет тебе прямо сейчас

ЗадачаБез DockerС Docker
Поднять PostgreSQLУстановка, pg_hba.conf, перезапускdocker run -d postgres:16-alpine
Запустить RedisСкачать, скомпилировать, настроитьdocker run -d redis:7-alpine
Собрать Go backendУстановить Go, настроить GOPATHdocker build -t backend .
Показать проект коллеге«Сначала установи Go 1.22, потом...»docker compose up
Docker не ускоряет код, не исправляет баги и не заменяет тесты. Он решает одну проблему - воспроизводимость окружения. Если приложение падает в контейнере, оно упадёт и без него.

Мини-задание

  • Установи Docker Desktop (macOS/Windows) или Docker Engine (Linux)
  • Проверь: docker --version и docker compose version
  • Запусти docker run --rm hello-world - увидишь приветствие от Docker
  • Запусти docker run --rm -it alpine sh - окажешься внутри контейнера Alpine
  • Внутри контейнера: cat /etc/os-release, whoami, exit

Итог

  • Docker упаковывает приложение + зависимости + ОС в один образ. «Работает у меня» становится «работает везде».
  • Контейнер - не VM: он разделяет ядро хоста, запускается за секунды, весит мегабайты.
  • Архитектура: CLI → Daemon → Container Runtime. Образы хранятся в Registry.
  • OCI-стандарт: навыки переносятся между Docker, Podman, containerd.

Типичная ошибка

Начинающие часто путают образ и контейнер. Собрал образ - он есть в docker images. Запустил контейнер - он в docker ps. Удалил контейнер (docker rm) - образ всё ещё на месте. Удалил образ (docker rmi) - а контейнеры от него могут ещё работать (пока не остановишь).

Вторая ошибка - думать, что Docker заменяет CI/CD, мониторинг и тесты. Docker - это инструмент упаковки, а не волшебная кнопка «в прод».

Мини-практика (10-15 минут)

Запусти три разных контейнера и исследуй их изнутри:

# 1. Alpine - минимальная Linux
docker run --rm -it alpine sh
# Внутри: ls /, cat /etc/os-release, exit

# 2. Ubuntu - знакомый Linux
docker run --rm -it ubuntu bash
# Внутри: apt list --installed | head, exit

# 3. Nginx - рабочий веб-сервер
docker run --rm -d -p 8080:80 --name test-nginx nginx:alpine
# Открой http://localhost:8080 в браузере
docker stop test-nginx

Сравни размеры: docker images | grep -E "alpine|ubuntu|nginx". Заметь разницу - Alpine ~5 МБ, Ubuntu ~70 МБ.

Зарегистрируйтесь бесплатно, чтобы пройти квиз, решить задание с автопроверкой и вести прогресс.