В кластере Kubernetes нода может умереть или перезапуститься.
Инструменты вроде Kubernetes обеспечивают высокую доступность, спроектированы для надёжного функционирования и автоматического восстановления в подобных сценариях, и Kubernetes действительно прекрасно со всем этим справляется.
Однако вы можете заметить: когда нода падает, поды сломанной ноды на протяжении какого-то времени всё ещё запущены и получают запросы, которые уже не выполняются.
И по умолчанию это время, как мне кажется, слишком велико — его можно уменьшить. На него влияют несколько параметров, настраиваемых в Kubelet и Controller Manager.
Вот описание процессов, которые возникают, когда нода падает:
1. Kubelet отправляет свой статус мастерам с -node-status-update-frequency=10s;
2. Нода в Kubernetes умирает.
3. Демон kube-controller-manager, который мониторит ноды, с интервалом -node-monitor-period=5s проверяет в мастерах статус ноды, полученный от Kubelet.
4. Kube-controller-manager видит, что нода не отвечает, и на протяжении мягкого интервала -node-monitor-grace-period=40s ожидает, стоит ли считать ноду проблемной. Этот параметр должен равняться node-status-update-frequency, умноженному на N, где N — количество попыток, разрешённых Kubelet для отправки статуса ноды. N — константа, для которой в коде определёно значение 5 (см. переменную nodeStatusUpdateRetry в kubelet/kubelet.go).
Обратите внимание, что значение по умолчанию не соответствует тому, что говорится в документации, потому что:
node-status-update-frequency × N != node-monitor-grace-period (10 × 5 != 40)
Насколько я понимаю, 5 попыток отправки статуса (каждая по 10 секунд) выполняются за 40 секунд, потому что первая выполняется сразу, а вторая и последующие — по 10 секунд. В результате, пять попыток завершаются за 40 секунд.
То есть реальная формула выглядит следующим образом:
node-status-update-frequency × (N-1) != node-monitor-grace-period
Подробности можно увидеть в коде controller/node/nodecontroller.go.
5. Когда нода отмечена проблемной, kube-controller-manager удаляет поды с применением параметра -pod-eviction-timeout=5m0s.
Это очень важный таймаут и по умолчанию он равен 5 минутам, что, на мой взгляд, очень большое значение. Хотя нода уже отмечена как проблемная, kube-controller-manager в течение указанного времени не удалит её поды, поэтому они будут доступны через свои службы, но запросы к ним не выполнятся.
6. Kube-proxy постоянно наблюдает за статусами через API, поэтому сразу же заметит момент, когда поды выведены из строя, и обновит правила iptables для ноды, после чего упавшие поды перестанут быть доступными.
Итак, упомянутые значения можно изменить, чтобы уменьшить количество невыполненных запросов, когда нода падает.
Для своего кластера Kubernetes я их настроил следующим образом:
- kubelet: node-status-update-frequency=4s (вместо 10s)
- controller-manager: node-monitor-period=2s (вместо 5s)
- controller-manager: node-monitor-grace-period=16s (вместо 40s)
- controller-manager: pod-eviction-timeout=30s (вместо 5m)
Результаты достаточно хороши: падение ноды определяется не за 5 минут 40 секунд, а за 46 секунд.
P.S. От переводчика: для себя мы пока подбираем оптимальные значения в зависимости от конфигурации сети (один или разные ЦОД, одна стойка и т.п.) и планируем поделиться результатами изысканий (т.е. оптимальных значений), когда они будут получены опытным путём.
Автор: Флант