Большинство современных программных систем имеют микросервисную архитектуру. Для стека микросервисных технологий Spring Cloud характерно содержание в прикладной системе нескольких прикладных микросервисов.
Перед запуском приложения необходимо запустить шлюз, центр регистрации, центр конфигурации, базу данных (даже при наличии внедренного в систему межплатформенного ПО, такого как Redis, RabbitMQ, системы управления логами ELK, системы визуализации Grafana и других сервисов).
При развертывании приложения с микросервисной архитектурой необходимо упаковать разработанный сервис Spring Boot в образ Docker, импортировать его в Docker, а затем запустить развертывание.
Межплатформенное ПО, база данных и другие сервисы также должны получить соответствующую версию образа из удаленного хранилища Docker для развертывания. Это довольно громоздкий процесс, занимающий много времени.
Уменьшить рабочую нагрузку позволяет использование Docker Compose — официального инструмента оркестрации контейнеров, предоставляемого компанией Docker.
Что такое оркестрация контейнеров?
Использование различных инструментов для автоматизации развертывания контейнеров, управления ими, адаптивного масштабирования, управления сетью и других функций — это и есть оркестрация контейнеров.
Всем известный Kubernetes (K8s) — продвинутый инструмент оркестрации контейнеров. Кроме него, широко используемыми инструментами оркестрации являются Docker Swarm и Docker Compose. Обе эти платформы — проекты официального инструмента оркестрации контейнеров Docker, однако роли их различны.
Docker Compose — это инструмент для определения и запуска многоконтейнерных приложений Docker. В основном он используется для создания контейнеров на одной машине.
Docker Swarm применяется в качестве платформы для управления кластерами Docker, которые можно использовать для создания контейнерных сервисов на нескольких серверах.
Предназначение K8s собственно такое же, как и у Docker Swarm. Это платформа для эксплуатации и обслуживания контейнеров, разработанная компанией Google. Она стала основным инструментом оркестрации контейнеров.
Dockerfile
Чтобы понимать, как работает Docker Compose, необходимо разбираться в Dockerfile. Сервис Spring Boot после компиляции представляет собой JAR-пакет. Перед развертыванием сервиса в контейнере Docker нужно собрать JAR-пакет в Docker-образ с помощью Dockerfile.
Dockerfile — это текстовый файл, используемый для создания образа. Содержимое файла — инструкции и указания по сборке образа.
Следует отметить, что каждая инструкция строит свой слой образа. Инструкций Dockerfile не так много, достаточно освоить те из них, которые используются в повседневной практике.
FROM
Задает базовый образ. Обычно это первая инструкция файла. Но можно также использовать ARG в качестве первой инструкции.
# Формат FROM [--platform=<platform>] <image> [AS <name>] FROM [--platform=<platform>] <image>[:<tag>] [AS <name>] FROM [--platform=<platform>] <image>[@<digest>] [AS <name>] # Использование FROM centos FROM openjdk:8-jre FROM node:12.18.4-alpine@sha256:757574c5a2...
Описание параметра:
[ — platform=<platform>]
— необязательный параметр, с помощью которого можно указать платформу образа, например Linux/amd64, Linux/arm64 и windows/amd64, обычно по умолчанию.<image>
— это имя образа, за которым следует номер версии:tag
, используемый для указания образа, и контекстно-адресуемый идентификатор@digest
(подробности об этих параметрах читайте на официальном сайте). Как правило, используются только теги. Если ни один из них не указан, будет получена последняя версия.[as <name>]
— имя текущего этапа сборки, поскольку в Dockerfile можно использовать несколько FROM для создания нескольких образов. Поэтомуas <name>
можно применять в следующей команде COPY. С помощью— from=<name>
можно ссылаться на образ, собранный ранее, например для копирования файлов, созданных предыдущим образом, и т. д.
ARG
Эта директива используется для указания переменной, которая передается во время выполнения сборки. Она может задавать значение по умолчанию. При сборке контейнера с помощью команды docker build
используйте — build-arg <varname> = <value>
для передачи параметров.
# Формат ARG <name>[=<default value>] # Использование ARG CODE_VERSION=laster ARG testArg=123 # Параметр FROM centos:7 ARG parameter=123 RUN echo $parameter docker build --build-arg parameter=234 -t test:1.0 # Примечание # ARG можно использовать до FROM, вне фазы сборки FROM, поэтому данную директиву нельзя использовать ни в одной инструкции после FROM. ARG CENTOS_VERSION=laster FROM centos:${CENTOS_VERSION}
ENV
Эта директива используется для установки переменных среды контейнера как в процессе сборки, так и в запущенном контейнере.
# Формат ENV <key>=<value> ... # Примечание # Можно задать более одного или использовать другой синтаксис ENV <ключ> <значение>. На официальном сайте рекомендуется использовать первый вариант, а второй может быть удален в будущих версиях. # Переменные ENV переопределяют переменные ARG # Использование ENV APP_VERSION=1.1.0 ENV WEB_HOME /opt/webapps
Copy
Эта директива используется для копирования файлов и каталогов из пути в контейнер.
# Формат COPY <src>... <dest> COPY "<src>",... "<dest>" # Использование COPY test.jar /opt/web/
ADD
Эта команда используется для копирования файлов, каталогов и удаленных файлов в образ. При этом сжатый пакетный файл типа TAR будет автоматически распакован.
# Формат ADD <src>... <dest> ADD "<src>",... "<dest>" # Использование ADD test.txt /tmp/test
WORKDIR
Эта директива устанавливает рабочий каталог для последующих директив. Если каталог не существует, он будет создан автоматически.
# Формат WORKDIR /path/to/workdir # Использование WORKDIR /build
LABEL
Эта директива используется для указания информации тега метаданных образа.
# Формат LABEL <key>=<value> <key>=<value> <key>=<value> ... # Использование LABEL version="1.0" LABEL description="This text illustrates"
CMD
Эта инструкция задает команду, которая будет выполняться при запуске контейнера после сборки образа.
# Формат CMD ["executable","param1","param2"] CMD ["param1","param2"] CMD command param1 param2 # Использование CMD sleep 40; java -jar secondkill-order.jar CMD ["java", "-jar", "secondkill-order.jar"]
RUN
Эта инструкция используется для указания команды, которая должна быть выполнена при сборке образа. Основное различие между RUN и CMD заключается в том, что CMD выполняется при запуске контейнера, а RUN — во время построения контейнера.
# Формат RUN <command> RUN ["executable", "param1", "param2"] # Использование RUN yum install -y net-tools RUN ["/bin/bash", "-c", "echo hello"]
EXPOSE
Эта команда указывает на то, что контейнер запущен на определенном порте. Вы можете указать протокол прослушивания. Если он не указан, по умолчанию используется протокол TCP.
# Формат EXPOSE <port> [<port>/<protocol>...] # Использование EXPOSE 80/udp EXPOSE 80 443
VOLUME
Эта директива используется для создания точки монтирования с указанным именем, которая может сопоставлять каталог за пределами контейнера.
# Формат VOLUME ["/data"] # Использование VOLUME /myvol
Здесь приведены лишь наиболее часто используемые команды Dockerfile. Чтобы ознакомиться с ними более детально, обратитесь к документации на официальном сайте.
Создание приложения Spring Boot с помощью Dockerfile
Использовать Dockerfile для упаковки Spring Boot достаточно просто. Для этого нужно использовать образ Jdk8, скопировать локально упакованный JAR-пакет в образ, открыть порт сервиса и запустить сервис.
# Зеркало, использующее openjdk8 FROM openjdk:8-jre # Установка рабочего каталога WORKDIR /build # Скопируйте пакет JAR в контейнер ADD ./test-springboot-docker-1.0.jar ./test.jar # Откройте порт 8080 EXPOSE 8080 # Запустите пакет JAR CMD java -jar test.jar
Как обычно помещаем Dockerfile в каталог проекта.
Затем развернем пакет maven для упаковки JAR-пакета. Поместим JAR-пакет и Dockerfile в один каталог на сервере со средой Docker и с помощью команды docker build
превратим микросервис Spring Boot в образ.
Затем запустим контейнер, чтобы проверить, может ли он успешно включиться в работу.
Поскольку порт 8080 используется другими сервисами, выполним маппинг на порт 80. Если получить доступ непосредственно к этому порту прямо сейчас, можно увидеть, что контейнер успешно запущен.
Docker Compose
На данном этапе JAR-пакет можно собрать в образ Docker. Но если приложение микросервисной архитектуры содержит несколько сервисов, его нельзя каждый раз вручную упаковывать и развертывать на сервере. Поэтому на данном этапе необходимо применить Docker Compose для управления контейнером.
Docker Compose использует файл docker-compose.yml
для определения нескольких сервисов. Формат файла — YAML. Для начала нужно определить структуру всего файла.
Файловая структура docker-compose.yml
Docker Compose предоставляет множество синтаксических шаблонов. Ниже перечислены только элементы синтаксиса, необходимые для данной структуры, остальные можно изучить на официальном сайте.
Официальная документация довольно подробна и представлена в формате docker-compose.yml
.
version: указание версии сборки, соответствующей текущему файлу; в основном это 1, 2.x и 3.x
service: список сервисов
<service-name>: имя сервиса
image: указание запущенного образа; можно напрямую извлекать существующий образ для обработки
build: установка папки, где находится Dockerfile, способный обрабатывать образы, которые должны быть собраны с помощью Dockerfile.
content: путь для хранения Dockerfile
dockerfile: указывает имя файла Dockerfile для сборки
args: аргументы сборки, доступные только в процессе сборки
container_name: установка имени контейнера
restart: стратегия перезапуска; есть такие опции, как no, always, no-failure и unless-stopped
ports: открытие порта контейнера, формат: порт хоста: порт контейнера
- 8080:8080
hostname: установка имени хоста контейнера
volumes: установка точки монтирования контейнера, который может быть смонтирован на хосте; основной формат: путь к хосту: путь к контейнеру [: режим доступа]
- /opt/data:/opt/data
- /var/lib/mysql:/var/lib/mysql:rw
volumes_from: монтирование объемов информации другого сервиса или контейнера
- service_name
- container_name
environment: установка переменных среды
- RACK_ENV=development
networks: настройка сетей
app_netwotk:
Команды Docker compose
Ниже перечислены часто используемые команды с их общими описаниями (подробные описания команд и используемых параметров представлены на официальном сайте).
build
: построить контейнер.ps
: вывести список всех контейнеров текущего проекта.up
: построить и запустить контейнер, общие параметры:-d
: фоновый старт,-
: указать конфигурационный файл.exec
: войти в указанный контейнер.top
: просмотреть текущее состояние каждого контейнера в проекте.logs
: просмотреть выходные данные контейнера.down
: остановить и удалить все контейнеры и соответствующую сеть.rm
: удалить все остановленные контейнеры.start
/stop
/restart
: запустить контейнер/остановить контейнер/перезапустить контейнер.
Развертывание микросервисов Docker Compose
В качестве примера воспользуемся проектом торгового центра с разделением на фронтенд и бэкенд. Он включает в себя 5 сервисов:
- шлюз;
- сервис аутентификации;
- пользовательский сервис;
- сервис товаров;
- сервис заказов.
Кроме того, есть реестр Nacos, а также проект использует Rabbitmq, Redis и базу данных Mysql. Таким образом, всего необходимо развернуть 8 контейнеров.
Установка Docker Compose
Хотя Docker Compose является инструментом оркестрации на официальном сайте, он не включен по умолчанию и должен быть установлен вручную.
Метод установки относительно прост: достаточно загрузить бинарный файл Docker Compose и установить разрешение на запуск исполняемого файла.
- Скачайте файл Docker Compose.
sudo curl -L https://github.com/docker/compose/releases/download/1.16.1/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
2. Добавьте к файлу разрешение на выполнение.
sudo chmod +x /usr/local/bin/docker-compose
3. Протестируйте результаты установки.
$ docker-compose --version
docker-compose version 1.18.0, build 8dd22a96
Общая структура файла
Общая структура файла docker-compose.yml
выглядит следующим образом: указывается версия файла (здесь используется версия 3), далее следуют сервисы (названия сервисов соответствуют нижеуказанным).
Составная часть сетевой конфигурации — это создание network
. Иначе по умолчанию будет создано имя сети с текущей папкой + _default
.
Например, если имя папки проекта — second kill
, а суффикс сети указан как app
, будет создана сеть secondkill_app
.
version: '3'
services:
secondkill-register:
...
secondkill-mysql:
...
secondkill-redis:
...
secondkill-rabbitmq:
...
secondkill-zuul:
...
secondkill-auth:
...
secondkill-goods:
...
secondkill-order:
...
secondkill-user:
...
networks:
app:
Развертывание реестра
Развертывание реестра — относительно простой процесс. Извлеките образ nacos/nacos-server:1.4.2
, но обратите внимание на установку режима запуска nacos
.
Поскольку по умолчанию Nacos запускается в кластере, необходимо увеличить MODE среды до автономного режима.
Кроме того, следует отметить, что здесь nacos
используется только как центр регистрации и соединение с базой данных не настроено.
Если понадобится сохранить данные Nacos в базе данных, обратите внимание на настройку информации о базе данных.
secondkill-register:
# Извлечение образа
image: nacos/nacos-server:1.4.2
# Метод перезапуска (Restart): always
restart: always
# Маппинг портов
ports:
- 8848:8848
# Имя контейнера
container_name: secondkill-register
# Имя хоста, которое требует от других контейнеров доступа к сети через вторичное имя
hostname: secondkill-register
# Переменная среды, установка режима запуска на автономный запуск
environment:
- MODE: standalone
# конфигурация информации mysql
# - SPRING_DATASOURCE_PLATFORM=mysql
# - MYSQL_MASTER_SERVICE_HOST=127.0.0.1
# - MYSQL_MASTER_SERVICE_PORT=3306
# - MYSQL_MASTER_SERVICE_USER=root
# - MYSQL_MASTER_SERVICE_PASSWORD=123456
# - MYSQL_MASTER_SERVICE_DB_NAME=nacos
# - MYSQL_SLAVE_SERVICE_HOST=122.112.152.188
# - MYSQL_SLAVE_SERVICE_PORT=3306
# Добавление в сеть
networks:
- app
Развертывание Rabbitmq и Redis
Развернуть очереди сообщений и Redis относительно легко. Однако следует отметить, что для удобства собственного развертывания для временной демонстрации я не перенаправлял постоянные данные и конфигурационные файлы Redis и Rabbitmq, что крайне не рекомендуется. Следует развертывать сервисы с фиксацией состояния и не хранить данные.
Когда контейнер развертывает сервисы, пригодные для конфигурирования и выполнения операций, конфигурационный файл и каталог данных следует монтировать на хосте.
secondkill-redis: # Образ redis image: redis:3.2 # Маппинг портов ports: - 6379:6379 # Метод перезапуска (Restart): always restart: always # Имя контейнера container_name: secondkill-redis # Имя хоста hostname: secondkill-redis # Присоединение к сети приложения networks: - app secondkill-rabbitmq: # Образ rabbitmq image: rabbitmq:3.8.4 # Маппинг портов ports: - 5672:5672 - 15672:15672 # Метод перезапуска (Restart): always restart: always # Имя контейнера container_name: secondkill-rabbitmq # Имя хоста hostname: secondkill-rabbitmq # Присоединение к сети приложения networks: - app
Развертывание базы данных
Как и сервис Redis, развертывание базы данных не монтирует конфигурационные файлы и данные (не рекомендуется, обратите на это внимание).
Поскольку при запуске базы данных здесь необходимо установить пароль базы данных, а также импортировать скрипт базы данных в базу данных, для создания образа здесь используется Dockerfile.
# Извлечение образа myql8
FROM mysql:8.0.14
# Установка переменной часового пояса
ENV TZ=Asia/Shanghai
# Установка часового пояса
RUN ln -sf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# Импорт скрипта базы данных
COPY ./choy_ms.sql /docker-entrypoint-initdb.d
Поместим скрипт базы данных и Dockerfile в один и тот же каталог, затем укажем каталог через build.content
в docker-compose.yml
.
secondkill-mysql:
# Установка каталога для скрипта сборки dockerfile
build:
context: ./db
environment:
# Установка пароля базы данных
MYSQL_ROOT_PASSWORD: 86598659yu
restart: always
container_name: secondkill-mysql
image: secondkill-mysql
ports:
- 3306:3306
networks:
- app
Развертывание микросервисов
Развертывание микросервисов должно начинаться после запуска вышеуказанных контейнеров, а также должно быть подключено к сервисам вышеуказанных контейнеров.
Поэтому в конфигурационном файле application.yml
необходимо заменить IP базы данных, очередь, реестра и Redis на имя хоста вышеуказанного контейнера, то есть на определенное имя хоста.
Наконец, соответствующий IP-адрес может быть найден автоматически после запуска контейнера.
spring:
cloud:
nacos:
discovery:
# secondkill-register - это имя хоста реестра
server-addr: secondkill-register:8848
datasource:
druid:
# Имя хоста базы данных: secondkill-mysql
url: jdbc:mysql://secondkill-mysql:3306/choy_ms...
...
redis:
# Имя хоста redis: secondkill-redis
host: secondkill-redis:127.0.0.1
...
rabbitmq:
# Имя хоста rabbitmq: secondkill-rabbitmq
host: secondkill-rabbitmq
port: 5672
При работе с Dockerfile необходимо обращать внимание на связь между местом хранения Dockerfile и целевым каталогом.
Поскольку весь проект извлекается, упаковывается и разворачивается на сервере через git, поместим Dockerfile под каждый микросервис, а JAR-пакет, в соответствии с командой ADD, должен предоставить целевой каталог.
Важно также при запуске микросервисов дождаться запуска сервисов центра регистрации, базы данных, Redis и очереди. Иначе запуск микросервисов будет неудачным. Для отсрочки запуска следует использовать команду sleep
или конфигурацию шаблона docker-compose.yml
: depends_on
.
# Извлечение образа java8
FROM openjdk:8-jre
# Установка рабочего каталога
WORKDIR /build
# Копирование JAR-пакета
ADD ./target/secondkill-order-1.1.0.jar ./secondkill-order.jar
# Открытый порт
EXPOSE 8010
# Чтобы запустить пакет JAR, необходимо отложить запуск и подождать, пока запустятся другие сервисы
CMD sleep 40; java -jar secondkill-order.jar
Следующим будет файл docker-compose.yml
. docker-compose.yml
хранится в корневом каталоге всего проекта.
В build.content
необходимо задать относительный путь к Dockerfile под каждым сервисом.
secondkill-order:
# Установка относительного пути к сервису, соответствующему Dockerfile
build:
context: ./secondkill-service/secondkill-order
ports:
- 8010:8010
restart: always
container_name: secondkill-order
hostname: secondkill-order
networks:
- app
Установим относительный путь к сервису, соответствующему Dockerfile.
# Указание номера версии
version: '3'
services:
# Сервис реестра
secondkill-register:
# Образ nacos-1.4.2
image: nacos/nacos-server:1.4.2
# Метод перезапуска (Restart): always
restart: always
# Маппинг портов
ports:
- 8848:8848
# Имя контейнера
container_name: secondkill-register
# Имя хоста
hostname: secondkill-register
# Переменная среды, установка режима запуска на автономный запуск
environment:
MODE: standalone
# Добавление в веб-приложение
networks:
- app
# Сервис базы данных
secondkill-mysql:
# База данных соответствует каталогу Dockerfile
build:
context: ./db
# Установка пароля базы данных
environment:
MYSQL_ROOT_PASSWORD: 86598659yu
restart: always
container_name: secondkill-mysql
image: secondkill-mysql
ports:
- 3306:3306
networks:
- app
# Сервис redis
secondkill-redis:
# Образ redis-3.2
image: redis:3.2
ports:
- 6379:6379
restart: always
container_name: secondkill-redis
hostname: secondkill-redis
networks:
- app
# Сервис rabbitmq
secondkill-rabbitmq:
# Образ rabbitmq-3.8.4
image: rabbitmq:3.8.4
ports:
- 5672:5672
- 15672:15672
restart: always
container_name: secondkill-rabbitmq
hostname: secondkill-rabbitmq
networks:
- app
# Далее следуют микросервисы
# Сервис шлюза
secondkill-zuul:
# Сервис шлюза соответствует пути Dockerfile
build:
context: ./secondkill-zuul
ports:
- 8000:8000
restart: always
container_name: secondkill-zuul
hostname: secondkill-zuul
networks:
- app
# Сервис аутентификации
secondkill-auth:
# Сервис аутентификации соответствует пути Dockerfile
build:
context: ./secondkill-auth
ports:
- 8002:8002
restart: always
container_name: secondkill-auth
hostname: secondkill-auth
networks:
- app
# Сервис продукта
secondkill-goods:
# Сервис продукта соответствует пути Dockerfile
build:
context: ./secondkill-service/secondkill-goods
ports:
- 8021:8021
restart: always
container_name: secondkill-goods
hostname: secondkill-goods
networks:
- app
# Сервис заказов
secondkill-order:
# Сервис заказов соответствует пути Dockerfile
build:
context: ./secondkill-service/secondkill-order
ports:
- 8010:8010
restart: always
container_name: secondkill-order
hostname: secondkill-order
networks:
- app
# Пользовательский сервис
secondkill-user:
# Пользовательский сервис соответствует пути Dockerfile
build:
context: ./secondkill-service/secondkill-user
ports:
- 8001:8001
restart: always
container_name: secondkill-user
hostname: secondkill-user
networks:
- app
# Установка app в качестве сети
networks:
app:
Развертывание сервиса
Сначала нужно извлечь проект на сервер. В данном случае берем его прямо из репозитория Github, затем входим в проект и выполняем mvn clean && mvn package
для упаковки и компиляции проекта.
Затем выполняем docker-compose up -d
для оркестрации и запуска контейнера.
На этом сервере установлен portainer
. Можно напрямую войти в portainer
для просмотра состояния контейнеров. Нажмите на имя каждого контейнера, чтобы посмотреть вывод запуска сервера.
Можно также напрямую войти в центр регистрации Nacos, чтобы просмотреть статус регистрации сервиса.
Если же потребуется остановить все сервисы и удалить контейнер, используйте команду docker-compose down
.
Читайте также:
- Докеризируем среду разработки в VS Code
- Меньше образы Docker => быстрее CI-конвейер
- Мир Docker и Kubernetes в аналогиях с жизнью разработчика
Читайте нас в Telegram, VK и Дзен
Перевод статьи Dwen: How to Orchestrate Microservices With Docker-Compose