Написано: 11.01.2023

Часть 8. Применение Docker Compose

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

Большое преимущество использования Compose заключается в том, что можно определить свой стек приложений в файле, сохранить его в корневом каталоге вашего проекта (теперь он контролируется версиями) и легко разрешить кому-либо другому вносить свой вклад в проект. Кому-то нужно будет только клонировать ваше репозиторий и запустить приложение compose. На самом деле, вы можете увидеть довольно много проектов на GitHub/GitLab, которые сейчас делают именно это.

Итак, с чего мы начнем?

Установка Docker Compose

Если вы установили Docker Desktop/Toolbox для Windows или Mac, у вас уже есть Docker Compose! В экземплярах Play-with-Docker также уже установлен Docker Compose. Если вы находитесь на компьютере с Linux, вам нужно будет установить Docker Compose.

После установки вы должны иметь возможность запустить следующее и просмотреть информацию о версии.

docker compose version

Создание файла Compose

1. В корне проекта приложения создайте файл с именем docker-compose.yml.

2. В файле compose мы начнем с определения списка служб (или контейнеров), которые мы хотим запустить как часть нашего приложения.

services:

А теперь мы начнем переносить службу по очереди в файл compose.

Определение app-службы

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

docker run -dp 3000:3000 \
  -w /app -v "$(pwd):/app" \
  --network todo-app \
  -e MYSQL_HOST=mysql \
  -e MYSQL_USER=root \
  -e MYSQL_PASSWORD=secret \
  -e MYSQL_DB=todos \
  node:18-alpine \
  sh -c "yarn install && yarn run dev"

1. Во-первых, давайте определим службу и изображение для контейнера. Мы можем выбрать любое название для сервиса. Имя автоматически станет сетевым псевдонимом, который будет полезен при определении нашего сервиса MySQL.

services:
  app:
    image: node:18-alpine

2. Как правило, вы увидите command рядом с определением image, хотя никаких требований к порядку нет. Итак, давайте продолжим и перенесем это в наш файл.

services:
  app:
    image: node:18-alpine
    command: sh -c "yarn install && yarn run dev"

3. Давайте перенесем часть команды -p 3000:3000, определив порты для службы. Здесь мы будем использовать краткий синтаксис, но доступен и более подробный.

services:
  app:
    image: node:18-alpine
    command: sh -c "yarn install && yarn run dev"
    ports:
      - 3000:3000

4. Далее мы перенесем как рабочий каталог (-w /app), так и сопоставление томов (-v "$(pwd):/app"), используя определения working_dir и volumes. Тома также имеют короткий и длинный синтаксис.

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

services:
  app:
    image: node:18-alpine
    command: sh -c "yarn install && yarn run dev"
    ports:
      - 3000:3000
    working_dir: /app
    volumes:
      - ./:/app

5. Наконец, нам нужно перенести определения переменных среды, используя ключ environment.

services:
  app:
    image: node:18-alpine
    command: sh -c "yarn install && yarn run dev"
    ports:
      - 3000:3000
    working_dir: /app
    volumes:
      - ./:/app
    environment:
      MYSQL_HOST: mysql
      MYSQL_USER: root
      MYSQL_PASSWORD: secret
      MYSQL_DB: todos

Определение сервиса для MySQL

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

docker run -d \
  --network todo-app --network-alias mysql \
  -v todo-mysql-data:/var/lib/mysql \
  -e MYSQL_ROOT_PASSWORD=secret \
  -e MYSQL_DATABASE=todos \
  mysql:8.0

1. Сначала мы определим новую службу и назовем ее mysql, чтобы она автоматически получала сетевой псевдоним. Мы пойдем дальше и также укажем изображение для использования.

services:
  app:
    # The app service definition
  mysql:
    image: mysql:8.0

2. Далее мы определим сопоставление томов. Когда мы запустили контейнер с помощью docker run, именованный том был создан автоматически. Однако этого не происходит при запуске с помощью Compose. Нам нужно определить том в разделе тома верхнего уровня:, а затем указать точку монтирования в конфигурации службы. При простом указании только имени тома используются параметры по умолчанию. Однако есть еще много доступных вариантов.

services:
  app:
    # The app service definition
  mysql:
    image: mysql:8.0
    volumes:
      - todo-mysql-data:/var/lib/mysql

volumes:
  todo-mysql-data:

3. Наконец, нам нужно только указать переменные среды

services:
  app:
    # The app service definition
  mysql:
    image: mysql:8.0
    volumes:
      - todo-mysql-data:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: secret
      MYSQL_DATABASE: todos

volumes:
  todo-mysql-data:

На этом этапе наш полный docker-compose.yml должен выглядеть следующим образом:

services:
  app:
    image: node:18-alpine
    command: sh -c "yarn install && yarn run dev"
    ports:
      - 3000:3000
    working_dir: /app
    volumes:
      - ./:/app
    environment:
      MYSQL_HOST: mysql
      MYSQL_USER: root
      MYSQL_PASSWORD: secret
      MYSQL_DB: todos

  mysql:
    image: mysql:8.0
    volumes:
      - todo-mysql-data:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: secret
      MYSQL_DATABASE: todos

volumes:
  todo-mysql-data:

Запуск нескольких приложений

Теперь, когда у нас есть наш файл docker-compose.yml, можем его запустить!

1. Убедитесь, что никакие другие копии приложения / базы данных первоначально не запущены (docker ps и docker rm -f <ids>).

2. Запустите стек приложений с помощью команды docker compose up. Мы добавим флаг -d, чтобы запускать все в фоновом режиме.

docker compose up -d

Когда мы запустим это, мы должны увидеть вывод, наподобие этого:

Creating network "app_default" with the default driver
Creating volume "app_todo-mysql-data" with default driver
Creating app_app_1   ... done
Creating app_mysql_1 ... done

Вы заметите, что том был создан так же, как и сеть! По умолчанию Docker Compose автоматически создает сеть специально для стека приложений (именно поэтому мы не определили ее в файле compose).

3. Давайте посмотрим на журналы с помощью команды docker compose logs -f. Вы увидите журналы из каждой службы, чередующиеся в один поток. Это невероятно полезно, когда вы хотите следить за проблемами, связанными со временем. Флаг -f “следует” за журналом, поэтому выдаст вам вывод в реальном времени по мере его создания.

Если вы уже выполнили команду, вы увидите вывод, который выглядит следующим образом:

mysql_1  | 2019-10-03T03:07:16.083639Z 0 [Note] mysqld: ready for connections.
 mysql_1  | Version: '8.0.31'  socket: '/var/run/mysqld/mysqld.sock'  port: 3306  MySQL Community Server (GPL)
 app_1    | Connected to mysql db at host mysql
 app_1    | Listening on port 3000

Название службы отображается в начале строки (часто цветное), чтобы помочь различать сообщения. Если вы хотите просмотреть журналы для определенной службы, вы можете добавить название службы в конец команды logs (например, docker compose logs -f app).

Совет: Ожидание базы данных перед запуском приложения
Когда приложение запускается, оно фактически сидит и ждет, пока MySQL будет запущен и готов, прежде чем пытаться подключиться к нему. Docker не имеет встроенной поддержки для ожидания полной загрузки, запуска и готовности другого контейнера перед запуском другого контейнера. Для проектов, основанных на Node.js, вы можете использовать зависимость wait-port. Аналогичные проекты существуют для других языков /фреймворков.

4. На этом этапе вы должны иметь возможность открыть свое приложение и увидеть, что оно запущено. И эй! Всё сводится к одной команде!

Просмотр стека приложений в Docker Dashboard

Если мы посмотрим на панель управления Docker, то увидим, что там есть группа с именем app. Это “название проекта” из Docker Compose, которое используется для группировки контейнеров вместе. По умолчанию имя проекта – это просто имя каталога, в котором находился docker-compose.yml.

Fig8-1

Если вы прокрутите приложение вниз, вы увидите два контейнера, которые мы определили в файле compose. Имена также немного более описательны, поскольку они следуют шаблону <имя службы>-<номер реплики>. Таким образом, очень легко быстро увидеть, какой контейнер является нашим приложением, а какой – базой данных mysql.

Fig8-2

Разрушение всех приложений

Когда вы будете готовы удалить все это, просто запустите docker compose down или нажмите на корзину на панели инструментов Docker для всего приложения. Контейнеры остановятся, и сеть будет удалена.

Предупреждение
Удаление томов
По умолчанию именованные тома в вашем файле compose не удаляются при запуске docker compose down. Если вы хотите удалить тома, вам нужно будет добавить флаг --volumes.
Панель управления Docker не удаляет тома при удалении стека приложений.

После завершения работы вы можете переключиться на другой проект, запустить docker compose up и быть готовым внести свой вклад в этот проект! На самом деле, немногое может быть проще этого!

Следующие шаги

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

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