Что такое Docker и Docker Compose: полное руководство для системных администраторов

Ilustración colorida del concepto de Docker y Docker Compose con una ballena nadando entre cubos que representan contenedores.

Если вы когда-нибудь слышали фразу «у меня на машине работает, а на сервере нет» — добро пожаловать в мир, до которого ещё не дошёл Docker. Именно эту проблему он и решает. В этой статье разберём, что такое Docker, зачем нужен Docker Compose, как они работают изнутри — и почему сегодня без них не обходится ни один серьёзный production-стенд.

Docker — что это и зачем

Определение

Docker — это открытая платформа для разработки, доставки и запуска приложений. Его ключевая идея: отделить приложение от инфраструктуры, на которой оно работает.

Официальная документация описывает это так: Docker позволяет упаковать и запустить приложение в изолированной среде, называемой контейнером. Контейнеры легковесны, содержат всё необходимое для работы и не зависят от того, что установлено на хосте.

Аналогия: грузовой контейнер

Представьте морской контейнер. Раньше при погрузке на корабль для каждого типа груза нужны были разные способы укладки, разные крепления, разные условия. Морской контейнер стандартизировал этот процесс: неважно, что внутри — автомобиль, бананы или электроника. Снаружи всё контейнеры одинаковые, их можно грузить на любой корабль, поезд или грузовик.

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

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

Частый вопрос: «Чем контейнер отличается от виртуальной машины?»

ПараметрВиртуальная машинаDocker-контейнер
РазмерГигабайтыМегабайты
ЗапускМинутыСекунды
ИзоляцияПолная (отдельное ядро ОС)Уровень процессов (общее ядро)
Накладные расходыВысокиеМинимальные
ПереносимостьСредняяВысокая

Виртуальная машина эмулирует железо и запускает полноценную операционную систему. Контейнер же использует ядро хостовой ОС, изолируя только окружение процессов через механизмы Linux — cgroups (ограничение ресурсов) и namespaces (изоляция пространства имён). Это и делает контейнеры такими быстрыми и лёгкими.

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

Docker работает по модели клиент-сервер. Ниже приведены ключевые компоненты:

КомпонентОписание
Docker Client (CLI)То, с чем работает пользователь. Команды docker run, docker build, docker ps. Клиент отправляет их в Daemon через REST API.
Docker Daemon (dockerd)Фоновый сервис, который управляет образами, контейнерами, сетями и томами. Именно он выполняет реальную работу.
Docker RegistryХранилище образов. Публичный реестр — Docker Hub. Можно поднять свой приватный реестр.
Docker HubОфициальный публичный реестр образов. Содержит более 100 000 готовых образов от сообщества и вендоров.

Ключевые понятия Docker

Образ (Image)

Docker Image — это шаблон только для чтения, из которого создаются контейнеры. Можно провести аналогию с ISO-образом диска или классом в объектно-ориентированном программировании.

Образ состоит из слоёв (layers). Каждая инструкция в Dockerfile создаёт отдельный слой. Это даёт два преимущества:

  • Слои кешируются — повторная сборка происходит быстро, пересобираются только изменённые слои
  • Образы эффективно переиспользуют общие слои — если два образа основаны на Ubuntu, слой с Ubuntu хранится один раз

Контейнер (Container)

Контейнер — запущенный экземпляр образа. Если образ — это класс, то контейнер — это объект (экземпляр класса). Из одного образа можно запустить сколько угодно контейнеров одновременно.

# Запустить контейнер из образа nginx
docker run -d -p 80:80 --name my-nginx nginx

# Посмотреть запущенные контейнеры
docker ps

# Зайти внутрь контейнера
docker exec -it my-nginx /bin/bash

# Остановить и удалить
docker stop my-nginx && docker rm my-nginx

Dockerfile

Dockerfile — текстовый файл с набором инструкций для сборки образа. Каждая строка — это шаг, каждый шаг — новый слой в образе.

# Базовый образ
FROM python:3.11-slim

# Рабочая директория внутри контейнера
WORKDIR /app

# Сначала копируем только зависимости (кеширование слоёв)
COPY requirements.txt .

# Устанавливаем зависимости
RUN pip install --no-cache-dir -r requirements.txt

# Копируем код приложения
COPY . .

# Открываем порт
EXPOSE 5000

# Команда запуска
CMD ["python", "app.py"]

Совет по оптимизации: копируйте requirements.txt и устанавливайте зависимости ДО копирования кода приложения. Тогда при изменении кода слой с зависимостями не пересобирается — он уже в кеше.

Volumes (Тома)

По умолчанию данные внутри контейнера эфемерны: при удалении контейнера они пропадают. Volume — это механизм для хранения данных вне контейнера, на хостовой машине.

# Создать том
docker volume create my-data

# Запустить контейнер с томом
docker run -d -v my-data:/var/lib/mysql mysql:8.0

# Или монтировать директорию хоста
docker run -d -v /home/user/data:/var/lib/mysql mysql:8.0

Networks (Сети)

Docker позволяет создавать изолированные виртуальные сети для контейнеров. Контейнеры в одной сети могут обращаться друг к другу по имени.

# Создать сеть
docker network create my-network

# Запустить контейнеры в одной сети
docker run -d --network my-network --name app my-app
docker run -d --network my-network --name db postgres:15

# Из контейнера app можно обратиться к db по имени: db:5432

Docker Compose

Проблема без Compose

Представьте типичное веб-приложение: фронтенд, бэкенд на Node.js, база данных PostgreSQL, кеш Redis, брокер сообщений RabbitMQ. Запуск всего этого вручную выглядит так:

docker network create app-network

docker run -d \
  --name postgres \
  --network app-network \
  -e POSTGRES_PASSWORD=secret \
  -e POSTGRES_DB=myapp \
  -v pgdata:/var/lib/postgresql/data \
  postgres:15

docker run -d \
  --name redis \
  --network app-network \
  redis:7

# ... и так далее для каждого сервиса

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

Что такое Docker Compose

Docker Compose — инструмент для определения и запуска многоконтейнерных приложений. Вся конфигурация описывается в одном YAML-файле (compose.yaml), а весь стек запускается одной командой.

Compose упрощает управление всем стеком приложения: легко управлять сервисами, сетями и томами в едином конфигурационном файле, а затем запустить всё одной командой: docker compose up.

Пример compose.yaml

services:
  postgres:
    image: postgres:15
    container_name: app-postgres
    environment:
      POSTGRES_PASSWORD: secret
      POSTGRES_DB: myapp
    volumes:
      - pgdata:/var/lib/postgresql/data
    networks:
      - app-network
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 10s
      timeout: 5s
      retries: 5

  redis:
    image: redis:7-alpine
    container_name: app-redis
    networks:
      - app-network

  backend:
    build: ./backend
    container_name: app-backend
    ports:
      - "3000:3000"
    environment:
      DB_HOST: postgres
      DB_PORT: 5432
      REDIS_HOST: redis
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_started
    networks:
      - app-network

  frontend:
    build: ./frontend
    container_name: app-frontend
    ports:
      - "80:80"
    depends_on:
      - backend
    networks:
      - app-network

volumes:
  pgdata:

networks:
  app-network:
    driver: bridge

Основные команды Compose

# Запустить весь стек в фоне
docker compose up -d

# Посмотреть статус сервисов
docker compose ps

# Логи всех сервисов в реальном времени
docker compose logs -f

# Логи конкретного сервиса
docker compose logs -f backend

# Остановить и удалить контейнеры
docker compose down

# Остановить и удалить включая тома
docker compose down --volumes

Ключевые возможности Docker Compose

Зависимости между сервисами (depends_on)

depends_on позволяет указать порядок запуска. С параметром condition: service_healthy Compose дождётся, пока healthcheck сервиса вернёт успех, прежде чем запустить зависящий от него сервис.

depends_on:
  postgres:
    condition: service_healthy

Переменные окружения и .env файлы

Compose автоматически читает .env файл из директории проекта. Это позволяет хранить чувствительные данные отдельно от конфига.

# .env файл
DB_PASSWORD=supersecret
APP_PORT=3000

# compose.yaml
services:
  backend:
    environment:
      DB_PASSWORD: ${DB_PASSWORD}
    ports:
      - "${APP_PORT}:3000"

Профили (Profiles)

Профили позволяют включать/выключать группы сервисов при запуске.

services:
  app:
    image: my-app

  debug-tools:
    image: some-debug-image
    profiles:
      - debug   # Запускается только с --profile debug

# Запустить с инструментами отладки
docker compose --profile debug up -d

Масштабирование сервисов

# Запустить 3 экземпляра backend
docker compose up -d --scale backend=3

Типичные сценарии применения

Среда разработки

Compose позволяет сократить «гайд по настройке» для нового разработчика с 10 страниц до трёх команд:

git clone https://github.com/myorg/myapp
cd myapp
docker compose up -d

CI/CD и автоматическое тестирование

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

# В pipeline: создаём окружение, запускаем тесты, сносим
docker compose up -d
./run_tests.sh
docker compose down

Продакшн на одном сервере

Для небольших проектов Compose прекрасно работает в продакшне. Обновление образов:

# Обновить образы из реестра
docker compose pull

# Пересоздать только изменившиеся контейнеры
docker compose up -d

Шпаргалка по командам

Docker — образы

КомандаОписание
docker imagesСписок всех локальных образов
docker pull nginx:latestСкачать образ из реестра
docker build -t myapp:1.0 .Собрать образ из Dockerfile
docker rmi myapp:1.0Удалить образ
docker image pruneУдалить неиспользуемые образы

Docker — контейнеры

КомандаОписание
docker run -d -p 80:80 nginxЗапустить контейнер в фоне
docker psСписок запущенных контейнеров
docker ps -aСписок всех контейнеров
docker stop <name>Остановить контейнер
docker start <name>Запустить остановленный контейнер
docker rm <name>Удалить контейнер
docker logs <name> -fЛоги контейнера в реальном времени
docker exec -it <name> bashВойти внутрь контейнера
docker system prune -aОчистить всё неиспользуемое

Docker Compose

КомандаОписание
docker compose up -dЗапустить весь стек в фоне
docker compose downОстановить и удалить контейнеры
docker compose psСтатус всех сервисов
docker compose logs -fЛоги всех сервисов
docker compose logs -f <svc>Логи конкретного сервиса
docker compose exec <svc> bashВойти в контейнер сервиса
docker compose pullОбновить образы
docker compose buildПересобрать образы
docker compose restart <svc>Перезапустить сервис
docker compose configПроверить итоговую конфигурацию
docker compose topПроцессы внутри контейнеров

Лучшие практики

Один процесс — один контейнер

Не запускайте nginx, php-fpm и postgresql в одном контейнере. Каждый сервис — отдельный контейнер. Это упрощает масштабирование, обновление и отладку.

Используйте .dockerignore

Аналог .gitignore для Docker. Исключайте node_modules, .git, .env, временные файлы — это ускорит сборку и не даст секретам попасть в образ.

node_modules
.git
.env
*.log
__pycache__

Не запускайте процессы от root

В Dockerfile создайте отдельного пользователя для большей безопасности:

RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser

Фиксируйте версии образов

Вместо nginx:latest пишите nginx:1.25.3. Это обеспечивает воспроизводимость сборки и защищает от неожиданных изменений.

Multi-stage builds для минимизации размера

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

# Stage 1: Сборка
FROM node:20 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# Stage 2: Продакшн образ
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
CMD ["node", "dist/main.js"]

Healthcheck для критических сервисов

Без healthcheck Compose считает контейнер готовым сразу после старта. С базами данных это проблема: PostgreSQL может быть запущен, но ещё не готов принимать подключения.

healthcheck:
  test: ["CMD-SHELL", "pg_isready -U postgres"]
  interval: 10s
  timeout: 5s
  retries: 5

Заключение

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

Docker Compose решает проблему управления несколькими контейнерами: весь стек описывается в одном YAML-файле и поднимается одной командой. Это стандарт де-факто для локальной разработки, CI/CD и небольших продакшн-окружений.

Вместе они формируют базу современного DevOps-подхода — infrastructure as code, воспроизводимые среды и быстрый цикл разработки.

Оцените статью
IT-Sierra