Ответ
Для StatefulSet с stateful-приложениями (например, Kafka, Elasticsearch, базы данных) я использую стратегию RollingUpdate с управляемым порядком и проверками готовности, чтобы гарантировать доступность и сохранность данных.
Ключевые настройки в манифесте StatefulSet:
apiVersion: apps/v1
kind: StatefulSet
spec:
updateStrategy:
type: RollingUpdate
rollingUpdate:
# partition: 2 # Управляет порядком обновления (см. ниже)
podManagementPolicy: OrderedReady # Дефолтное поведение: обновление по одному
replicas: 3
template:
spec:
containers:
- name: app
readinessProbe: # КРИТИЧНО! Подает трафик только когда под готов
httpGet:
path: /health
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
lifecycle:
preStop: # Дает время на graceful shutdown
exec:
command: ["sh", "-c", "sleep 30 && /bin/graceful_shutdown.sh"]
Процесс обновления (например, образа контейнера):
- Поэтапное обновление (Canary для StatefulSet): Использую поле
partition. Если установитьpartition: 2для StatefulSet с 3 репликами, Kubernetes обновит только поды с индексами 2 и выше (т.е. под с индексом 2). Поды 0 и 1 останутся на старой версии.kubectl patch statefulset my-app -p '{"spec":{"updateStrategy":{"rollingUpdate":{"partition":2}}}}' kubectl set image statefulset/my-app app=myrepo/app:v2.0.0 - Проверка: После обновления пода-2 тщательно проверяю его работу, метрики и репликацию данных (если это БД).
- Продвижение обновления: Если все в порядке, уменьшаю
partitionдо 1, чтобы обновился под-1, затем до 0 для пода-0. Это гарантирует, что как минимум один лидер (часто это под-0) всегда на старой, стабильной версии до последнего момента.
Дополнительные меры для баз данных:
- Для мастер-реплика структур (например, PostgreSQL с Patroni) сначала обновляю реплики, затем вручную выполняю switchover, чтобы мастером стала уже обновленная реплика, и затем обновляю старый мастер.
- Всегда предварительно тестирую процедуру обновления и отката на staging-окружении, имитирую сбои пода во время обновления.