Как выполнять обновления Kubernetes Deployments с нулевым временем простоя (Zero-Downtime Rolling Updates)
Введение
В современных архитектурах микросервисов поддержание непрерывной доступности во время обновлений приложений является обязательным требованием. Kubernetes Deployments упрощают этот процесс, предлагая автоматизированные поэтапные обновления (Rolling Updates) — стратегию, предназначенную для постепенной замены старых версий Подов новыми.
Однако для достижения истинного нулевого простоя требуется нечто большее, чем стандартная конфигурация Kubernetes. Это требует тщательной координации между манифестом Deployment, конечными точками работоспособности приложения и процессом корректного завершения работы.
В этом руководстве представлен комплексный пошаговый подход к настройке Kubernetes Deployments, чтобы обновления приложений проходили беспрепятственно и были незаметны для конечного пользователя.
Мы рассмотрим критически важную роль проверок готовности (readiness probes), как настроить параметры стратегии развертывания (maxSurge и maxUnavailable), а также лучшие практики для завершения работы приложения, чтобы исключить перерывы в обслуживании во время переходов развертывания.
Предпосылки для нулевого времени простоя
Прежде чем настраивать манифест Kubernetes, базовое приложение должно соответствовать определенным принципам, чтобы поддерживать развертывание с нулевым простоем:
- Обратная совместимость приложения: В течение короткого периода, когда одновременно работают старая и новая версии приложения, они должны быть совместимы с общими ресурсами (базы данных, очереди, кэши).
- Идемпотентность: Операции, которые могут обрабатываться обеими версиями, должны быть повторяемыми без негативных побочных эффектов.
- Корректное завершение работы: Приложение должно быть запрограммировано на распознавание сигнала
SIGTERM, отправляемого Kubernetes, и корректное прекращение приема новых соединений, завершая при этом активные запросы перед выходом.
Понимание стратегии поэтапного обновления Kubernetes
По умолчанию в Kubernetes Deployments используется стратегия RollingUpdate. Этот метод гарантирует, что старая версия приложения не будет полностью остановлена до того, как новая версия станет работоспособной, управляя переходом с помощью двух основных параметров:
| Параметр | Описание | Влияние на нулевой простой |
|---|---|---|
maxSurge |
Определяет максимальное количество Подов, которое может быть создано сверх желаемого числа реплик. Может быть абсолютным числом или процентом (по умолчанию: 25%). | Контролирует скорость развертывания и обеспечивает временное увеличение мощности. |
maxUnavailable |
Определяет максимальное количество Подов, которые могут быть недоступны во время обновления. Может быть абсолютным числом или процентом (по умолчанию: 25%). | Критически важно для нулевого простоя. Установка этого значения в 0% означает, что ни один обслуживающий Под не будет завершен до тех пор, пока новые Поды полностью не станут Ready (Готовыми). |
Рекомендуемая стратегия для нулевого времени простоя
Для максимальной доступности наилучшая конфигурация часто заключается в обеспечении отсутствия потерь мощности в период простоя:
maxUnavailable: 0(Гарантировать, что мощность никогда не падает).maxSurge: 1или25%(Позволить мощности ненадолго превысить целевое значение, гарантируя, что новый Под будет готов до того, как старый будет завершен).
Шаг 1: Реализация проверок готовности (Readiness Probes)
Проверка готовности (Readiness Probe) — это самый важный механизм для обеспечения обновлений с нулевым простоем. Kubernetes полагается на эту проверку, чтобы определить, готов ли новый Под принимать пользовательский трафик и продолжает ли старый Под активно обслуживать трафик.
Liveness против Readiness
- Liveness Probe (Проверка работоспособности): Сообщает Kubernetes, здоров ли и функционален контейнер. Если проверка не пройдена, контейнер перезапускается.
- Readiness Probe (Проверка готовности): Сообщает Kubernetes, готов ли контейнер обслуживать запросы. Если проверка не пройдена, Под удаляется из конечных точек связанного Сервиса, перенаправляя трафик от него, пока он не станет готов.
Для поэтапных обновлений Проверка готовности используется для управления переходом. Kubernetes не начнет завершать старый Под до тех пор, пока недавно созданный Под успешно не пройдет проверку готовности.
# Фрагмент deployment.yaml
spec:
containers:
- name: my-app
image: myregistry/my-app:v2.0
ports:
- containerPort: 8080
# --- Конфигурация проверки готовности ---
readinessProbe:
httpGet:
path: /health/ready
port: 8080
initialDelaySeconds: 15 # Время ожидания перед первой попыткой проверки
periodSeconds: 5 # Как часто выполнять проверку
timeoutSeconds: 3
failureThreshold: 3 # Количество последовательных сбоев для пометки Пода как неготового
# --- Конфигурация проверки работоспособности (стандартная проверка здоровья) ---
livenessProbe:
httpGet:
path: /health/live
port: 8080
initialDelaySeconds: 60
periodSeconds: 10
Совет: Убедитесь, что конечная точка
/health/readyвашего приложения возвращает код успеха (HTTP 200-299) только тогда, когда инициализация, подключения к базе данных и другие внешние зависимости полностью работоспособны.
Шаг 2: Настройка стратегии развертывания
Чтобы потребовать истинного нулевого простоя, мы явно настраиваем стратегию поэтапного обновления, чтобы предотвратить любое падение количества доступных реплик.
В этой конфигурации Kubernetes сначала создаст новый Под (maxSurge: 1). Только после того, как новый Под пройдет проверку готовности, Kubernetes завершит старый Под. Поскольку maxUnavailable равно 0, мощность сервиса никогда не опускается ниже целевого количества реплик.
# Фрагмент deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-web-deployment
spec:
replicas: 4
strategy:
type: RollingUpdate
rollingUpdate:
# Гарантирует, что мощность никогда не опускается ниже желаемого количества реплик (4)
maxUnavailable: 0
# Позволяет создать один дополнительный Под во время развертывания
maxSurge: 1
template:
# ... спецификация контейнера ...
Шаг 3: Обеспечение корректного завершения работы
Даже при надежных проверках готовности, если приложение немедленно завершает работу после получения сигнала завершения, оно рискует потерять активные запросы.
Kubernetes следует определенной последовательности завершения работы:
- Под помечается как Terminating (Завершается).
- Под удаляется из конечных точек Сервиса (трафик перестает направляться на него).
- Выполняется хук pre-stop (если определен).
- Контейнер получает сигнал
SIGTERM. - Kubernetes ожидает длительность, определенную
terminationGracePeriodSeconds(по умолчанию: 30 секунд). - Если контейнер все еще работает, он получает безапелляционный сигнал
SIGKILL.
Для обеспечения корректного завершения работы приложение должно обрабатывать SIGTERM, а terminationGracePeriodSeconds должно быть достаточно долгим, чтобы приложение успело завершить существующие запросы.
# Фрагмент deployment.yaml, внутри спецификации контейнера
terminationGracePeriodSeconds: 45 # Увеличенное время для корректного завершения работы
containers:
- name: my-app
image: myregistry/my-app:v2.0
lifecycle:
preStop:
exec:
# Пример: Запуск скрипта для немедленного сброса соединений
command: ["/bin/sh", "-c", "sleep 10"]
Лучшая практика: Время между сбоем Проверки готовности Пода (Шаг 2) и получением сигнала
SIGTERM(Шаг 4) является критическим. Если ваше приложение корректно обрабатываетSIGTERM, установка немного большего значенияterminationGracePeriodSeconds(например, 45 или 60 секунд) предотвращает жесткое завершение работы.
Шаг 4: Выполнение и мониторинг обновления
Как только ваш манифест Deployment будет включать оптимизированную стратегию и надежные проверки, выполнение обновления становится простым.
-
Обновите тег образа: Измените манифест развертывания, чтобы отразить новую версию образа (например, с
v2.0наv2.1). -
Примените конфигурацию:
bash kubectl apply -f deployment.yamlИли вы можете исправить образ напрямую:
bash kubectl set image deployment/my-web-deployment my-app=myregistry/my-app:v2.1 -
Отслеживайте статус развертывания: Наблюдайте, как Kubernetes проходит этапы, проверяя, что количество готовых Подов никогда не опускается ниже желаемого числа.
bash kubectl rollout status deployment/my-web-deployment -
Проверьте доступность Подов: Наблюдайте за статусом Подов, чтобы убедиться, что старые Поды (v2.0) корректно завершают работу только после того, как новые Поды (v2.1) полностью готовы.
bash kubectl get pods -l app=my-web-deployment -w
Дополнительные соображения
Использование бюджетов прерывания Подов (Pod Disruption Budgets, PDB)
В то время как стратегия развертывания управляет добровольными обновлениями, Бюджет прерывания Подов (PDB) гарантирует минимальное количество доступных Подов даже при незапланированных сбоях (например, обслуживание узлов, обновления кластера). Хотя PDBs напрямую не контролируют скорость поэтапного обновления, они служат мерой безопасности.
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: my-app-pdb
spec:
minAvailable: 75% # Гарантировать, что как минимум 75% реплик всегда доступны
selector:
matchLabels:
app: my-web-deployment
Важность начальной задержки
Если вашему приложению требуется время на разогрев (например, загрузка больших файлов конфигурации или создание кэшей), убедитесь, что initialDelaySeconds в вашей Проверке готовности достаточно велико. Если проверка срабатывает слишком рано и завершается неудачей, Под будет помечен как нездоровый и может застрять в цикле сбоев, останавливая все развертывание.
Заключение
Достижение истинных поэтапных обновлений Kubernetes с нулевым простоем — это сочетание надежной конфигурации платформы и дисциплинированной разработки приложений. Правильно используя Проверки готовности для сигнализации о рабочем состоянии, настраивая стратегию развертывания (maxUnavailable: 0) для поддержания мощности и реализуя обработчики корректного завершения работы, вы можете гарантировать, что обновления приложений выполняются надежно, не прерывая обслуживание ваших пользователей. Всегда тщательно тестируйте процесс обновления в промежуточной среде, чтобы проверить логику периода ожидания завершения работы и проверок.