Rolling update: обновление без простоя
Как Deployment переливает трафик со старого ReplicaSet на новый, что делают maxSurge и maxUnavailable, откуда берутся ревизии.
Что делает Deployment при обновлении
Deployment - объект Kubernetes, который держит нужное число одинаковых Pod. Pod - наименьшая единица, которую запускает Kubernetes, внутри неё работает контейнер. ReplicaSet - объект, который следит, чтобы число Pod совпадало с заданным.
Deployment хранит шаблон Pod в поле spec.template. Шаблон меняется:
новый образ, новые env, новые resources. После этого Deployment
создаёт новый ReplicaSet и запускает плавный переход.
Старый ReplicaSet постепенно сжимается до нуля Pod. Новый растёт до нужного числа реплик. Этот плавный переход и называют rolling update.
RS старый (v1) ●●● → ··· 3 → 0 Pod
RS новый (v2) ··· → ●●● 0 → 3 Pod
Поведением перехода управляет блок spec.strategy:
spec:
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
maxSurge - сколько Pod сверх replicas разрешено поднять на время
перехода. При replicas: 3 и 25% получится один лишний Pod.
maxUnavailable - сколько Pod из старого набора разрешено выключить
до подъёма новых. При нуле новые Pod поднимаются первыми, и только
потом гасятся старые.
По умолчанию оба значения равны 25%. На тесном кластере ставят
maxSurge: 0, чтобы не плодить лишние Pod. Если приложению важна
доступность, ставят maxUnavailable: 0, тогда новые Pod поднимаются
раньше выключения старых.
| Поле | Что разрешает | Значение 0 |
|---|---|---|
maxSurge | лишние Pod сверх replicas | ни одного лишнего Pod, переход медленнее |
maxUnavailable | недостающие Pod из старого набора | сначала поднять новый, потом гасить старый |
Вторая стратегия - Recreate. Она сначала убивает все старые Pod,
потом поднимает все новые. Здесь гарантирован короткий простой. Она
нужна приложениям, которые не работают в двух версиях одновременно.
kubectl set image
kubectl - командная утилита для управления Kubernetes. Поменять
образ можно через правку YAML и kubectl apply. В проде чаще делают
это одной командой:
kubectl set image deploy/app app=nginx:1.27
Слева от = имя контейнера в Deployment, справа новый образ. Команда
правит spec.template, и rolling update запускается сразу.
Дождаться окончания перехода:
kubectl rollout status deploy/app
Команда вернёт нулевой код выхода, когда все реплики станут Ready на новом образе.
Если указать тег, которого нет в registry, kubelet не сможет скачать
образ. Новый Pod застрянет в статусе ErrImagePull, потом
ImagePullBackOff, и rollout status будет ждать его Ready бесконечно.
При maxUnavailable: 0 старые Pod продолжают обслуживать трафик, так
что простоя нет, но переход не завершится, пока образ не починят или
не откатятся назад.
Чтобы зафиксировать причину обновления, добавляют annotation. Annotation - произвольная пометка на объекте в формате ключ-значение.
kubectl annotate deploy/app kubernetes.io/change-cause="upgrade to 1.27"
Эта annotation попадёт в rollout history в колонку CHANGE-CAUSE.
rollout history
Команда kubectl rollout history deploy/app показывает все ревизии.
Ревизия - сохранённая версия шаблона Pod на момент изменения.
REVISION CHANGE-CAUSE
1 <none>
2 upgrade to 1.27
За каждой ревизией стоит отдельный ReplicaSet. Сам Deployment
ссылается на текущую через annotation
deployment.kubernetes.io/revision.
Сколько ReplicaSet остаётся в истории, задаёт поле
spec.revisionHistoryLimit. По умолчанию это 10. При значении 0
история стирается, и откатить будет некуда.
Посмотреть полный шаблон конкретной ревизии:
kubectl rollout history deploy/app --revision=2
Команда покажет образ, env, ports для этой ревизии без отката.
Откат в двух словах
Если новая версия оказалась битой, переход разворачивают обратно:
kubectl rollout undo deploy/app
kubectl rollout undo deploy/app --to-revision=1
Без аргументов команда вернёт ревизию N-1. После отката номер ревизии не повторяется. Откатились с revision=2 на revision=1 - в истории появится revision=3 с тем же шаблоном, что был у revision=1. Номер всегда растёт, история остаётся линейной. Что при этом происходит с ReplicaSet под капотом, разбирает следующий урок.
Полезные команды
# Что есть прямо сейчас
kubectl get deploy app -o wide
kubectl get rs -l app=app
# Текущий образ
kubectl get deploy app -o jsonpath='{.spec.template.spec.containers[0].image}'
# История
kubectl rollout history deploy/app
Домашка
Теорию закрепляет задание на своём кластере: 3 шага с проверкой. Кластер поднимается по треку Kubernetes локально, задания лежат в репозитории k8s-practice.
./run.sh start k8s-rolling-update # развернуть стартовое состояние
./run.sh verify k8s-rolling-update # проверить текущий шаг
Коротко
- Смена
spec.templateсоздаёт новый ReplicaSet, старый сжимается до нуля. maxSurgeразрешает лишние Pod,maxUnavailableразрешает недостающие.maxUnavailable: 0держит доступность,maxSurge: 0экономит ресурсы кластера.Recreateгасит всё разом, годится приложениям без совместимости версий.- Битый тег образа не роняет прод, но подвешивает rollout в ImagePullBackOff.
change-causeчерез annotation делает историю ревизий читаемой.
Прошли материал до конца? Отметьте урок пройденным.
Прогресс сохранён в этом браузере
Почистишь историю или откроешь с телефона, и отметки пропадут. Оставь почту, они переедут в аккаунт. Пароль придумывать не нужно.
Готово. теперь в аккаунте: прогресс виден с любого устройства. Мой прогресс