K8s Q A PodDisruptionBudget
PodDisruptionBudget (PDB)
Механизм PodDisruptionBudget (PDB) — это must have для работы приложения в production-среде. Он позволяет контролировать, какое количество pod’ов приложения могут быть недоступны в момент времени. Читая первую часть статьи, можно было подумать, что мы уже ко всему подготовлены, если у приложения запущены несколько реплик и прописан podAntiAffinity, который не позволит pod’ам schedule’иться на один и тот же узел. Однако может случиться ситуация, при которой из эксплуатации одновременно выйдет не один узел. Например, вы решили поменять инстансы на более мощные. Могут быть и другие причины, но сейчас это не так важно. Важно, что несколько узлов выведены из эксплуатации в один момент времени. «Это же Kubernetes! — скажете вы. — Тут всё эфемерно. Ну, переедут pod’ы на другие узлы — что такого?» Давайте разберёмся. Предположим, приложение состоит из 3-х реплик. Нагрузка распределена равномерно по ним, а pod’ы — по узлам. Оно выдержит, если упадет одна из реплик. Но вот при падении двух реплик из трёх начнётся деградация сервиса: один pod просто не справится с нагрузкой, клиенты начнут получать 500-е ошибки. Ок, если мы подготовились и заранее прописали rate limit в контейнере c nginx (конечно, если у нас есть контейнер с nginx в pod’е…), то ошибки будут 429-е. Но это все равно деградация сервиса. Тут нам на помощь и приходит PodDisruptionBudget. Взглянем на его манифест: apiVersion: policy/v1beta1 kind: PodDisruptionBudget metadata:
name: app-pdb
spec:
maxUnavailable: 1 selector: matchLabels: app: app
Конфиг довольно простой, и большая часть полей в нем скорее всего знакома (по аналогии с другими манифестами). Самое интересное — это maxUnavailable. Данное поле позволяет указать, сколько pod’ов (максимум) могут быть недоступны в момент времени. Указывать значение можно как в единицах pod’ов, так и в процентах. Предположим, что для приложения настроен PDB. Что теперь произойдет, когда два или более узлов, на которые выкачены pod’ы приложения, начнут по какой-либо причине вытеснять (evict) pod’ы? PDB позволит вытеснить лишь один pod, а второй узел будет ждать, пока реплик не станет хотя бы две (из трёх). Только после этого еще одну из реплик можно вытеснить. Есть также возможность определять и minAvailable. Например: apiVersion: policy/v1beta1 kind: PodDisruptionBudget metadata:
name: app-pdb
spec:
minAvailable: 80% selector: matchLabels: app: app
Так можно гарантировать, что кластер будет следить за тем, чтобы 80% реплик всегда были доступны, а вытеснять с узлов [при такой необходимости] можно только оставшиеся 20%. Указывать это соотношение снова можно в процентах и единицах. Есть и обратная сторона медали: у вас должно быть достаточное количество узлов, причем с учетом podAntiAffinity. Иначе может сложиться ситуация, что одну реплику вытеснили с узла, а вернуться она никуда не может. Результат: операция drain просто ждет вечность, а вы остаетесь с двумя репликами приложения… В describe pod’а, который висит в Pending, можно, конечно, найти информацию о том, что нет свободных узлов, и исправить ситуацию, но лучше до этого не доводить. Итоговая рекомендация: всегда настраивайте PDB для критичных компонентов вашей системы.