Настройка Rolling Update деплоя для веб-приложения
Rolling Update — постепенная замена инстансов приложения: сначала обновляется 1–2 подa/контейнера, проверяется их здоровье, затем следующие. В отличие от Blue-Green, не требует двойных ресурсов, но кратковременно сосуществуют старая и новая версии.
Rolling Update в Kubernetes
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
replicas: 6
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 2 # добавить до 2 лишних пода при обновлении
maxUnavailable: 1 # максимум 1 под недоступен в любой момент
minReadySeconds: 30 # под считается готовым через 30 сек после старта
selector:
matchLabels: { app: myapp }
template:
metadata:
labels: { app: myapp }
spec:
containers:
- name: myapp
image: registry.example.com/myapp:v1.1.0
readinessProbe:
httpGet:
path: /health/ready
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
failureThreshold: 3
livenessProbe:
httpGet:
path: /health/live
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
terminationGracePeriodSeconds: 60 # дать время завершить обработку запросов
# Обновить образ
kubectl set image deployment/myapp myapp=registry.example.com/myapp:v1.2.0
# Следить за прогрессом
kubectl rollout status deployment/myapp
# История
kubectl rollout history deployment/myapp
# Откат
kubectl rollout undo deployment/myapp
kubectl rollout undo deployment/myapp --to-revision=3
Graceful Shutdown
// Node.js/Express — корректное завершение при SIGTERM
process.on('SIGTERM', async () => {
console.log('SIGTERM received, shutting down gracefully');
// Перестать принимать новые соединения
server.close(() => {
console.log('HTTP server closed');
});
// Дать время завершить текущие запросы
await new Promise(resolve => setTimeout(resolve, 30_000));
// Закрыть соединения с БД
await db.destroy();
process.exit(0);
});
// Laravel/Octane — graceful stop
// Octane сам обрабатывает SIGTERM, дожидается завершения запросов
// В Dockerfile используют:
STOPSIGNAL SIGTERM
Rolling Update в Docker Swarm
# docker-compose.yml
services:
web:
image: registry.example.com/myapp:latest
deploy:
replicas: 4
update_config:
parallelism: 1 # обновлять по 1 за раз
delay: 30s # 30 секунд между обновлениями
failure_action: rollback
monitor: 60s # мониторить 60 сек после обновления пода
max_failure_ratio: 0.1
rollback_config:
parallelism: 2
delay: 0s
failure_action: pause
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
# Обновить сервис
docker service update --image registry.example.com/myapp:v1.2.0 myapp_web
# Следить
docker service ps myapp_web
# Откат
docker service rollback myapp_web
Health Check Endpoint
Для корректного rolling update необходим health check, различающий liveness и readiness:
// Laravel — health check routes
Route::get('/health/live', function () {
// Просто проверить, что процесс жив
return response()->json(['status' => 'ok']);
});
Route::get('/health/ready', function () {
// Проверить готовность принимать трафик
try {
DB::connection()->getPdo();
Cache::store()->get('health-check');
} catch (\Exception $e) {
return response()->json(['status' => 'not ready', 'error' => $e->getMessage()], 503);
}
return response()->json(['status' => 'ready']);
});
Проблема несовместимых миграций
При Rolling Update кратковременно работают две версии приложения. Схема БД должна быть совместима с обеими:
Правило: миграции запускать до деплоя нового кода. Миграция должна быть backward-compatible.
// НЕЛЬЗЯ: сразу переименовать колонку
// Схема сломает старую версию
// МОЖНО: трёхэтапный деплой
// Deploy 1: добавить new_column (nullable)
// Deploy 2: заполнить new_column, перейти на него в коде
// Deploy 3: удалить old_column
Срок реализации
- Kubernetes Rolling Update с health checks: 2–3 дня
- Docker Swarm rolling update: 1–2 дня
- Стратегия обратно-совместимых миграций: 1 день







