💤 Как усыпить livenessProbe на время долгой миграции 〰️ и почему initialDelaySeconds для этого не подходит
Классическая ситуация 〰️ приложению на старте нужно прогнать миграции через Liquibase или Alembic. Заранее неизвестно, сколько это займёт 〰️ 10 минут, час или несколько часов.
А livenessProbe уже через пару минут начинает возвращать ошибки, и kubelet перезапускает контейнер прямо посреди миграции.
Разберёмся, почему простое увеличение initialDelaySeconds 〰️ не лучшее решение и какие параметры действительно позволяют пережить долгий старт.
✔️ readinessProbe 🆚 livenessProbe
✅ Провал readinessProbe
🔵 Pod остаётся работать
🔵 Kubernetes перестаёт направлять на него трафик
🔵 Pod никто не перезапускает
✅ Провал livenessProbe
🔵 превышен failureThreshold
🔵 kubelet перезапускает контейнер
Эти проверки полностью независимы друг от друга 〰️ изменение одной никак не влияет на вторую.
✔️ initialDelaySeconds 〰️ это просто пауза
Пока не истечёт initialDelaySeconds, kubelet вообще не выполняет проверку.
Если задать
initialDelaySeconds: 28800 # 8 часов до первой проверки
то даже если приложение полностью запустится через 5 минут, первая проверка всё равно произойдёт только через 8 часов.
То есть это не терпение, а обычная задержка перед началом проверок.
✔️ failureThreshold × periodSeconds 〰️ верхняя граница терпения
А вот это уже другое.
После окончания initialDelaySeconds проверки начинают выполняться регулярно.
Как только health-эндпоинт впервые отвечает успешно, счётчик ошибок сразу сбрасывается в ноль, и livenessProbe снова начинает успешно проходить. Неважно, произошло это через 10 минут или через 7 часов 〰️ никакого ожидания окончания окна не происходит.
Максимальное время до рестарта можно приблизительно оценить так
initialDelaySeconds + failureThreshold × periodSeconds
Например, нужно дать приложению до 8 часов на выполнение миграций, но не ждать эти 8 часов, если всё пройдёт быстрее.
livenessProbe:
path: /actuator/health/liveness
initialDelaySeconds: 150
periodSeconds: 5
failureThreshold: 5730 # (28800 - 150) / 5 ≈ 8 часов запаса
Получаем примерно 8 часов запаса, но если приложение станет готово раньше, livenessProbe сразу начнёт успешно проходить и никаких дополнительных ожиданий не будет.
✔️ Не забываем про readiness
Если увеличить только livenessProbe, а readinessProbe оставить со стандартными значениями, получится странная ситуация
🔵 Pod продолжит работать.
🔵 Рестартов контейнера не будет.
🔵 Kubernetes перестанет направлять на Pod трафик.
Поэтому на время долгих миграций обычно имеет смысл синхронизировать параметры обеих проверок, чтобы поведение было предсказуемым 〰️ пока приложение не готово, Kubernetes не направляет трафик на Pod, а livenessProbe не приводит к рестарту контейнера.
readinessProbe:
path: /actuator/health/readiness
timeoutSeconds: 5
periodSeconds: 5
initialDelaySeconds: 150
failureThreshold: 5730 # тоже 8 часов, чтобы не было рассинхрона с liveness
✔️ Важный компромисс
У такого решения есть цена.
Пока действует большое окно терпения, livenessProbe практически перестаёт защищать от настоящих зависаний приложения. Если приложение действительно зависнет или перестанет отвечать, контейнер может оставаться в таком состоянии до окончания настроенного окна.
Поэтому это не постоянная настройка, а временная мера на время долгих миграций. После успешной раскатки значения failureThreshold лучше вернуть к обычным.
✔️ ПЫСЫ Да, для подобных сценариев Kubernetes рекомендует использовать startupProbe. Но у нас их нет, да и если прямо перед ПРОД-релизом не хочется менять уже проверенную схему health checks, временное увеличение окна терпения у livenessProbe может быть вполне рабочим компромиссом.
#livenessProbe #readinessProbe #k8s #Liquibase #Alembic #DevOps
Классическая ситуация 〰️ приложению на старте нужно прогнать миграции через Liquibase или Alembic. Заранее неизвестно, сколько это займёт 〰️ 10 минут, час или несколько часов.
А livenessProbe уже через пару минут начинает возвращать ошибки, и kubelet перезапускает контейнер прямо посреди миграции.
Разберёмся, почему простое увеличение initialDelaySeconds 〰️ не лучшее решение и какие параметры действительно позволяют пережить долгий старт.
✔️ readinessProbe 🆚 livenessProbe
✅ Провал readinessProbe
🔵 Pod остаётся работать
🔵 Kubernetes перестаёт направлять на него трафик
🔵 Pod никто не перезапускает
✅ Провал livenessProbe
🔵 превышен failureThreshold
🔵 kubelet перезапускает контейнер
Эти проверки полностью независимы друг от друга 〰️ изменение одной никак не влияет на вторую.
✔️ initialDelaySeconds 〰️ это просто пауза
Пока не истечёт initialDelaySeconds, kubelet вообще не выполняет проверку.
Если задать
initialDelaySeconds: 28800 # 8 часов до первой проверки
то даже если приложение полностью запустится через 5 минут, первая проверка всё равно произойдёт только через 8 часов.
То есть это не терпение, а обычная задержка перед началом проверок.
✔️ failureThreshold × periodSeconds 〰️ верхняя граница терпения
А вот это уже другое.
После окончания initialDelaySeconds проверки начинают выполняться регулярно.
Как только health-эндпоинт впервые отвечает успешно, счётчик ошибок сразу сбрасывается в ноль, и livenessProbe снова начинает успешно проходить. Неважно, произошло это через 10 минут или через 7 часов 〰️ никакого ожидания окончания окна не происходит.
Максимальное время до рестарта можно приблизительно оценить так
initialDelaySeconds + failureThreshold × periodSeconds
Например, нужно дать приложению до 8 часов на выполнение миграций, но не ждать эти 8 часов, если всё пройдёт быстрее.
livenessProbe:
path: /actuator/health/liveness
initialDelaySeconds: 150
periodSeconds: 5
failureThreshold: 5730 # (28800 - 150) / 5 ≈ 8 часов запаса
Получаем примерно 8 часов запаса, но если приложение станет готово раньше, livenessProbe сразу начнёт успешно проходить и никаких дополнительных ожиданий не будет.
✔️ Не забываем про readiness
Если увеличить только livenessProbe, а readinessProbe оставить со стандартными значениями, получится странная ситуация
🔵 Pod продолжит работать.
🔵 Рестартов контейнера не будет.
🔵 Kubernetes перестанет направлять на Pod трафик.
Поэтому на время долгих миграций обычно имеет смысл синхронизировать параметры обеих проверок, чтобы поведение было предсказуемым 〰️ пока приложение не готово, Kubernetes не направляет трафик на Pod, а livenessProbe не приводит к рестарту контейнера.
readinessProbe:
path: /actuator/health/readiness
timeoutSeconds: 5
periodSeconds: 5
initialDelaySeconds: 150
failureThreshold: 5730 # тоже 8 часов, чтобы не было рассинхрона с liveness
✔️ Важный компромисс
У такого решения есть цена.
Пока действует большое окно терпения, livenessProbe практически перестаёт защищать от настоящих зависаний приложения. Если приложение действительно зависнет или перестанет отвечать, контейнер может оставаться в таком состоянии до окончания настроенного окна.
Поэтому это не постоянная настройка, а временная мера на время долгих миграций. После успешной раскатки значения failureThreshold лучше вернуть к обычным.
✔️ ПЫСЫ Да, для подобных сценариев Kubernetes рекомендует использовать startupProbe. Но у нас их нет, да и если прямо перед ПРОД-релизом не хочется менять уже проверенную схему health checks, временное увеличение окна терпения у livenessProbe может быть вполне рабочим компромиссом.
#livenessProbe #readinessProbe #k8s #Liquibase #Alembic #DevOps