Многоликий controller-manager и бесчисленные api-server’ы

Что делать, когда кластер превращается в тыкву? На этот вопросы мы начали отвечать в предыдущей статье. Сегодня продолжим разбирать способы построения кластеров большого объема.

Первым шагом dBrain.cloud на пути к построению кластеров большого объема стало разделение etcd. Далее мы взялись за controller-manager.

8bc751fd1450723ed86eb912acf6fd9c.png

Как не тратить время на сбор мусора?

У controller-manager«ов есть флажок «controllers». Внутри находится много контроллеров, каждый из которых отвечает за свои объекты: репликасеты, поды и др. При запуске controller-manager горизонтально не скейлится. Пример: есть три реплики controller-manager«ов, они между собой выбирают мастера — и в итоге работает только один.

Какие функции выполняет controller-manager? Он сверяет состояние кластера с эталонным. Controller-manager постоянно ходит по кластеру и сличает текущее состояние с тем, которое записано в etcd, Kubernetes и т.д. Controller-manager проверяет все описания объектов в Kubernetes и ищет, где остались объекты без владельца, то есть динамически созданные Kubernetes, а не пользователями. На одном из наших высоконагруженных проектов с более чем 100 тысячами подов, мы столкнулись с тем, что controller-manager 90 процентов времени тратил на garbage collection. У него просто не было времени заниматься своей непосредственной работой: проверять количество подов, реплики деплойментов, сервисы, записывать адреса и т.д.

Благодаря флажку «controllers» мы разделили controller-manager на три кластера. Вышло как с etcd: три кластера по три controller-manager в каждом, при этом один из них — мастер. Таким образом, у нас получилось три параллельно работающих и выполняющих разные задачи инстанса controller-manager.

b265e50a66bf443a5ff351a3cca8e543.png

Теперь схема работы controller-manager«ов выглядит так: первый взял на себя всю рабочую нагрузку: ReplicaSet, Services, Deployments, StatefulSet и др., второй — garbage collection, просчет ttl и т.д., третий — все остальное: node, pv, pvc, certs и т.д.

Так мы повысили отзывчивость кластера на различные изменения. Garbage collection происходит в отдельном controller-manager, процесс может идти непрерывно, теперь это не влияет на работу кластера.

HPA для регулировки нагрузки и envoy

В dBrain, как и везде, api-серверы находятся в статик-подах и используются сейчас как бутстрапные для того, чтобы запустились кластеры, оверлейная сеть и основные api-серверы — в деплойменте. Их сертификаты мы поместили в секреты Kubernetes, теперь api-серверы могут шедулиться по всему кластеру, а не находиться статически на каких-то нодах. Благодаря таким манипуляциям появляются все плюсы Kubernetes в виде фенси автоскейлинга и отказоустойчивости. Сейчас на api-серверах в dBrain мы настроили HPA (Horizontal Pod Autoscaler), они автоматически скейлятся в зависимости от утилизации. Надеемся, вам будет полезен наш лайфхак:)

В dBrain есть envoy (L4-L7-прокси), который живет на каждом хосте. Он работает как прокси на статик-поды api-серверов и на api-серверы в деплойментах и реализует доступность kube api на всех хостах кластера, чтобы kubelet«ы, controller-manager-ы и scheduler могли работать. И здесь встает извечный вопрос: чтобы было раньше — курица или яйцо? Кластер должен подняться, а для этого нужны работающие api-серверы. Если api-серверы в деплойменте, то кластер не поднимется. Поэтому в envoy реализованы приоритеты по хелсчекам, если api-серверы в гибко скейлящемся горизонтально деплойменте доступны — весь траффик идет на них, в противном случае — на api-серверы в статик-подах.

В платформе более ранних версий у нас был envoy, через который системные компоненты Kubernetes ходили на api-серверы в статик-подах. Раньше api-серверы в деплойментах обрабатывали запросы исключительно изнутри кластера (с сервиса kubernetes.default.svc), также к ним подключались пользователи, которые работают с кластером. Системные же компоненты работали исключительно с api-серверами в статик-подах.

Что касается scheduler, то его, в отличие от controller-manager, скейлить не надо. Scheduler в одном экземпляре, это компонент, который не испытывает постоянной нагрузки и работает около событийно. Например, на больших кластерах он не выгребает все хосты, в попытках что-то куда-то зашедулить. Он берет по дефолту около 10 процентов хостов и пытается зашедулить поды на них, если не получилось, берет следующие 10 процентов и так далее.

Подведем итог: с помощью разделения etcd и controller-manager мы можем работать с большими кластерами так же быстро как с маленькими. Благодаря двум действиям мы смогли устранить проблемы, которые при росте объема кластера приводили к его неадекватной работе и другим побочным действиям.

Теперь у нас кластер любого размера гораздо отзывчивее: его части перестали влиять друг на друга. При администрировании кластера через kubectl компонент не лагает вне зависимости от размера кластера. Сервисы, завязанные на ресурсы самого Kubernetes, стали отрабатывать мгновенно. Идем к 200 тысячам подов в кластере, не переключайтесь ;)

Если вы нашли нашу статью полезной, поделитесь ей со своими коллегами или друзьями — вовлечение и прочтение материалов заряжают нас энтузиазмом для поиска и раскрытия новых интересных тем для вас.

© Habrahabr.ru