docker-compose
docker-compose
Docker Compose — это инструмент для определения и запуска многоконтейнерных приложений в среде Docker. Инструмент позволяет описать конфигурацию всего приложения, включая все необходимые контейнеры, сети, тома и переменные окружения, в одном текстовом файле формата YAML.
Технически Docker Compose является утилитой командной строки, которая читает файл конфигурации docker-compose.yml или docker-compose.yaml, интерпретирует его содержимое и выполняет соответствующие команды для создания инфраструктуры. Утилита связывает отдельные контейнеры в единую сеть, монтирует общие диски и управляет их жизненным циклом как единым блоком.
Основная цель использования инструмента заключается в устранении необходимости выполнять множество разрозненных команд docker run вручную. Разработчик получает возможность запускать сложную систему из нескольких сервисов одной командой. Это обеспечивает воспроизводимость среды на любых машинах, где установлен Docker Engine.
Система управления версиями Git хранит файл конфигурации вместе с исходным кодом проекта. Любой член команды может получить актуальную версию репозитория и запустить полную среду разработки локально. Операторы используют этот подход для развертывания приложений на серверах или в облачных средах.
Файл конфигурации определяет три основных уровня абстракции:
- Сервисы — описание каждого контейнера, образа, портов и зависимостей;
- Сети — логическая изоляция и связь между контейнерами;
- Тома — управление постоянными данными и их хранение вне контейнеров.
Компонент поддерживает функции масштабирования количества экземпляров сервиса, перезапуска упавших процессов и автоматического обновления образов при наличии новых версий.
Архитектура работы инструмента
Работа Docker Compose базируется на парсинге декларативного файла конфигурации. Пользователь описывает желаемое состояние системы, а утилита приводит реальное состояние хоста к этому описанию. Процесс запуска включает несколько последовательных этапов.
Первым шагом происходит чтение файла docker-compose.yml. Утилита проверяет синтаксис документа и структуру данных. Формат YAML требует строгого соблюдения отступов, так как они определяют иерархию элементов. Любая ошибка в отступах приведет к невозможности запуска.
После валидации конфигурации система анализирует зависимости между сервисами. Если один сервис зависит от другого, например, база данных должна быть доступна перед запуском веб-приложения, Compose учитывает эти связи. Однако прямая зависимость по времени старта не гарантирует мгновенную готовность базы данных. Для решения этой проблемы используются механизмы ожидания или специальные скрипты внутри контейнеров.
Далее утилита создает необходимые сетевые интерфейсы. По умолчанию каждый проект (категория папок с файлом compose) получает собственную виртуальную сеть. Контейнеры подключаются к этой сети автоматически, если не указано иное. Внутри этой сети сервисы могут обращаться друг к другу по именам сервисов, определенным в файле конфигурации.
Следующим этапом идет создание томов. Тонкие слои хранения данных создаются либо системой управления Docker, либо пользовательскими драйверами. Тома сохраняют данные даже после удаления контейнеров. Это критически важно для баз данных и других систем, требующих сохранения состояния.
Затем начинается процесс запуска контейнеров. Команда up инициирует сборку образов, если они отсутствуют локально, и затем создает контейнеры согласно описанию. Каждый контейнер получает уникальный идентификатор и имя, основанное на имени сервиса и номера экземпляра.
Управление ресурсами осуществляется через ограничения CPU и памяти, которые можно задать в конфигурации. Система распределяет доступные ресурсы хоста между активными контейнерами. При исчерпании ресурсов операционная система может ограничить работу процесса.
Завершение работы также управляется централизованно. Команда down останавливает все контейнеры проекта, удаляет созданные сети и тома (опционально). Это позволяет быстро очистить среду тестирования без ручного вмешательства.
Структура файла конфигурации
Файл конфигурации представляет собой набор ключей и значений, организованных в иерархическую структуру. Корневой элемент содержит раздел services, который является обязательным. В нем перечисляются все компоненты приложения.
Каждый сервис определяется своим именем и набором параметров. Параметры задают поведение контейнера и его взаимодействие с внешней средой. Основные параметры включают образ, команду запуска, переменные окружения и правила проброса портов.
Пример структуры файла:
version: '3.8'
services:
web:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./html:/usr/share/nginx/html
db:
image: postgres:15
environment:
POSTGRES_USER: admin
POSTGRES_PASSWORD: secret
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:
Параметр image указывает на используемый образ. Значение может содержать имя образа и тег версии. Если тег не указан, система использует тег latest. Образ загружается из реестра Docker Hub или локального хранилища.
Параметр ports определяет правила трансляции портов. Формат записи host_port:container_port означает, что запросы, пришедшие на порт хоста, будут перенаправлены в контейнер. Использование протоколов TCP и UDP возможно через указание суффикса.
Параметр environment задает переменные окружения внутри контейнера. Эти переменные доступны приложению во время выполнения. Они позволяют изменять поведение программы без пересборки образа. Значения могут быть строками, числами или булевыми значениями.
Параметр volumes связывает файловые пути хоста с директориями внутри контейнера. Синтаксис host_path:container_path определяет точку монтирования. Типы путей могут быть абсолютными путями на хосте или именами томов, определенных в секции volumes.
Секция networks позволяет создавать пользовательские сети. Это дает возможность изолировать часть сервисов от остальной системы или создать сложную топологию взаимодействия. Сети могут иметь разные драйверы, такие как bridge, host или overlay.
Секция depends_on объявляет зависимости между сервисами. Команда up запустит зависимые сервисы первыми. Важно помнить, что наличие зависимости не означает ожидание полной готовности сервиса. Приложение должно самостоятельно проверять доступность зависимых компонентов.
Секция restart определяет политику перезапуска контейнера. Возможные значения: no, always, on-failure, unless-stopped. Политика always гарантирует, что контейнер будет запущен сразу после остановки или сбоя системы.
Управление жизненным циклом
Утилита предоставляет набор команд для управления состоянием системы. Каждая команда выполняет конкретный набор операций над сервисами проекта.
Команда up запускает приложение. Опция -d запускает процессы в фоновом режиме (detached mode), позволяя продолжать работу в терминале. Без этой опции вывод логов всех сервисов отображается в консоли в реальном времени. Параметр --build заставляет пересобрать образы перед запуском, игнорируя кэш.
Команда down останавливает и удаляет контейнеры, сети и тома, созданные текущим проектом. Параметр --volumes дополнительно удаляет тома, содержащие данные. Это действие необратимо и приводит к потере сохраненных данных.
Команда ps выводит список активных контейнеров проекта. Вывод содержит информацию об имени, статусе, открытых портах и количестве созданных экземпляров. Это полезный инструмент для быстрой проверки текущего состояния системы.
Команда logs отображает выходные данные (логи) одного или всех сервисов. Опция -f позволяет следить за логами в режиме реального времени, аналогично команде tail -f. Параметр --tail N показывает только последние N строк лога.
Команда exec запускает новую команду внутри работающего контейнера. Синтаксис exec service_name command позволяет выполнить консольную команду, например, проверку конфигурации или запуск отладчика. Это эквивалентно выполнению docker exec для конкретного контейнера.
Команда stop останавливает работающие контейнеры проекта, но сохраняет их состояние. Контейнеры можно перезапустить позже командой start. Это полезно для временной паузы работы системы без удаления ресурсов.
Команда kill принудительно завершает работу контейнеров, отправляя сигнал SIGKILL. Этот метод используется, когда стандартная остановка не работает или требуется немедленное прекращение работы.
Команда config проверяет корректность файла конфигурации и выводит его в нормализованном виде. Эта функция помогает выявить ошибки синтаксиса или несовместимости параметров перед запуском.
Команда build собирает образы для сервисов, указанных в файле. Параметр --parallel позволяет собирать несколько образов одновременно, ускоряя процесс. После сборки образы становятся доступны для запуска.
Команда pull скачивает образы из удаленного реестра без создания контейнеров. Это полезно для предварительной загрузки необходимых компонентов в среду, где нет доступа к интернету во время деплоя.
Команда pause ставит все контейнеры проекта на паузу, замораживая их выполнение. Команда unpause возобновляет работу. Это позволяет временно остановить обработку данных без остановки самих процессов.
Работа с сетью и связностью
Встроенная сеть Docker Compose обеспечивает автоматическое подключение всех сервисов проекта к общему мосту. Сервисы получают возможность общаться друг с другом по именам, указанным в конфигурации.
Механизм DNS встроен в сетевой стек Docker. Каждому контейнеру присваивается имя, равное имени сервиса. Веб-сервис может обратиться к базе данных по адресу db вместо IP-адреса. Это упрощает конфигурацию приложений и делает их независимыми от динамических адресов.
Для создания изолированных сетей используется секция networks. Можно определить несколько сетей с разными настройками безопасности и доступности. Сервисы подключаются к нужным сетям через параметр networks внутри определения сервиса.
Драйверы сетей определяют способ взаимодействия. Драйвер bridge создает изолированную сеть для проекта. Драйвер host позволяет контейнерам использовать сетевой стек хоста напрямую. Драйвер overlay используется в кластерах Swarm для связи контейнеров на разных узлах.
Правила проброса портов (ports) делают сервисы доступными извне. Порт хоста мапится на порт контейнера. Внешние клиенты обращаются к публичному порту, а Docker перенаправляет трафик внутрь контейнера.
Параметр expose открывает порт только для внутренних сервисов проекта. Этот порт не доступен извне хоста, но доступен другим контейнерам в той же сети. Это повышает безопасность, скрывая внутренние сервисы от прямого доступа.
Настройка links устарела и не рекомендуется к использованию. Она была заменена встроенной системой DNS и автоматической сетью. Использование ссылок усложняет конфигурацию и снижает производительность.
Конфигурация прокси-серверов возможна через параметры http_proxy и https_proxy в переменной окружения. Это позволяет контейнерам выходить в интернет через корпоративный шлюз.
Управление данными и томами
Сохранение данных в контейнерах требует использования томов. Данные внутри контейнера исчезают при его удалении. Тома хранят файлы на диске хоста или в управляемом хранилище.
Секция volumes в корне файла определяет имена томов. Эти тома создаются автоматически при первом использовании. Docker управляет их расположением и правами доступа.
Типы томов:
- Bind mounts — привязка конкретной директории хоста к контейнеру. Используется путь вида
/path/on/host:/path/in/container. Подходит для разработки, когда нужно видеть изменения кода в реальном времени. - Named volumes — тома с уникальным именем. Используются для хранения данных баз данных, логи и других важных файлов. Данные сохраняются независимо от жизненного цикла контейнера.
- Tmpfs mounts — временные тома, хранящиеся в оперативной памяти хоста. Не подходят для больших объемов данных, но обеспечивают высокую скорость.
Права доступа к томам регулируются параметром user в сервисе. Контейнер может запускаться под определенным пользователем или группой. Это предотвращает проблемы с правами чтения/записи файлов.
Шифрование данных в томах возможно через внешние драйверы или настройки Docker Security. Стандартные тома не шифруются автоматически.
Резервное копирование данных осуществляется через команду run с образом busybox и утилитой tar. Данные экспортируются в архив на хосте. Восстановление выполняется распаковкой архива в том.
Переменные окружения и секреты
Переменные окружения передают конфигурационные данные в контейнеры. Они заменяют необходимость хардкодить значения в коде или образах.
Параметр environment в сервисе задает статические значения.
environment:
DB_HOST: localhost
DEBUG: "true"
Подстановка значений из внешнего файла .env осуществляется автоматически. Файл должен находиться в той же директории, что и docker-compose.yml. Команда docker-compose up считывает переменные из этого файла.
Синтаксис подстановки ${VARIABLE_NAME} позволяет использовать значения из файла окружения или переменных ОС. Если переменная не найдена, используется значение по умолчанию ${VARIABLE_NAME:-default_value}.
Секретность данных обеспечивается через использование файлов секретов. Параметр secrets ссылается на файлы с паролями или ключами. Эти файлы монтируются в контейнер в защищенной области памяти.
Файлы секретов хранятся в отдельной директории и не должны попадать в репозиторий кода. Доступ к ним контролируется правами доступа операционной системы.
Приложение получает доступ к секрету через специальный путь внутри контейнера. Это позволяет хранить чувствительные данные вне конфигурационного файла.
Масштабирование и оркестрация
Команда up --scale service_name=number запускает несколько экземпляров одного сервиса. Каждый экземпляр получает уникальный номер в имени. Например, web-1, web-2.
Распределение нагрузки между экземплярами осуществляется балансировщиком. В локальной среде это может быть встроенный механизм Docker или внешний балансировщик.
Параметр deploy.replicas в формате версии 3.x позволяет задать количество реплик для сервиса. Это используется в режиме Swarm Mode, но также поддерживается в некоторых сценариях Compose.
Автомасштабирование требует внешних инструментов или скриптов. Сам по себе Compose не отслеживает нагрузку и не добавляет новые экземпляры динамически.
Безопасность и лучшие практики
Использование фиксированных версий образов (nginx:1.24-alpine) вместо тега latest гарантирует стабильность среды. Обновления происходят контролируемо после тестирования.
Отказ от запуска контейнеров с правами root повышает безопасность. Параметр user: 1000:1000 запускает приложение под обычным пользователем.
Ограничение ресурсов через cpus и memory предотвращает перегрузку хоста одним сервисом.
Регулярное обновление образов защищает от уязвимостей. Инструменты типа dependabot или renovatebot могут автоматически обновлять зависимости.
Изоляция проектов достигается путем размещения файлов docker-compose.yml в отдельных папках. Каждый проект получает свою сеть и пространство имен.
Избегание хардкода чувствительных данных в файле конфигурации обязательно. Использование .env файлов и секретов является стандартом.
Пример комплексной конфигурации
Ниже представлен пример конфигурации типичного веб-приложения с базой данных и кешированием.
version: '3.8'
services:
app:
build: .
ports:
- "3000:3000"
environment:
NODE_ENV: production
DB_HOST: db
REDIS_HOST: redis
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
networks:
- frontend
restart: unless-stopped
db:
image: postgres:15
environment:
POSTGRES_DB: myapp
POSTGRES_USER: user
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
volumes:
- pg_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U user"]
interval: 10s
timeout: 5s
retries: 5
networks:
- frontend
restart: unless-stopped
redis:
image: redis:7-alpine
volumes:
- redis_data:/data
networks:
- frontend
restart: unless-stopped
networks:
frontend:
driver: bridge
volumes:
pg_data:
redis_data:
secrets:
db_password:
file: ./secrets/db_pass.txt
В этом примере:
- Приложение
appзависит от здоровья базы данных. Запуск продолжится только после успешной проверкиhealthcheck. - Пароль базы данных хранится в файле секрета, а не в переменной окружения.
- Базы данных и Redis используют тома для сохранения данных.
- Все сервисы находятся в общей сети
frontend. - Политики перезапуска настроены на автоматический старт после сбоя или перезагрузки системы.
Диагностика и отладка
При возникновении проблем с запуском используйте команду docker-compose config для проверки файла. Ошибки синтаксиса часто становятся причиной неудач.
Логи каждого сервиса доступны через docker-compose logs <service_name>. Анализ логов помогает найти причины падения приложений.
Проверка состояния контейнеров выполняется командой docker-compose ps. Статус Exited указывает на проблему с запуском или работой.
Команда docker-compose exec <service> sh позволяет войти в оболочку контейнера для ручной диагностики.
Сетевые проблемы можно проверить через ping или curl внутри контейнера. Команда docker-compose run --rm app ping db тестирует связность.
Очистка старых ресурсов выполняется командой docker-compose down -v. Это удаляет тома и сети, освобождая место.
Интеграция в CI/CD
В системах непрерывной интеграции Docker Compose используется для запуска тестов в изолированной среде. Пайплайн выполняет команду docker-compose up --build перед запуском тестов.
После завершения тестов среда очищается командой docker-compose down. Это гарантирует чистоту следующего запуска.
Использование параллельной сборки (--parallel) ускоряет процесс в конвейерах.