Дополнительная обвязка K8s и самописные компоненты в Kubernetes: для чего и кому нужны
Базовых настроек Kubernetes недостаточно, чтобы создать удобную PaaS‑платформу для работы со всеми компонентами K8s кластера и управления множеством кластеров. Мы начинили dBrain большим количеством сервисов для легкого решения этой проблемы. Как наша команда готовит Kubernetes для dBrain.cloud, мы рассказывали здесь. Сегодня познакомим вас с надстройками Kubernetes в платформе dBrain, большая часть которых — наши собственные разработки для отслеживания пограничных состояний кластеров K8s.
Lost-node-cleaner
Этот самописный компонент следит за состоянием хостов в Kubernetes. Когда хост недоступен, поды на нем зависают в состоянии terminating. Пока поды Deployment-ов и StatefulSet-ов находятся в этом состоянии, их невозможно перераспределить на другие ноды. Проблему фиксит lost-node-cleaner. Он проверяет состояние всех хостов. Если находит недоступный, то запускает таймер на две минуты на случай возобновления работы подов на данной ноде. Если хост остается недоступен, lost-node-cleaner удаляет с него все поды, чтобы они могли запуститься на других хостах кластера.
Lb-gen svc
Компонент lb-gen svc облегчает работу с Load Balancer. По умолчанию Kubernetes не предоставляет сервисы подобного рода. Например, когда пользователь создает сервис типа Load Balancer в Google Cloud, у него появляется публичный адрес, он публикуется в интернет и работает. В Kubernetes для реализации подобного функционала есть специальные компоненты MetalLB или PureLB, но они требуют ручного вмешательства (конфигурации их ресурсов). В них нельзя просто создать сервисы вроде Load Balancer, в каждом необходимо вручную проставить аннотации. Это неудобно для пользователя. Поэтому мы написали компонент lb-gen svc: он автоматически проставляет необходимые аннотации, чтобы сервис публиковался по нужному внешнему IP-адресу.
Descheduler
Это стандартная разработка Open Source, которая помогает подам равномерно разъезжаться по нодам. Kubernetes в стандартном флоу kube-scheduler пытается максимально уплотнить каждую ноду по очереди. Descheduler понадобился, чтобы не переписывать kube-scheduler или не создавать для него собственный флоу. Descheduler растягивает поды по нодам таким образом, чтобы они были загружены более равномерно.
Namespace‑controller
Он следит, чтобы неймспейс был правильно сконфигурирован при создании. Когда мы создаем неймспейс во время деплоя, то вписываем у него дефолтные taints, tolerations и др. Когда пользователь создает неймспейс руками или через консоль, то эти параметры туда не прописываются. Сущность namespace‑controller периодически «пробегает» по одноименным неймспейсам и корректирует их параметры.
Node‑problem‑detector
Стандартная разработка, которую мы сконфигурировали под свои запросы. Компонент следит за нодой, а когда на ней возникают проблемы, отправляет соответствующее событие в API-сервер. Вся информация по статусам таких проверок также отображается в дескрайбе ноды. Это детектор проблем, связанных с хостовой операционной системой. Любые проблемы с ОС, такие как kernel deadlock, частые рестарты cri-o и kubelet, синхронизация времени с NTP сервером, могут впоследствии приводить к аномальному поведению в кластере Kubernetes, а node‑problem‑detector их обнаруживает.
Gen‑svc
В платформе dBrain в качестве Ingress-контроллера используется Ingress NGINX. Компонент является реализацией абстракции Ingress в Kubernetes (публикация сервисов по L-7), а также может существовать в режиме TCP или UDP forwarding proxy (L-4). Для публикации какого-то сервиса в режиме TCP или UDP forwarding нужно отредактировать соответствующую configmap Ingress NGINX для TCP или UDP. Gen‑svc редактирует сервисы типа Load Balancer, которые принадлежат Ingress NGINX, и прописывает в них нужные порты, опубликованные пользователем через configmap в режиме TCP или UDP forwarding. Кроме того, gen‑svc следит за наличием Ingress-классов в созданных пользователями Kubernetes Ingress. Без Ingress-класса правила Ingress публиковаться в кластере не будут. Gen‑svc может проставлять Ingress-классы принудительно, но по умолчанию работает в режиме «если класс не указан». То есть если пользователь не задал Ingress-класс, то компонент gen‑svc проставит наш стандартный NGINX.
Lb‑autohealer
Сервис понадобился в процессе эксплуатации PureLB, т.к. у него есть проблемы с отказоустойчивостью.
Обычно в платформе есть три железных сервера, у каждого из которых роль Load Balancer. На них «селится» PureLB, отвечающий за публикацию VIP-адресов на внешних интерфейсах, которые появляются после создания пользователями в кластере сервисов типа Load Balancer. Когда хост выходит из строя, вместе с ним становятся недоступны и эти VIP адреса. PureLB нужно 10–15 минут, чтобы это обнаружить и перенести адрес на другой хост. Случается, что на хосте вышла из строя только часть сервисов. В такой ситуации компонент PureLB может продолжить работу, но связь с оставшимся кластером пропадет. Соответственно, PureLB нескольких хостов будут публиковать один и тот же адрес, и в сети возникнет конфликт адресов. Эту проблему призван решать lb‑autohealer. Он проверяет серверы и при обнаружении конфликта адресов или недоступности IP Load Balancer перезапускает агентов PureLB. При этом они в срочном порядке должны друг с другом «договориться» и опубликовать адреса только на нужных серверах.
У lb‑autohealer есть поддержка MetalLB. Суть работы та же что и с PureLB, но с MetalLB отпадает принципиальная необходимость использования lb‑autohealer. MetalLB буквально в течение нескольких миллисекунд бесшовно переключает адреса между хостами. Конечный пользователь этого даже не замечает.
RBD-remounter
Сервис призван повысить отказоустойчивость платформы при выходе какого-либо хоста из строя, своеобразный autohealing. В dBrain на Ceph мы поддерживаем хранение в любом виде: на S3, RBD и CephFS. RBD-remounter работает с RBD. Представим, что у нас есть рабочая нагрузка, которая эксклюзивно использует выделенный диск в Ceph и там хранит свои данные. Если хост вышел из строя, на нем остается примонтированная в Ceph RBD, как persistent volume, подмаунченный внутрь контейнера для хранения данных. Получается, что с точки зрения Ceph, этот диск остается закреплен за вышедшим из строя хостом. У диска эксклюзивный лок, поэтому если он где-то примонтирован, то его нельзя подмаунтить в другой контейнер. Эксклюзивный лок = эксклюзивный маунт. Зачастую при сбоях нода не возвращается в кластер, и диск зависает надолго. При этом новый контейнер (даже если ему помог переехать lost-node-cleaner, который затерминейтил старые поды на проблемной ноде) не запустится, т.к. не может подмаунтить свой volume с данными. Эту проблему и решает RBD-remounter, он инспектирует хосты и отламывает «зависшие» маунты. Если сервис уцелел на неисправном хосте, то он через какое-то время размонтирует на нем все сетевые диски. Продолжающие работать в целой части кластера RBD-remounter-ы отправляются в Ceph и там снимают эксклюзивный лок, оставшийся от недоступной ноды, чтобы новый запущенный контейнер смог подмаунтить этот volume себе и запуститься на другой ноде.
CoreDNS
Стандартная система внутреннего DNS для Kubernetes. Внутри нашего CoreDNS также живут зоны для внешнего доступа. Компонент обрабатывает не только внутреннюю доменную зону самого кластера и пространства имен Kubernetes, но и держит внешнюю зону для доступа к ресурсам кластера по хостнеймам. Например, в Grafana мы пишем не адрес, а имя кластера, и заходим в интерфейс. Такой функционал обеспечивает работа CoreDNS в связке с external-DNS.
Киллер-фича dBrain — Kube API External
Кроме стандартных API-серверов, реализованных в K8s статик-подами и живущих на мастер-нодах, мы реализовали kube API external в виде не привязанного к нодам деплоймента. Это дополнительные kube API-серверы, которые скейлятся в зависимости от пользовательской нагрузки. Таким образом, все внешние запросы обрабатываются отдельным deployment kube-api-server. Они работают внутри кластера, сами себя регистрируют в стандартном сервисе Kubernetes, обрабатывают внутрикластерные url на kube API и внутрикластерные запросы пользовательской нагрузки. External kube API-server, в отличии от стандартных API-serverов мастер-нод, не обрабатывают системные вещи: запросы Kubelet-ов, kube-controller менеджера, kube-scheduler, но отвечают на внутрикластерные запросы к kube-api.
Таким образом, это позволяет нам обрабатывать все внешние и внутренние запросы от приложений, которые запущены в Kubernetes с минимальными задержками и автоматически масштабироваться под требуемые нагрузки. Kube API external повышает отказоустойчивость и производительность API и кластера в целом.
Наша команда стремится создавать PaaS‑платформу, использование которой не составит труда с точки зрения пользовательского опыта. Самописные компоненты нужны для того, чтобы поведение Kubernetes и сопутствующих сервисов в платформе dBrain было приближено к стандартам, задаваемым такими облачными гигантами как Google или
AWS, а в чем-то даже превосходило их. Пользователи привыкли к ним и хотят видеть привычные функции при переходе на новую платформу. В dBrain все максимально автоматизировано: обслуживание Kubernetes-кластера сводится к нажатию нескольких кнопок на консоли управления. При этом платформа стремится к обеспечению максимальной производительности и масштабируемости, особенно на bare-metal серверах.