Дисциплина "Проектирование и развертывание веб-решений в эко-системе Python"
- Содержимое registry:
- Успешная аутентификация
- Неуспешная аутентификация
- Узлы в состоянии Active
- Узлы в состоянии Drain
Нет, автоматического восстановления работы не происходит.
Когда узел переводится в режим Drain, Docker Swarm останавливает все задачи на этом узле и перемещает их на другие доступные узлы кластера. После возврата узла в режим Active он снова становится доступным для планировщика Swarm и может принимать новые задачи, но ранее перемещённые задачи на него автоматически не возвращаются.
- Принудительное обновление сервиса:
docker service update --force sleep-app
- Масштабирование сервиса:
docker service scale sleep-app=N
Где N — новое количество реплик.
Количество нодов (реплик) для каждого сервиса в стеке задаётся через параметр replicas в секции deploy docker-compose.yml файла.
vote:
# ...
deploy:
replicas: 2
worker:
# ...
deploy:
replicas: 2
Docker Swarm запустит:
- 2 реплики сервиса
vote - 2 реплики сервиса
worker
- Прямая проверка жизнеспособности через
healthcheck - Зависимости между сервисами с условием готовности (
depends_on->service_healthy)
Файл docker-compose.swarm.yml содержит конфигурацию для кластеризованного развертывания:
services:
app:
image: ${DOCKER_REGISTRY:-localhost:5000}/counter-app:latest
ports:
- "80:8000"
deploy:
replicas: 4 # 4 экземпляра Flask приложения
endpoint_mode: vip # Встроенная балансировка нагрузки
update_config:
parallelism: 2
delay: 10s
failure_action: rollback
resources:
limits:
cpus: '0.50'
memory: 512M
reservations:
cpus: '0.25'
memory: 256M
placement:
preferences:
- spread: node.id
environment:
- REDIS_HOST=redis
- REDIS_PORT=6379
- REDIS_DB=0
redis:
image: redis:7-alpine
command: ["redis-server", "--save", "60", "1", "--appendonly", "yes"]
deploy:
replicas: 1
Для проверки производительности приложения используется Locust. Сценарии нагрузочного тестирования содержатся в файле locustfile.py.
Нагрузочное тестирование будет использоваться для сравнения производительности: 1 реплика vs 4 реплики.
Параметры тестирования:
- Максимальное количество пользователей - 300
- Увеличение количества пользователей в секунду - 30
- Длительность тестирования - 60 секунд
Результаты тестирования:
| Метрика | 1 реплика | 4 реплики | Изменение |
|---|---|---|---|
| RPS (запросов/сек) | 219.50 | 222.49 | +1.4% |
| Среднее время отклика | 46.18 мс | 30.39 мс | -34.2% |
| 95-й перцентиль | 150.00 мс | 110.00 мс | -26.7% |
| 99-й перцентиль | 270.00 мс | 190.00 мс | -29.6% |
| Процент ошибок | 0% | 0% | - |
Анализ результатов тестирования:
Увеличение количества реплик с 1 до 4 показало ограниченное улучшение пропускной способности, но значительное снижение времени отклика:
-
Минимальный прирост RPS (+1.4%)
- Пропускная способность практически не изменилась
- Узкое место - не CPU приложения, а Redis
- Приложение выполняет простые операции (чтение/запись в Redis) без сложных вычислений
-
Значительное улучшение времени отклика (-34.2%)
- Среднее время отклика снизилось с 46.18 мс до 30.39 мс
- 95-й перцентиль улучшился на 26.7%
- 99-й перцентиль улучшился на 29.6%
- Распределение нагрузки между репликами снижает вероятность длинных очередей
-
Факторы, ограничивающие эффект масштабирования:
- Приложение легковесное — простые CRUD операции без тяжелой бизнес-логики
- Redis обрабатывает запросы быстрее, чем приложение
- Локальное тестирование исключает реальные сетевые задержки
- Все реплики работают на одной машине
Выводы:
Для данного приложения кластеризация Flask дает умеренный эффект:
- Пропускная способность: практически не изменяется, так как узкое место в Redis
- Время отклика: значительно улучшается за счет распределения нагрузки
- Отказоустойчивость: основное преимущество — при падении одной реплики система продолжает работать
- Production сценарий: при более сложной логике (аутентификация, внешние API, обработка данных) эффект от масштабирования был бы более выраженным
Файл docker-compose.swarm-replicated.yml содержит конфигурацию для кластеризованного развертывания (3 реплики Redis):
services:
app:
image: ${DOCKER_REGISTRY:-localhost:5000}/counter-app:latest
ports:
- "80:8000"
deploy:
replicas: 4 # 4 экземпляра Flask приложения
endpoint_mode: vip # Встроенная балансировка нагрузки
update_config:
parallelism: 2
delay: 10s
failure_action: rollback
resources:
limits:
cpus: '0.50'
memory: 512M
reservations:
cpus: '0.25'
memory: 256M
placement:
preferences:
- spread: node.id
environment:
- REDIS_HOST=redis
- REDIS_PORT=6379
- REDIS_DB=0
redis:
image: redis:7-alpine
command: ["redis-server", "--save", "60", "1", "--appendonly", "yes"]
deploy:
replicas: 3 # 3 реплики Redis
Особенности при использовании нескольких реплик Redis в Docker Swarm:
-
Независимые экземпляры БД
- Каждая реплика Redis является независимым экземпляром
- Данные не синхронизируются автоматически между репликами
- Каждое подключение может попасть на любой экземпляр Redis
-
Проблема консистентности данных
- Запись в одну реплику не отражается в других
- Разные экземпляры приложения могут видеть разные данные
- Потеря целостности данных счетчика
-
Балансировка подключений
- Docker Swarm распределяет подключения между репликами случайным образом
- Нет контроля, какое приложение к какой реплике подключается
Пути решения проблем репликации:
-
Redis Sentinel
- Автоматическое управление master и replicas
- Автоматический failover при отказе master
- Требует дополнительной настройки конфигурации
-
Redis Cluster
- Распределение данных по нескольким узлам
- Автоматическая репликация
- Более сложная настройка, но лучшая производительность
-
Внешний managed Redis (AWS ElastiCache, Redis Cloud и т.д.)
- Управляемый сервис с автоматической репликацией
- Минимальная настройка, максимальная надежность
Файл k8s-deployment.yaml содержит конфигурацию для кластеризованного развертывания:
apiVersion: apps/v1
kind: Deployment
metadata:
name: counter-app
labels:
app: counter-app
spec:
replicas: 4 # 4 реплики Flask приложения
selector:
matchLabels:
app: counter-app
template:
metadata:
labels:
app: counter-app
spec:
containers:
- name: counter-app
image: localhost:5000/counter-app:latest
imagePullPolicy: Never
ports:
- containerPort: 8000
env:
- name: REDIS_HOST
value: "redis-service"
- name: REDIS_PORT
value: "6379"
- name: REDIS_DB
value: "0"
resources:
limits:
cpu: "500m"
memory: "512Mi"
requests:
cpu: "250m"
memory: "256Mi"
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis
labels:
app: redis
spec:
replicas: 1
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
containers:
- name: redis
image: redis:7-alpine
command: ["redis-server", "--save", "60", "1", "--appendonly", "yes"]
ports:
- containerPort: 6379
---
apiVersion: v1
kind: Service
metadata:
name: counter-app-service
spec:
type: LoadBalancer
ports:
- port: 80
targetPort: 8000
protocol: TCP
selector:
app: counter-app
---
apiVersion: v1
kind: Service
metadata:
name: redis-service
spec:
ports:
- port: 6379
targetPort: 6379
protocol: TCP
selector:
app: redis
Изменения при использовании Kubernetes вместо Docker Swarm:
-
Формат конфигурации
- Swarm использует
docker-compose.ymlс синтаксисом Compose - Kubernetes использует YAML-манифесты с декларативным API Kubernetes
- Swarm использует
-
Архитектура
- Swarm интегрирован в Docker, более простая настройка
- Kubernetes - отдельная оркестрационная система, более мощная, но сложнее
-
Балансировка нагрузки
- Swarm: встроенная балансировка через VIP (Virtual IP)
- Kubernetes: Service с типами ClusterIP, NodePort, LoadBalancer
-
Масштабирование
- Swarm:
docker service scale - Kubernetes:
kubectl scale deploymentили изменениеreplicasв манифесте
- Swarm:
Для проверки производительности приложения используется Locust. Сценарии нагрузочного тестирования содержатся в файле locustfile.py.
Нагрузочное тестирование будет использоваться для сравнения производительности: Docker Swarm vs Kubernetes.
Параметры тестирования:
- Максимальное количество пользователей - 300
- Увеличение количества пользователей в секунду - 30
- Длительность тестирования - 60 секунд
Результаты тестирования:
| Метрика | Docker Swarm (4 реплики) | Kubernetes (4 реплики) | Изменение |
|---|---|---|---|
| RPS (запросов/сек) | 222.49 | 223.91 | +0.6% |
| Среднее время отклика | 30.39 мс | 18.89 мс | -37.8% |
| 95-й перцентиль | 110.00 мс | 96.00 мс | -12.7% |
| 99-й перцентиль | 190.00 мс | 180.00 мс | -5.3% |
| Процент ошибок | 0% | 100% | - |
Анализ результатов тестирования:
Сравнение производительности (при условии исправления конфигурации):
-
Пропускная способность (RPS)
- Разница минимальна и находится в пределах погрешности измерений
- Обе платформы показывают схожую производительность при равном количестве реплик
-
Время отклика
- Более низкое время отклика в Kubernetes может объясняться оптимизацией сетевого стека
-
Особенности платформ:
- Docker Swarm: проще в настройке, интегрирован в Docker, встроенная балансировка через VIP
- Kubernetes: более гибкая конфигурация, расширенные возможности (автомасштабирование, политики безопасности, ресурсы)
Выводы:
Для данного простого приложения:
- Docker Swarm предпочтительнее — проще настройка и управление для простых сценариев
- Kubernetes оправдан, если требуются его продвинутые функции (автомасштабирование, сетевые политики, сложные стратегии развертывания)
- Обе платформы показывают сопоставимую производительность при корректной конфигурации
- Основное ограничение производительности — Redis, а не выбор оркестратора
Проект поддерживает два способа кластеризованного развертывания: