Развертывание отказоустойчивого веб-приложения с разделением компонентов во фреймворке Docker Swarm
В этой лабораторной работе вы научитесь развертывать в кластере Docker Swarm микросервисное веб-приложение, состоящее из трех компонентов: frontend, backend и база данных. Приложение будет работать с веб-интерфейсом, API-сервисом и централизованным хранилищем данных.
Отказоустойчивость архитектуры будет обеспечена за счет следующих технологий:
-
репликация сервисов frontend и backend на нескольких виртуальных машинах, объединенных в один кластер;
-
использование базы данных MySQL, развернутой как сервис внутри Swarm;
-
хранение данных в томах для обеспечения их устойчивости к сбоям контейнеров.
Вы будете использовать следующие сервисы:
-
Виртуальные машины — виртуальная машина в облаке для размещения приложения.
-
Публичный IP-адрес — для доступа к виртуальным машинам через интернет.
-
VPC сеть — изолированная виртуальная сеть для создания безопасной инфраструктуры.
-
Load Balancer — балансировщик нагрузки для виртуальных машин в облаке Evolution.
-
Artifact Registry — хранение, совместное использование и управление Docker-образами и Helm-чартами.
В конце лабораторной работы вы протестируете доступность системы при отключении одного из узлов кластера.
Шаги:
Перед началом работы
-
Если вы уже зарегистрированы, войдите под своей учетной записью.
-
Убедитесь, что у вас достаточно прав для создания реестра и загрузки артефактов в сервисе Artifact Registry.
-
Создайте реестр в Artifact Registry. Скопируйте полученный URI реестра, он будет нужен для выполнения дальнейших шагов.
-
Получите ключи доступа сервисного аккаунта. Запишите Key ID (логин) и Key Secret (пароль), они будут нужны для выполнения дальнейших шагов. После того как вы закроете окно, повторно посмотреть пароль будет нельзя.
1. Разверните ресурсы в облаке
Все создаваемые ресурсы должны располагаться в одной зоне доступности.
-
Сгенерируйте ключевую пару и загрузите публичный ключ в Cloud.ru 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. Настройте балансировщик нагрузки
- Протестируйте отказоустойчивость и работоспособность приложения
- Что дальше