С помощью этого руководства вы научитесь разворачивать в кластере Docker Swarm микросервисное веб-приложение, состоящее из трех компонентов: frontend, backend и база данных. Приложение будет работать с веб-интерфейсом, API-сервисом и централизованным хранилищем данных.
Отказоустойчивость архитектуры будет обеспечена за счет следующих технологий:
репликация сервисов frontend и backend на нескольких виртуальных машинах, объединенных в один кластер;
использование базы данных MySQL, развернутой как сервис внутри Swarm;
хранение данных в томах для обеспечения их устойчивости к сбоям контейнеров.
В конце вы сможете протестировать доступность системы при отключении одного из узлов кластера.
Вы будете использовать следующие сервисы:
Виртуальные машины — сервис, в рамках которого предоставляется виртуальная машина для размещения приложения.
Публичный IP-адрес для доступа к виртуальным машинам через интернет.
VPC-сеть — изолированная виртуальная сеть для создания безопасной инфраструктуры.
Load Balancer — балансировщик нагрузки для виртуальных машин.
Artifact Registry для хранения, совместного использования и управления Docker-образами и Helm-чартами.
Docker — система контейнеризации.
Шаги:
Перед началом работы
-
Если вы уже зарегистрированы, войдите под своей учетной записью.
Убедитесь, что у вас достаточно прав для создания реестра и загрузки артефактов в сервисе Artifact Registry.
Создайте реестр в Artifact Registry. Скопируйте полученный URI реестра, он будет нужен для выполнения дальнейших шагов.
Получите ключи доступа сервисного аккаунта. Запишите Key ID (логин) и Key Secret (пароль), они будут нужны для выполнения дальнейших шагов.
1. Разверните ресурсы в облаке
Все создаваемые ресурсы должны располагаться в одной зоне доступности.
Сгенерируйте ключевую пару и загрузите публичный ключ в облако Evolution.
Создайте VPC-сеть или выберите одну из существующих сетей.
Создайте подсеть в выбранной VPC-сети или выберите одну из существующих.
Создайте группу безопасности и добавьте в нее правило входящего трафика со следующими параметрами:
Протокол: TCP;
Порт: 8080;
Тип источника: IP-адрес;
Источник: 0.0.0.0/0.
Создайте три виртуальные машины со следующими параметрами:
Название: docker-swarm-manager-1, docker-swarm-worker-1 и docker-swarm-worker-2.
Зона доступности: та же, что у подсети и группы безопасности.
Образ: выберите образ с ОС Ubuntu 22.04. Вы можете выбрать другую ОС, но команды для выполнения могут отличаться от описанных в этом руководстве.
Подключить к подсети: включите опцию и укажите подсеть и группу безопасности, созданные ранее.
Подключить публичный IP: включите опцию и выберите прямой IP-адрес.
Метод аутентификации: выберите Публичный ключ и укажите SSH-ключ, созданный ранее.
Запишите публичные IP-адреса каждой виртуальной машины. В этом руководстве используются следующие IP-адреса:
docker-swarm-manager-1 — 176.123.162.37;
docker-swarm-worker-1 — 176.109.104.79;
docker-swarm-worker-2 — 176.123.162.146.
2. Настройте виртуальные машины
В терминале для каждой из созданных машин выполните действия:
Подключитесь к виртуальной машине по SSH с использованием публичного IP-адреса.
Установите Docker:
curl -fsSL get.docker.com -o get-docker.sh && sudo sh get-docker.sh
3. Создайте кластер Docker Swarm
Откройте сессию терминала с подключением к виртуальной машине docker-swarm-manager-1.
Создайте кластер при помощи команды:
sudo docker swarm init --default-addr-pool 192.168.100.0/16 --advertise-addr 176.123.162.37Где:
--default-addr-pool — адрес overlay-сети, которая соединит контейнеры на разных машинах в одну виртуальную сеть. Без нее распределенные приложения в Swarm работать не будут. Адрес overlay-сети не должен совпадать с адресом подсети, к которой подключены виртуальные машины.
--advertise-addr — IP-адрес, который менеджер Swarm будет использовать для связи с другими узлами. Укажите здесь публичный IP-адрес основной машины. В этом сценарии — 176.123.162.37.
В ответе вернется сообщение, что текущая машина является менеджером кластера, и команда для добавления узлов в кластер:
Swarm initialized: current node (zbjlb49a21tzg3ae0qthjsb7r) is now a manager.To add a worker to this swarm, run the following command:docker swarm join --token SWMTKN-1-example123 176.123.162.37:2377To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.Скопируйте команду для добавления узлов.
Для виртуальных машин docker-swarm-worker-1 и docker-swarm-worker-2 в терминале выполните скопированную команду под корневым пользователем:
sudo docker swarm join --token SWMTKN-1-example123 176.123.162.37:2377В ответе вернется сообщение, что машина назначена worker-узлом в кластере.
Убедитесь, что в кластер добавлены все нужные узлы. Для этого перейдите в сессию терминала docker-swarm-manager-1 и выполните команду:
sudo docker node ls
В ответе вернется список узлов:
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION2vl32ofyer2w7fmx6m5sjldjz * docker-swarm-manager-1 Ready Active Leader 28.3.235r3qrtgb7l4nq3n0ykughkdw docker-swarm-worker-1 Ready Active 28.3.2cllbe9vic7tihon6qqjd9usz5 docker-swarm-worker-2 Ready Active 28.3.2
4. Создайте структуру каталогов и файлы проекта
На виртуальной машине docker-swarm-manager-1 создайте новую директорию для проекта и перейдите в нее:
mkdir swarm-appcd swarm-appСоздайте директории для всех компонентов приложения и хранения файлов базы данных:
mkdir backend frontend mysql_data mysql-initУбедитесь, что структура каталогов веб-приложения создана верно, выполнив команду ls.
Перейдите в директорию backend и создайте файлы для приложения на Flask:
cd backendtouch app.py requirements.txt Dockerfilecd ..Где:
app.py — исходный код сервера backend;
requirements.txt — список зависимостей Python;
Dockerfile — инструкции для сборки образа backend-приложения.
Перейдите в директорию frontend и создайте файлы для frontend-приложения:
cd frontendtouch default.conf Dockerfilecd ..Где:
default.conf — конфигурационный файл nginx;
Dockerfile — инструкции для сборки образа frontend-приложения.
Перейдите в директорию mysql-init и создайте файлы для frontend-приложения:
cd mysql-inittouch init.sqlcd ..Создайте в корне проекта файл docker-swarm.yml, который будет описывать стек приложения:
touch docker-swarm.yml
Проверьте итоговую структуру каталогов. На этом этапе она должна иметь следующий вид:
swarm-app/├── backend/│ ├── app.py│ ├── requirements.txt│ └── Dockerfile├── frontend/│ ├── default.conf│ └── Dockerfile├── mysql_data/ # directory for volume MySQL├── mysql-init/│ └── init.sql└── docker-swarm.yml
5. Создайте backend-приложение
Перейдите в директорию backend и откройте файл requirements.txt:
cd backendnano requirements.txtДобавьте код для определения зависимости вашего приложения и сохраните изменения:
flaskflask-mysqldbОткройте файл backend/app.py:
nano app.pyДобавьте минимальный рабочий код Flask-приложения с подключением к MySQL:
from flask import Flask, request, redirect, url_for, render_template_stringfrom flask_mysqldb import MySQLapp = Flask(__name__)# MySQL connection settingsapp.config['MYSQL_HOST'] = 'db'app.config['MYSQL_USER'] = 'user'app.config['MYSQL_PASSWORD'] = 'password'app.config['MYSQL_DB'] = 'appdb'# Initializing MySQLmysql = MySQL(app)# HTML-template with BootstrapHTML_TEMPLATE = '''<!DOCTYPE html><html lang="ru"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Notes in Docker Swarm</title><link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet"></head><body class="bg-light"><div class="container py-5"><h1 class="mb-4 text-center">📝 Notes in Swarm</h1><form method="post" action="/" class="mb-4"><div class="input-group"><input type="text" name="note" class="form-control" placeholder="Enter a new note" required><button class="btn btn-primary" type="submit">Add</button></div></form><div class="card shadow"><div class="card-body">{% if notes %}<ul class="list-group">{% for id, content in notes %}<li class="list-group-item d-flex justify-content-between align-items-center"><span>{{ content }}</span><span class="badge bg-secondary rounded-pill">#{{ id }}</span></li>{% endfor %}</ul>{% else %}<p class="text-muted">There are no notes yet...</p>{% endif %}</div></div></div></body></html>'''@app.route('/', methods=['GET', 'POST'])def index():conn = mysql.connectioncursor = conn.cursor()if request.method == 'POST':# читаем поле note из формыnote = request.form.get('note')if note:cursor.execute("INSERT INTO entries (name) VALUES (%s)", (note,))conn.commit()return redirect(url_for('index'))# GET:cursor.execute("SELECT id, name FROM entries ORDER BY id")notes = cursor.fetchall()cursor.close()return render_template_string(HTML_TEMPLATE, notes=notes)if __name__ == '__main__':app.run(host='0.0.0.0', port=5000)
6. Создайте Dockerfile для backend-приложения
Откройте Dockerfile в редакторе:
nano DockerfileВставьте в Dockerfile следующий код:
FROM python:3.9-slim# Installing dependencies for compiling mysqlclientRUN apt-get update && apt-get install -y \gcc \default-libmysqlclient-dev \pkg-config \&& rm -rf /var/lib/apt/lists/*WORKDIR /appCOPY requirements.txt requirements.txtRUN pip install --no-cache-dir -r requirements.txtCOPY . .CMD ["python", "app.py"]Соберите образ и загрузите его в реестр:
sudo docker build . -t <registry_name>.cr.cloud.ru/backend:1.0 --platform linux/amd64sudo docker push <registry_name>.cr.cloud.ru/backend:1.0Где:
<registry_name>.cr.cloud.ru — URI реестра, в котором находится репозиторий.
backend — название репозитория, соответствует названию загружаемого образа.
platform linux/amd64 — флаг указывает, что образ должен быть собран для платформы linux/amd64. Это требуется для создания контейнера.
1.0 — тег образа.
7. Создайте frontend-приложение
Перейдите в директорию frontend, создайте файл default.conf и откройте его:
cd ../frontendnano default.confВставьте следующий код:
server {listen 80;# Proxy all requests (GET, POST, etc.) to backendlocation / {proxy_pass http://backend:5000;proxy_http_version 1.1;proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_set_header X-Forwarded-Proto $scheme;}}Создайте файл Dockerfile:
nano DockerfileВставьте следующий код:
FROM nginx:1.27.5-alpine # Using nginx as a web serverCOPY default.conf /etc/nginx/conf.d/default.conf # Copy the HTML file to the standart nginx directoryСоберите ваш образ и загрузите его в реестр:
sudo docker build . -t <registry_name>.cr.cloud.ru/frontend:1.0 --platform linux/amd64sudo docker push <registry_name>.cr.cloud.ru/frontend:1.0
8. Настройте структуру базы данных
Создайте файл mysql-init/init.sql и перейдите к его редактированию:
cd ../mysql-initnano init.sqlВставьте код, который создает целевую таблицу:
CREATE DATABASE IF NOT EXISTS appdb;USE appdb;CREATE TABLE IF NOT EXISTS entries (id INT AUTO_INCREMENT PRIMARY KEY,name VARCHAR(255) NOT NULL);Сохраните файл mysql-init/init.sql и вернитесь на уровень выше, выполнив команду cd ...
9. Создайте файл для запуска приложения в Docker Swarm
Файл должен содержать декларацию трех компонентов проекта в Docker Swarm:
frontend — перенаправление к приложению, 2 реплики, подключен к overlay-сети;
backend — Flask-приложение (API), 2 реплики, подключен к overlay-сети;
база данных — MySQL, 1 реплика, подключена к overlay-сети, хранение данных в томе mysql_data.
Откройте файл в корне проекта:
nano docker-swarm.ymlВставьте следующий код:
services:db:image: mysql:8.0environment:MYSQL_ROOT_PASSWORD: rootpassMYSQL_DATABASE: appdbMYSQL_USER: userMYSQL_PASSWORD: passwordvolumes:- db-data:/var/lib/mysql- ./mysql-init:/docker-entrypoint-initdb.dnetworks:- appnetdeploy:placement:constraints: [node.role == manager]backend:image: <registry_name>.cr.cloud.ru/backend:1.0depends_on:- dbenvironment:MYSQL_DATABASE_HOST: dbMYSQL_DATABASE_USER: userMYSQL_DATABASE_PASSWORD: passwordMYSQL_DATABASE_NAME: appdbnetworks:- appnetdeploy:replicas: 2restart_policy:condition: on-failurefrontend:image: <registry_name>.cr.cloud.ru/frontend:1.0ports:- "8080:80"networks:- appnetdepends_on:- backenddeploy:replicas: 2restart_policy:condition: on-failurevolumes:db-data:networks:appnet:driver: overlayГде:
<registry_name> — название реестра.
volumes: db-data — сохраняет базу между перезапусками.
deploy.replicas — создает отказоустойчивость фронтенда и бэкенда.
networks.overlay — дает сервисам доступ друг к другу по имени, например http://backend:5000.
placement.constraints — закрепляет базу только за менеджером, где том будет доступен локально.
Это простое решение — более сложное потребует использования Galera или Vitess.
10. Разверните приложение в Swarm
Разверните ваше приложение в Swarm, используя команду:
sudo docker stack deploy -c docker-swarm.yml --with-registry-auth myappПодождите несколько минут, пока загрузятся образы и запустится приложение.
Проверьте статус с помощью команды:
sudo docker service ls
Все контейнеры должны быть в статусе «replicated» и с полным количеством реплик.
11. Настройте балансировщик нагрузки
Отвяжите публичные адреса от виртуальных машин и добавьте балансировщик нагрузки, чтобы приложение было доступно при выходе из строя рабочего сервера:
Отвяжите публичный IP-адрес от каждой из трех виртуальных машин.
Создайте балансировщик нагрузки со следующими параметрами:
Зона доступности: та же, в которой расположены виртуальные машины.
VPC: та же, в которой расположены виртуальные машины.
Тип балансировщика: выберите внешний тип балансировщика.
Правило балансировки трафика:
Создайте новую backend-группу и добавьте в нее три созданные виртуальные машины.
Порт балансировщика: 80.
Порт backend группы: 8080.
Включите проверку доступности:
Порт: 8080.
Интервал: 10.
Таймаут: 5.
Порог успешных ответов: 3.
Порог неуспешных ответов: 3.
Дождитесь, когда балансировщик нагрузки перейдет в статус «Активен».
Протестируйте отказоустойчивость и работоспособность приложения
Проверьте работоспособность приложения при активности всех рабочих узлов:
Откройте в браузере страницу с адресом публичного IP балансировщика — http://<load_balancer_public_IP>.
Убедитесь, что:
Загружается веб-интерфейс.
Отображаются записи, если добавлялись.
Добавьте новую запись — она должна сохраниться и отобразиться после обновления.
Проверьте работу отказоустойчивости при выходе из строя одного из рабочих узлов:
Выключите виртуальную машину docker-swarm-worker-2.
Откройте в браузере страницу с адресом публичного IP балансировщика — http://<load_balancer_public_IP>.
Убедитесь, что:
Загружается веб-интерфейс.
Отображаются записи, если добавлялись.
Добавьте новую запись — она должна сохраниться и отобразиться после обновления.
Результат
Вы научились:
настраивать кластер Docker Swarm и объединять узлы;
разворачивать многокомпонентные приложения с помощью docker stack deploy;
использовать overlay-сети для взаимодействия сервисов;
конфигурировать работу Flask-приложения с внешней базой MySQL;
обеспечивать сохранность данных с помощью Docker Volumes;
проверять отказоустойчивость путем симуляции отказа узлов;
диагностировать состояние кластера и отдельных компонентов с помощью команд Docker.
- Перед началом работы
- 1. Разверните ресурсы в облаке
- 2. Настройте виртуальные машины
- 3. Создайте кластер Docker Swarm
- 4. Создайте структуру каталогов и файлы проекта
- 5. Создайте backend-приложение
- 6. Создайте Dockerfile для backend-приложения
- 7. Создайте frontend-приложение
- 8. Настройте структуру базы данных
- 9. Создайте файл для запуска приложения в Docker Swarm
- 10. Разверните приложение в Swarm
- 11. Настройте балансировщик нагрузки
- Протестируйте отказоустойчивость и работоспособность приложения
- Результат