Что такое canary deployment?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Canary Deployment
Определение
Canary Deployment — это стратегия развертывания новой версии приложения, при которой новый код сначала развертывается только для небольшого процента пользователей (5-10%), а затем постепенно увеличивается количество пользователей, получающих новую версию. Если всё работает корректно, новая версия постепенно раскатывается на 100% пользователей.
Происхождение названия
"Canary" (канарейка) — историческое название от практики шахтёров, которые брали канареек в шахты. Птица была индикатором опасного газа: если канарейка падала, это означало опасность. Здесь новая версия выступает "канарейкой" для обнаружения проблем перед полным развертыванием.
Архитектура Canary Deployment
Пользователи (100%)
│
┌────┴────┐
│ │
90%│ │10% (Canary)
│ │
┌────v───┐ ┌────v────┐
│ Старая │ │ Новая │
│версия │ │ версия │
│ v1.0 │ │ v1.1 │
└────────┘ └─────────┘
│ │
│ Мониторинг
│ │
Если OK ──> Увеличить % новой версии
Если ошибка ──> Быстрый rollback
Этапы Canary Deployment
Этап 1: Подготовка (0% → 5%)
# Конфигурация балансировщика (например, NGINX или Kubernetes)
# 5% трафика на новую версию
upstream app_v1 {
server app-v1:8000 weight=95;
server app-v1-new:8000 weight=5; # Canary
}
Этап 2: Мониторинг (5%)
import logging
from prometheus_client import Counter, Histogram
import time
# Метрики для мониторинга
error_rate = Counter("app_errors_total", "Total errors", ["version"])
response_time = Histogram("response_time_seconds", "Response time", ["version"])
def handle_request(version):
start = time.time()
try:
result = process_request()
duration = time.time() - start
response_time.labels(version=version).observe(duration)
return result
except Exception as e:
error_rate.labels(version=version).inc()
logging.error(f"Error in {version}: {e}")
raise
Этап 3: Постепенное увеличение (5% → 25% → 50% → 100%)
# Пример с использованием Kubernetes
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: app
spec:
hosts:
- app
http:
- match:
- headers:
user-type:
exact: "canary_user" # Метка для canary
route:
- destination:
host: app
subset: v1_1 # Новая версия
# Остальные пользователи (95%)
- route:
- destination:
host: app
subset: v1_0
weight: 95
- destination:
host: app
subset: v1_1
weight: 5 # Начинаем с 5%
Этап 4: Полный rollout (100%)
Когда метрики в норме, 100% трафика переводится на новую версию.
Реальный пример с Docker и NGINX
# app_v1.0/main.py
from flask import Flask
app = Flask(__name__)
@app.route("/api/status")
def status():
return {"version": "1.0", "status": "ok"}
@app.route("/api/data")
def get_data():
# Старая логика
return {"data": [1, 2, 3]}
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8000)
# app_v1.1/main.py (новая версия с улучшениями)
from flask import Flask
app = Flask(__name__)
@app.route("/api/status")
def status():
return {"version": "1.1", "status": "ok", "improvements": ["faster", "more_data"]}
@app.route("/api/data")
def get_data():
# Улучшенная логика
return {"data": [1, 2, 3], "count": 3} # Добавлено count
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8000)
# NGINX конфигурация для canary
upstream app_v1_0 {
server app-v1.0:8000;
}
upstream app_v1_1 {
server app-v1.1:8000; # Canary
}
server {
listen 80;
server_name api.example.com;
# 5% на canary, 95% на stable
location / {
# Случайный выбор с весами
set $upstream "app_v1_0";
set $random $msec; # Текущее время в мс
if ($random % 100 <= 5) {
set $upstream "app_v1_1"; # 5% на новую версию
}
proxy_pass http://$upstream;
}
}
Мониторинг и метрики
from prometheus_client import start_http_server, Counter, Gauge, Histogram
import time
# Метрики для tracking
request_count = Counter(
"requests_total",
"Total requests",
["version", "endpoint", "method"],
)
error_count = Counter(
"errors_total",
"Total errors",
["version", "error_type"],
)
response_time = Histogram(
"response_seconds",
"Response time",
["version"],
buckets=(0.1, 0.5, 1.0, 2.5, 5.0),
)
# Запуск метрик сервера
start_http_server(8001)
def process_request(version):
start = time.time()
try:
# Обработка запроса
result = business_logic()
duration = time.time() - start
# Фиксирование метрик
request_count.labels(version=version, endpoint="/api/data", method="GET").inc()
response_time.labels(version=version).observe(duration)
return result
except Exception as e:
error_count.labels(version=version, error_type=type(e).__name__).inc()
raise
Критерии отката (Rollback)
# Если метрики показывают проблемы, откатить на старую версию
error_rate_threshold = 0.05 # 5% ошибок
latency_threshold = 1.0 # 1 секунда
def should_rollback(metrics):
v1_1_error_rate = metrics["v1.1"]["error_rate"]
v1_1_p99_latency = metrics["v1.1"]["p99_latency"]
v1_0_error_rate = metrics["v1.0"]["error_rate"]
# Если ошибки значительно выше
if v1_1_error_rate > v1_0_error_rate * 2:
return True
# Если latency выше threshold
if v1_1_p99_latency > latency_threshold:
return True
return False
Сценарий полного развертывания
Время | Версия v1.0 | Версия v1.1 | Статус
-------|-------------|-------------|------------------
0 мин | 100% | 0% | Развертывание началось
5 мин | 95% | 5% | Мониторинг (canary)
15 мин | 90% | 10% | Увеличение (OK)
30 мин | 75% | 25% | Дальнейшее увеличение
45 мин | 50% | 50% | Полусеride
60 мин | 25% | 75% | Почти готово
75 мин | 0% | 100% | Полное развертывание
Преимущества
- Минимальный риск: только 5% пользователей затронуты ошибками
- Ранее обнаружение: проблемы выявляются до полного развертывания
- Быстрый rollback: если что-то не так, легко откатить
- Реальные данные: тестируется на реальном трафике
- Zero-downtime: пользователи не заметят развертывания
Инструменты для Canary Deployment
- Kubernetes с Istio/Linkerd
- ArgoCD для GitOps
- Flagger для automated canary
- Nginx с custom конфигом
- AWS CodeDeploy (managed service)
- Jenkins с custom scripts
Итоговая схема
Canary Deployment — это безопасная стратегия развертывания, при которой новая версия сначала развертывается для малого % пользователей, затем постепенно раскатывается на всех, с мониторингом и возможностью быстрого отката при появлении проблем.