Тариф успешно добавлен в корзину
В корзину
url image

Работа с контейнерами в Docker Compose

В статье расскажем, что такое Docker Compose, какие задачи он решает и как используется на практике. Рассмотрим структуру конфигурационного файла, основные команды и пример развёртывания.

Что такое Docker Compose

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

Зачем нужен Docker Compose

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

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

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

Однако следует учитывать, что Docker Compose используется для управления контейнерами на одном сервере. Для управления контейнерами в распределённых кластерах применяются системы оркестрации.

Когда использовать Docker Compose 

Приведем наиболее распространённые сценарии использования инструмента: 

  • Разработка и развёртывание многоконтейнерных приложений. Docker Compose позволяет описать все компоненты приложения в одном compose-файле и управлять ими как единым целым. После описания конфигурации всю инфраструктуру можно запустить, остановить или пересоздать одной командой.
  • Развёртывание локальной среды разработки. Разработчику не нужно самостоятельно устанавливать и настраивать базы данных, брокеры сообщений, системы кэширования и другие сервисы. Их конфигурация описана в compose-файле, который хранится в репозитории проекта и используется всеми участниками команды. Окружение разворачивается автоматически с помощью Docker Compose. Использование такого подхода позволяет:
    • обеспечить одинаковую конфигурацию среды у всех разработчиков;
    • быстро развернуть рабочее окружение проекта;
    • избежать конфликтов версий программного обеспечения и зависимостей.
  • Тестирование приложений. В процессе тестов можно запускать полный стек приложения. После завершения тестирования всю среду легко удалить и получить чистое окружение.
  • Развёртывание демонстрационной среды. Docker Compose удобно применять для демонстраций, учебных проектов и лабораторных работ, так как он помогает быстро развернуть заранее подготовленное окружение одной командой.
  • Запуск сервисов для экспериментов. Инструмент позволяет разворачивать и удалять различные сервисы, не засоряя основную систему.

Установка

Для работы с Docker Compose необходимо установить Docker Engine и плагин Docker Compose CLI. Начиная с версии Docker 20.10 Compose поставляется как плагин к Docker Engine.

Установить Docker Engine и Docker Compose вам поможет статья.

Проверка установки:

docker --version
docker compose version

Структура compose.yaml — основные разделы

Инфраструктура проекта описывается в файле compose.yaml, который размещается в рабочей директории проекта. В более ранних версиях также использовались имена docker-compose.yaml или docker-compose.yml. Файл использует формат YAML и содержит декларативное описание сервисов, сетей и томов. Важно соблюдать синтаксис YAML: структура файла определяется отступами, и ошибка в форматировании может привести к невозможности запуска проекта.

Для проверки корректности compose-файла используется команда:

docker compose config --quiet

Если файл некорректный, команда выведет ошибку с точной строкой. Если ошибок нет — вывод будет пустой.

Ключевые разделы:

  • services — описание контейнеров;
  • volumes — именованные тома;
  • networks — пользовательские сети.

Формально, раздел services является единственным обязательным разделом верхнего уровня.

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

Сначала рассмотрим минимальный пример использования Compose, а затем перейдём к более сложной конфигурации. Опишем сервис Nginx в compose-файле и запустим его:

  1. В директории проекта создадим файл compose.yml:
services:
 nginx:
   image: nginx
   ports:
     - "8080:80"
  1. Введём команду: 
docker compose up -d

Compose выполнит следующие действия:

  • скачает образ nginx;

  • создаст контейнер;

  • пробросит порт 8080 на 80;

  • запустит контейнер.

Запуск контейнеров проекта

В результате nginx будет запущен на 8080 порту хоста.

Если порт 8080 на хосте занят другим приложением, то контейнер не запустится (несмотря на то, что предыдущие этапы прошли корректно) и compose выведет ошибку:

Ошибка при запуске контейнеров

С помощью параметра include можно использовать дополнительные compose-файлы:

compose.yaml:
services:
  web:
    image: nginx
    ports:
      - "80:80"
include:
  - database.yaml
database.yaml:
services:
  db:
    image: postgres:15

Рассмотрим реальный пример конфигурации и запуска многоконтейнерного приложения — Nginx — сайт на WordPress — MySQL:

version: "3.9"
services:
  nginx:
    image: nginx:stable
    container_name: nginx_proxy
    restart: unless-stopped
    ports:
      - "80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - wp_data:/var/www/html
    depends_on:
      - wordpress
    networks:
      - frontend
      - backend

wordpress:
  image: wordpress:php8.2-fpm
  container_name: wordpress_app
  restart: unless-stopped
  environment:
    WORDPRESS_DB_HOST: db:3306
    WORDPRESS_DB_USER: wp_user
    WORDPRESS_DB_PASSWORD: strong_password
    WORDPRESS_DB_NAME: wordpress
  volumes:
    - wp_data:/var/www/html
  depends_on:
    - db
  networks:
    - backend

db:
  image: mysql:8.0
  container_name: mysql_db
  restart: unless-stopped
  environment:
    MYSQL_DATABASE: wordpress
    MYSQL_USER: wp_user
    MYSQL_PASSWORD: strong_password
    MYSQL_ROOT_PASSWORD: root_password
  volumes:
    - db_data:/var/lib/mysql
  networks:
    - backend

volumes:
  wp_data:
  db_data:

networks:
  frontend:
  backend:
    internal: true

В начале compose-файла часто можно увидеть поле version. В современных версиях Docker Compose поле version больше не используется и игнорируется. Оно сохраняется только для совместимости со старыми версиями Compose.

Имя проекта может быть задано параметром name. Если параметр не задан, то в качестве имени проекта используется имя директории, в которой находится compose-файл.

Имя проекта

Services (сервисы)

В данном разделе описываем сервисы приложения и их параметры. При запуске Docker Compose для каждого сервиса создаётся отдельный контейнер. Полный список атрибутов данного раздела приведен в официальной документации.

Основные атрибуты:

  • image — определяет образ из которого запускается контейнер. В нашем примере образы nginx, wordpress, mysql будут загружены из репозитория docker.
  • build — задаёт параметры сборки образа, включая контекст сборки (директорию с файлами, используемыми при сборке) и путь к Dockerfile.

При наличии обоих атрибутов image и build образ будет собран из dockerfile, указанного в build.собранный образ получит тег, прописанный в image.

Например,  

services:
  app:
    build: ./app
    image: myapp:1.0

Образ будет собран из dockerfile, который расположен в поддиректории проекта app и ему будет присвоен тег myapp:1.0

Фактически, выполняется:

docker build -t myapp:1.0 ./app
  • command — задаёт команду, которая будет выполнена при запуске контейнера. Если указан данный атрибут, он переопределяет команду по умолчанию (CMD) из Dockerfile:
services:
  app:
    image: nginx
    command: ["-g", "daemon off;"]
  • entrypoint — задаёт основной исполняемый процесс контейнера. Если указан, переопределяет ENTRYPOINT из Dockerfile:
services:
  app:
    image: nginx
    entrypoint: ["nginx"]
  • container_name — задаёт имя контейнера. В нашем примере поле используется для наглядности, но в большинстве случаев container_name не рекомендуется использовать, так как Docker Compose автоматически генерирует уникальные имена контейнеров.
  • restart — определяет политику перезагрузки контейнера:
    • no — контейнер не перезапускается ни при каких обстоятельствах.
    • always —  контейнер перезапускается всегда: при падении, при ручной остановке Docker daemon, после перезагрузки сервера.
    • on-failure —  контейнер перезапускается только при завершении с ошибкой (exit code ≠ 0).
    • unless-stopped — контейнер перезапускается при падении, после перезагрузки сервера, но не будет перезапущен при ручной остановке.
  • ports — проброс портов контейнера на хост. Левая часть относится к хосту, правая — к контейнеру.

Например:

ports:
      - "80:8080"

Порт 80 на хосте будет соответствовать 8080 порту в контейнере.

В нашем примере 80 порт контейнера nginx соответствует 80 порту на хосте.

  • environment — определяет переменные окружения, которые используются в контейнере.
  • env_file — указывает путь к файлу с переменными окружения. Можно задать несколько файлов.
env_file:
  - .env
  - db.env

В .env файле переменные записываются в формате ключ=значение:

APP_NAME=web_service
APP_PORT=80

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

Если заданы оба атрибута environment и env_file, переменные из environment имеют более высокий приоритет.

  • volumes — подключает хранилище данных к контейнеру. В качестве источника могут использоваться:
    • bind mount (директория или файл на хосте);
    • именованный том (Docker volume);
    • временная файловая система (tmpfs).
  • networks — определяет сети, к которым подключен контейнер.
  • depends_on — устанавливает порядок запуска контейнеров. В нашем примере сервис nginx зависит от wordpress, а wordpress — от db. Сначала будет запущен сервис db, потом wordpress, потом nginx.

Volumes (тома)

Контейнер — это временная сущность, он может быть удален или пересоздан.

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

Использование томов решает несколько задач:

  • сохраняет данные между перезапусками контейнера;
  • позволяет разным контейнерам совместно использовать данные;
  • позволяет хранить данные вне контейнера;
  • упрощает резервное копирование и миграцию данных.

Важно не путать! В разделе services используется атрибут volumes.

Следует различать:

  • раздел верхнего уровня volumes — объявляет тома.
  • атрибут volumes внутри services — подключает их к контейнерам.

В нашем примере в разделе верхнего уровня volumes мы объявляем два именованных тома wp_data и db_data

volumes:
  wp_data:
  db_data:

Docker сам создаёт именованные тома и управляет ими, а доступ к ним осуществляется по имени, а не через путь в файловой системе.

Именованные тома хранятся на хосте в директории /var/lib/docker/volumes/ (для Linux):

Именованные тома

Имена директорий томов имеют вид <project>_<volume>. В нашем случае compose_db_data и compose_wp_data

Том wp_data подключен к контейнеру wordpress. Внутри контейнера данный том расположен по пути /var/www/html

volumes:
  - wp_data:/var/www/html

Том wp_data подключен также к контейнеру nginx:

volumes:
  - ./nginx.conf:/etc/nginx/nginx.conf:ro
  - wp_data:/var/www/html

Здесь:

  • wp_data — именованный том.
  • ./nginx.conf:/etc/nginx/nginx.conf:ro — bind mount.

Bind mount — это способ подключения файлов или директорий с хоста напрямую в контейнер.

В примере файл nginx.conf из директории проекта монтируется в контейнер по пути /etc/nginx/nginx.conf. Параметр ro означает, что файл доступен только для чтения.

Можно также подключать контейнеры к уже существующему тому, созданному ранее в другом compose-проекте или с помощью docker volume create. Для этого используется атрибут external: true

volumes:
  data:	
    external: true

Подробнее об использовании томов в Docker Compose вы можете прочитать в статье документации. Об общих принципах работы томов рассказали в нашей статье.

Networks (сети)

Сети в Docker обеспечивают взаимодействие между контейнерами, позволяют изолировать сервисы и запускать несколько идентичных compose-проектов без конфликтов.

Тип сети можно указать через необязательный атрибут driver. Основные типы сетей:

  • bridge — самый распространенный тип. Каждый контейнер получает собственный внутренний IP-адрес, уникальный в рамках одной сети. Работает встроенный DNS — если сервисы находятся в одной сети, они могут обращаться друг к другу по имени сервиса. Контейнеры имеют доступ к внешней сети через механизм NAT.
  • host — контейнер работает напрямую через сеть хоста. В этом режиме проброс портов (ports) не используется, так как контейнер и хост фактически используют одну и ту же сеть.
  • none — контейнер запускается без сетевого подключения и не может взаимодействовать с другими контейнерами.

Если в compose-файле не указан раздел networks, Compose автоматически создаёт сеть <project>_default. Она является пользовательской сетью типа bridge. Все сервисы проекта, для которых явно не заданы другие сети, автоматически подключаются к данной сети.

Можно подключать контейнеры к уже существующей сети Docker с помощью атрибута external: true

networks:
  mynetwork:
    external: true

Это нужно, когда:

  • несколько compose-проектов должны общаться;
  • контейнер должен видеть сервисы вне compose.

Также можно создать сеть, изолированную от внешней сети с помощью атрибута internal:true

В нашем примере создаются две сети: frontend и backend.

Сервис nginx подключён к обеим сетям. Порт 80 проброшен на хост, поэтому nginx принимает запросы из внешней сети.

Сервисы nginx, wordpress и db подключены к сети backend, через которую они взаимодействуют друг с другом. Сеть изолирована от внешней сети (internal: true)

Разделение на сети frontend и backend позволяет отделить точку входа приложения (nginx) от внутренней инфраструктуры (wordpress и db).

В сервисе wordpress мы задаем переменную окружения WORDPRESS_DB_HOST, в значении которой ссылаемся на сервис db по имени сервиса: 

WORDPRESS_DB_HOST: db:3306

Подробнее об использовании сетей в Docker Compose вы можете прочитать в документации.

Запуск проекта

  1. Создайте директорию проекта, если она еще не создана, и перейдите в нее:
mkdir compose
cd compose
  1. Создайте файл compose.yaml и вставьте код.
  2. Создайте файл конфигурации nginx.conf
events {}
http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;
    server {
        listen 80;
        server_name _;
        root /var/www/html;
        index index.php index.html;
        location / {
            try_files $uri $uri/ /index.php?$args;
        }
        location ~ \.php$ {
            fastcgi_split_path_info ^(.+\.php)(/.+)$;
            fastcgi_pass wordpress:9000;
            fastcgi_index index.php;
            include fastcgi_params;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            fastcgi_param PATH_INFO $fastcgi_path_info;
        }
        location ~ /\.ht {
            deny all;
        }
    }
}
  1. Запустите проект
docker compose up -d
запуск проекта

Предупреждение WARN означает, что параметр version в файле compose.yml больше не используется в новых версиях Docker Compose.

Можем убедиться, что контейнеры запущены:

Вывод информации о контейнерах проекта

Введя IP-адрес сервера в строку браузера, видим начальную страницу установки WordPress:

страница установки WordPress

Команды docker compose

Создание и запуск контейнеров проекта:

docker compose up

Запуск контейнеров в фоновом режиме:

docker compose up -d

Запуск конкретного сервиса:

docker compose up -d db

Остановка проекта:

docker compose down

Запуск\остановка\перезапуск контейнеров проекта:

docker compose start
docker compose stop
docker compose restart
docker compose start <имя_сервиса>
docker compose stop <имя_сервиса>
docker compose restart <имя_сервиса>

Команда docker compose up используется для первичного запуска проекта. иОна выполняет несколько действий:

  • создаёт сеть проекта;
  • создаёт тома;
  • создаёт контейнеры;
  • скачивает образы (если их нет);
  • запускает контейнеры.

Если контейнеры уже существуют, Compose проверит конфигурацию и при необходимости пересоздаст контейнеры.

Команда docker compose start используется для запуска уже созданных контейнеров.

Пересоздание контейнеров принудительно, даже если их конфигурация и образ не изменились:

docker compose up --force-recreate

Вывести список контейнеров проекта:

docker compose ps -a

В отличие от docker ps -a будут выведены только контейнеры текущего проекта.

Вывод логов проекта:

docker compose logs

Вывод логов отдельного сервиса (db):

docker compose logs  db

Просмотр логов сервиса db в режиме реального времени

docker compose logs -f db

Вывод списка томов:

docker compose volumes

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

Минимализм

Compose-файл должен оставаться простым описанием инфраструктуры. Его не стоит перегружать сложной логикой или пытаться использовать как инструмент управления всей системой.

Не рекомендуется:

  • добавлять сложные скрипты запуска внутри command или entrypoint;
  • пытаться управлять порядком и состоянием сервисов через shell-скрипты;
  • использовать Compose для оркестрации сложных сценариев развертывания.

Например ожидание базы через цикл в command:

services:
  app:
    image: myapp
    command: >
      sh -c "
      until nc -z db 5432;
      do echo waiting for db;
      sleep 2;
      done;
      python app.py
      "

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

Использование .env

Используйте файл .env для хранения переменных окружения, которые могут отличаться в разных средах (разработка, тестирование, рабочая среда). Тогда при переносе проекта на другой сервер или в другую среду достаточно заменить файл .env — основная конфигурация compose.yaml останется прежней.

Явные версии образов

Для надёжности лучше использовать конкретные версии образов. Использование специальных тегов (latest, stable и т.д.) может привести к несовместимости с компонентами приложения из-за изменения версии образа. 

Разделение окружений

Используйте несколько compose-файлов. Это позволит разделить базовую инфраструктуру и настройки для отдельных сред.

Пример:

compose.yaml # базовая конфигурация
compose.dev.yaml # настройки для разработки
compose.prod.yaml # настройки для production

Относительные пути

При использовании bind mount рекомендуется указывать относительные пути вместо абсолютных. Это позволяет запускать проект на разных серверах без изменения конфигурации.

Этот материал был полезен?

Скидка новым клиентам
Закажите сервер сегодня и получите скидку на первый месяц аренды!
Наш сайт использует cookies Вы можете отключить их в настройках браузера, но это может ограничить функционал. Оставаясь на сайте, вы соглашаетесь с использованием cookies.