Знакомство с docker-compose
Следующим шагом после установки Docker, я считаю, должно быть знакомство в docker-compose. Почему? Потому что, чаще всего, вы используете не один контейнер для задачи (проекта), а несколько. Да и сама идея микро-сервисов диктует именно такой подход. Например для сайта на WordPress, по хорошему, вам потребуется минимум три контейнера: контейнер с web сервером – например nginx, контейнер с WordPress и контейнер с базой данных. Можно конечно собрать собственный большой контейнер, на базе какого-нибудь nix дистрибутива, поставить в него и сервер и базу данных и WordPress запихнуть, но это будет монстр, который будет неудобно обслуживать, который будет занимать лишнее место и который будет в корне противоречить идее микро-сервисов. А поэтому – разделяй и властвуй.
Итак, возвращаясь к примеру в web-сервером, нужно три контейнера. Отлично. Есть вариант запускать их все вручную, используя команды типа
$ docker run --name some-wordpress -e WORDPRESS_DB_HOST=10.1.2.3:3306\
-e WORDPRESS_DB_USER=... -e WORDPRESS_DB_PASSWORD=... -d wordpress
А еще не забывать про постоянное хранилище, для тех контейнеров, где нужно хранить данные между перезапусками
$ docker run --name some-mysql -v /my/custom:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag
Ну в общем не очень удобно, не очень наглядно, а самое главное – перенести это все на другой хост будет еще тем развлечением.
И в этом случае на помощь приходит docker-compose.
docker-compose – это удобный инструмент для работы с мульти-контейнерными проектами, входящий в состав docker и позволяющий запустить проект, создав описание контейнеров, входящий в него, в одном конфигурационном файле.
Ну и что бы не быть голословным: практический пример. Несколько упростим схему и предположим, что наш проект состоит всего из двух контейнеров: web-сервера и базы данных.
Для начала создадим новую директорию, назовём ее, например myProject. Название проекта docker-compose берет именно с названия директории, в которой расположен конфигурационный файл.
$ cd ~
$ mkdir myProject
$ cd myProject
Теперь нужно создать конфигурационный файл нашего проекта для docker-compose. Как ни странно, он называется docker-compose.yaml (можно использовать трехбуквенное расширение yml)
nano docker-compose.yaml
И вставляем в него такой код:
version: "3.7"
services:
web-server:
container_name: web-server
image: nginx:stable-alpine
restart: unless-stopped
depends_on:
- database
ports:
- 80:80
- 443:443
volumes:
- ./webserver:/var/www/html
database:
container_name: database
image: istitch07/mariadb-alpine-rpi:latest
restart: unless-stopped
volumes:
- ./database:/var/lib/mysql
env_file: .env
environment:
- MYSQL_DATABASE=WebDB
command: '--default-authentication-plugin=mysql_native_password'
Формат этого файла обычен для YAML разметки, для тех кто с ней не знаком – обращу внимание: все отступы делаются пробелами, использование табуляции не разрешается.
Да, важное: пример рассчитан на запуск на Raspberry Pi, то есть на процессоре с архитектурой arm/v7, если у вас другая архитектура процессора, вам потребуется использовать другой образ для базы данных.
Что в этом файле что: вначале идет описание версии файла конфигурации, в зависимости от версии может не быть доступны те или иные опции, чем больше версии, тем больше опций поддерживается, но следите за тем, что бы ваш docker-compose мог поддерживать эту версию. На данный момент самая актуальная версия: 3.8, поддерживается docker-compose начиная с версии 19.03.0.
Дальше идут описание сервисов, в нашем случае – контейнеров. Начинается с названия сервиса, например web-server:, а далее идет описание его конфигурации
Опция | Назначение |
---|---|
container_name: | Имя контейнера, может отличаться от имени сервиса |
image: | Какой образ использовать для контейнера. В случае отсутствия данного образа локально, будет произведена попытка скачать его с hub.docker.com (по умолчанию) |
restart: | Политика перезапуска контейнера после, например, перезагрузки. Допустимые значения:"no" – не перезапускать;always – перезапускать всегда;on-failure – перезапускать только при возникновении ошибки в контейнере;unless-stopped – перезапускать всегда, пока контейнер не будет остановлен вручную, например командой docker stop <имя контейнера> |
ports: | Какие порты следует пробросить в контейнер. Если для работы не требуется доступ к контейнеру извне докера – можно не пробрасывать, контейнеры внутри одного проекта и так могут обращаться к друг другу. |
volumes: | В случае если требуется хранить какие-либо данные между перезапусками контейнера, необходимо примапить хранилище с хостовой системы. Это может быть как внутреннее хранилище docker-а, так и конкретная папка на файловой системе, как в данном примере. |
depends_on: | Зависимости контейнера. В данном случае нам не имеет смысла поднимать веб сервер, пока не работает база данных, поэтому она указана в зависимостях этого контейнера. |
env_file: | Файл с переменными окружения. Для базы данных нужно задать пароли рута и пользователя базы, и имя этого пользователя. Это можно указать прямо в конфигурации, а можно вынести в отдельный файл. В данном случае я выношу это в файл .env |
environment: | Задать значение переменных окружения. |
command: | Перезапись команды по умолчанию. В моем примере мы передаем дополнительный аргумент –default-authentication-plugin=mysql_native_password |
Есть и другие опции, но для быстрого знакомства этих вполне будет достаточно. Есть есть желание изучить их подробнее – это можно сделать на официальном сайте docker.
Поскольку в конфиге я указал, что мне нужно хранить данные в локальных папках, то теперь требуется их создать. Создать их нужно по тому пути который указан в файле конфигурации, директория где он расположен является . для docker-compose. Поэтому создаем обе директории прямо внутри myProject
$ mkdir webserver database
Ну и осталось создать и наполнить файл .env
$ nano .env
MYSQL_ROOT_PASSWORD=RooTPassWord
MYSQL_USER=MySQLUser
MYSQL_PASSWORD=UserPassword
На этом мы закончили создавать наш проект и его уже можно запустить. По хорошему еще нужно положить файлы web-сервера в его директорию, но это уже будет выходить за рамки простого примера. Поэтому запускаем проект так. Проверяем, что находимся в папке, в которой лежит docker-compose.yaml и выполняем команды:
$ docker-compose pull
Эта команда говорит, что нам нужно скачать (или обновить уже имеющиеся) образы из репозитория. После того как образы скачены и установлены, можно из запускать:
$ docker-compose up -d
Этой командой мы говорим, что хотим запустить все контейнеры перечисленные в файле конфигурации и оставить их выполняться в фоне. Без ключа -d контейнер останется привязанным к консоли и будет завершен после нажатия клавиш CTRL-C
Проверить что все запустилось и работает можно как обычной командой докера $ docker ps
так и командой $ docker-compose ps
(да, на моих скриншотах папка проекта называется tests, пусть это вас не смущает)
Останавлить или перезапустить один контейнер так же можно как командой $ docker stop/restart <container name>
так и командой $ docker-compose stop/restart <container name>
А вот остановить все контейнеры входящие в один проект уже однозначно удобнее при помощи docker-compose: достаточно перейти в папку с его конфигурационным файлом и выполнить $ docker-compose stop
без параметров
И еще одно преимущество docker-compose – это переносимость. Для того что бы перенести проект на другую машину – достаточно всего лишь скопировать папку с проектом (при условии, что постоянное хранение организовано в локальные папки внутри директории проекта) и на новой машине так же выполнить pull и up в директории с проектом.
На этом пока все, чуть позже напишу как запустить проект умного дома при помощи docker-compose на примере моего.