ПроКодинг - Откроем для вас мир IT!

Представь ситуацию: ты написал код на своем ноутбуке, все работает идеально. Но когда коллега запускает проект у себя - падает из-за версии библиотеки. Или сервер в продакшене ведет себя иначе, чем в тестовой среде. Знакомо? Именно здесь на сцену выходит Docker, платформа для автоматизации развертывания приложений в изолированных контейнерах. Для джуниор-DevOps-инженера это не просто «еще один инструмент», а фундамент, без которого сложно представить современную инфраструктуру.

В этом руководстве мы разберем, как Docker меняет подход к разработке, какие команды нужно знать наизусть, и как избежать типичных ошибок новичков. Никакой воды - только то, что реально пригодится на первой работе или в учебных проектах.

Почему Docker стал стандартом де-факто

Раньше настройка окружения занимала часы: установка зависимостей, компиляция, правка конфигов. Теперь весь процесс упаковывается в контейнер - легкую, переносимую единицу исполнения. В отличие от виртуальных машин (VM), контейнеры не эмулируют операционную систему, а используют ядро хоста. Это делает их быстрее и легче.

  • Изоляция: каждое приложение живет в своей песочнице, конфликты библиотек исключены.
  • Скорость: запуск контейнера занимает секунды, против минут для VM.
  • Переносимость: образ, собранный на Mac, запустится на Linux-сервере без изменений.

Для джуниора важно понимать: Docker решает проблему «а у меня работает». Он гарантирует, что код будет вести себя одинаково в любой среде - от локальной разработки до облачного кластера Kubernetes.

Ключевые понятия: образы, контейнеры и реестры

Чтобы уверенно работать с Docker, нужно четко различать три базовых сущности:

  1. Образ (Image) - это статический шаблон приложения со всеми зависимостями. Представь его как рецепт торта: список ингредиентов и инструкции. Образы хранятся в реестрах, например, в Docker Hub.
  2. Контейнер (Container) - это работающий экземпляр образа. Если образ - это рецепт, то контейнер - это сам испеченный торт, который можно съесть (запустить) или выбросить (удалить).
  3. Реестр (Registry) - хранилище образов. Публичный Docker Hub содержит миллионы готовых образов (nginx, postgres, redis). Компании часто ведут свои приватные реестры для контроля версий.

Типичная ошибка новичка - путать эти понятия. Запомни: ты собираешь образ, запускаешь контейнер и тянешь образ из реестра.

Практика: твой первый Dockerfile

Сердце любого Docker-проекта - файл Dockerfile. Это текстовый скрипт, который описывает шаги сборки образа. Давай создадим простой Node.js сервис.

FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install --production
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]

Разберем каждую строку:

  • FROM node:18-alpine: берем базовый образ Node.js версии 18 на базе Alpine Linux (очень легкий, ~5 МБ против ~800 МБ у стандартного Debian).
  • WORKDIR /app: устанавливаем рабочую директорию внутри контейнера.
  • COPY: копируем файлы из проекта в образ. Сначала манифесты пакетов, чтобы использовать кэш при повторной сборке.
  • RUN npm install: устанавливает зависимости. Команда RUN создает новый слой в образе.
  • EXPOSE 3000: документирует, какой порт использует приложение (не открывает его автоматически, но полезно для документации).
  • CMD: команда по умолчанию при запуске контейнера.

Собираем образ командой: docker build -t my-app:1.0 .. Флаг -t дает имя и тег образу. Точка в конце указывает на текущую директорию как контекст сборки.

Conceptual illustration of Docker images, containers, and registry structure

Управление контейнерами: основные команды

Когда образ собран, пора управлять жизненным циклом контейнеров. Вот минимальный набор команд, который должен быть под рукой:

Основные команды Docker CLI
Команда Описание Пример
docker run Создает и запускает новый контейнер docker run -d -p 3000:3000 my-app
docker ps Показывает список работающих контейнеров docker ps -a (все, включая остановленные)
docker logs Выводит логи контейнера docker logs -f my-container
docker stop Останавливает контейнер docker stop my-container
docker rm Удаляет контейнер docker rm my-container
docker exec Выполняет команду внутри работающего контейнера docker exec -it my-container bash

Флаг -d в команде run запускает контейнер в фоне (detach mode). Флаг -p пробрасывает порты с хоста в контейнер: формат HOST_PORT:CONTAINER_PORT.

Docker Compose: мульти-контейнерные приложения

Никто не разворачивает монолитное приложение одним контейнером. Обычно есть веб-сервер, база данных, кэш, очередь задач. Здесь на помощь приходит Docker Compose - инструмент для определения и запуска многоконтейнерных приложений с помощью YAML-файла.

Пример файла docker-compose.yml:

version: '3.8'
services:
  web:
    build: .
    ports:
      - "3000:3000"
    depends_on:
      - db
  db:
    image: postgres:15
    environment:
      POSTGRES_PASSWORD: secret
    volumes:
      - pgdata:/var/lib/postgresql/data
volumes:
  pgdata:

Этот конфиг делает три вещи:

  • Запускает два сервиса: web (наш Node.js) и db (PostgreSQL).
  • Настраивает зависимость: web стартует после db.
  • Создает том pgdata для хранения данных БД вне контейнера, чтобы они не терялись при удалении контейнера.

Запуск всего стека одной командой: docker compose up -d. Остановка: docker compose down.

Futuristic server room with glowing network connections representing CI/CD

Типичные ошибки джуниоров и как их избежать

Даже опытные инженеры иногда совершают оплошности, но вот несколько частых граблей для новичков:

1. Хранение данных в контейнере

Если ты пишешь данные прямо в файловую систему контейнера, они исчезнут при удалении контейнера. Решение: используй тома (volumes) или bind mounts. Для баз данных это критически важно.

2. Огромные образы

Стандартный образ Ubuntu весит сотни мегабайт. Для продакшена лучше использовать Alpine или Distroless. Также следит за тем, чтобы в образ не попадали ненужные файлы (используй .dockerignore аналогично .gitignore).

3. Игнорирование кэша слоев

Порядок инструкций в Dockerfile важен. Если ты копируешь весь код перед установкой зависимостей, каждый коммит будет вызывать переустановку всех пакетов. Всегда копируй манифесты пакетов сначала, затем остальной код.

4. Запуск root-пользователя

По умолчанию процессы в контейнере работают от имени root. Это небезопасно. Добавь в Dockerfile инструкцию USER node (или другой непривилегированный пользователь).

Интеграция с CI/CD: следующий шаг

Локальная разработка - это только начало. В реальной жизни Docker-образы строятся и публикуются автоматически через системы непрерывной интеграции (CI/CD), такие как GitHub Actions, GitLab CI или Jenkins.

Типичный пайплайн выглядит так:

  1. Разработчик пушит код в репозиторий.
  2. CI-система запускает тесты.
  3. Если тесты прошли, собирается Docker-образ.
  4. Образ загружается в реестр (например, Harbor, ECR, GCR).
  5. Обновляется конфигурация оркестратора (Kubernetes) или деплоится на сервер.

Как джуниору стоит подготовиться к этому этапу? Учись писать чистые Dockerfile, которые легко автоматизируются. Избегай хардкода путей и переменных окружения, которые могут отличаться между средами. Используй аргументы сборки (ARG) и переменные окружения (ENV) гибко.

Чек-лист перед первым деплоем

Прежде чем отправлять свой проект в прод или показывать ментору, прогони этот список:

  • [ ] Используется ли легкая базовая система (Alpine/Distroless)?
  • [ ] Есть ли файл .dockerignore?
  • [ ] Данные БД сохраняются во внешних томах?
  • [ ] Приложение работает от непривилегированного пользователя?
  • [ ] Порты проброшены корректно и документированы?
  • [ ] Логи выводятся в stdout/stderr (для сбора логгером)?
  • [ ] Образ имеет осмысленный тег (версия, git hash)?

Docker - это не магия, а дисциплина. Как только ты освоишь базу, откроется путь к более сложным темам: оркестрации в Kubernetes, сетевым моделям и мониторингу. Начни с малого: собери свой пет-проект, упакуй его в контейнер и запусти через Compose. Практика даст больше, чем десять часов чтения документации.

Какая разница между Docker и виртуальными машинами?

Виртуальные машины эмулируют всю операционную систему, поэтому тяжелые и медленные. Контейнеры используют общее ядро хоста и изолируют только пространство имен и файловую систему. Это делает контейнеры в десятки раз быстрее и легче по ресурсам.

Нужно ли устанавливать Docker Desktop на Linux?

Нет. На Linux Docker Engine устанавливается напрямую в системное ядро, что обеспечивает максимальную производительность. Docker Desktop нужен для macOS и Windows, где требуется виртуальная машина для поддержки Linux-контейнеров.

Что такое многоступенчатая сборка (multi-stage build)?

Это техника, позволяющая использовать разные образы на разных этапах сборки. Например, первый этап собирает бинарник с помощью компилятора (Go, Rust), а второй этап копирует только готовый файл в легкий финальный образ (scratch или alpine). Это значительно уменьшает размер итогового образа.

Как посмотреть, сколько места занимают образы и контейнеры?

Используй команду docker system df. Она покажет распределение дискового пространства между изображениями, контейнерами, томами и неиспользуемыми объектами. Для очистки можно использовать docker system prune.

Можно ли запустить контейнер без Dockerfile?

Да, если использовать готовый образ из реестра. Например, docker run nginx скачает официальный образ Nginx и запустит его. Dockerfile нужен только тогда, когда нужно создать собственный кастомный образ с уникальными настройками или кодом.