Как устроен Kubernetes as a Service на платформе Linx Cloud
Работа с Kubernetes aaS в Linx Cloud — это:
- Удобная панель управления для выполнения операций над кластерами, включая их создание.
- Добавление или удаление нод (Cluster Autoscaler), иными словами возможность автоматического масштабирования узлов кластера.
- Возможность мониторинга сервисов и самого кластера на основе Prometheus Operator и Grafana.
- Хранение и управление образами благодаря сотрудничеству с Docker Registry.
- Развертывание федеративных кластеров Kubernetes на базе AWS и Linx Cloud автоматически.
- Возможность получения реальных IP пользователей внутри кластеров с помощью Cluster Policy: Local.
- Функции Start/Stop для кластера целиком, что поспособствует экономии для тестовых сред.
- Возможность строить геораспределенные кластеры и федерации, когда кластеры находятся в разных дата-центрах.
- Cозданиt Node Pools, пулов виртуальных машин разных размеров.
- Работа кластеров с VPN-соединением.
- Persistent Volumes интегрированы с системой хранения OpenStack.
- Создание и масштабирование кластеров Kubernetes с помощью UI или API Linx Cloud, управление сущностями через Kubernetes dashboard и kubectl.
- Простое и быстрое обновление (rolling update) для минорных мажорных версий.
- Свой Terraform-провайдер для Kubernetes.
Место Kubernetes в инфраструктуре облачной платформы
Нижний слой — типовые физические серверы (compute nodes), используемые для вычисления и хранение. Мы обеспечиваем файловыми и блочными хранилищами на базе Ceph и S3-совместимыми объектными хранилищами. Наши серверы распределены по дата-центрам, между которыми проложена сеть 40 Gbps.
Над уровнем серверов работает OpenStack, обеспечивающий виртуализацию для пользовательских окружений. А уже поверх виртуальных машин, сетей и балансировщиков работают PaaS-решения: Kubernetes, базы данных, DWH на базе ClickHouse, Hadoop, Spark и другие.
Аналогичную схему мы строим и в приватных инсталляциях Kubernetes как сервиса в дата-центрах наших заказчиков в формате частного облака.
Какие инструменты мы используем
- Операционная система. Сначала мы использовали CoreOS, которая работает на хостах, сейчас у нас Fedora Atomic (1.14-1.15) и CentOS (1.16).
- CRI. Мы два года используем Docker последней версии, но сейчас мигрируем, добавляем опциональную возможность виртуализации с повышенной изоляцией на базе Firecracker и Kata Container.
- Сеть — Calico. Сети Kubernetes зависят от облачной сети, которая обеспечивается SDN всего облака. В основе нашей SDN изначально был OpenStack Neutron. Но год назад мы начали разработку модуля Sprut — нашего собственного SDN-решения, которое поддерживает API Neutron, но работает по другим принципам. Подход Sprut решил наши проблемы масштабируемости, возникающие из-за десятков тысяч сетевых сущностей (портов) у нас в облаке, когда при падении сетевых нод в сети такого размера начинался процесс полной синхронизации (fullsync). Сейчас Sprut мы задействуем для тех клиентов, для которых в силу особенностей нагрузки на сеть использовать его целесообразнее, чем Calico, в перспективе мы его откроем для всех.
- Кластерный DNS на базе CoreDNS, со всеми его Service Discovery, метриками Prometheus и другими стандартными фичами.
- Ingress Controller. Сейчас это Nginx, но мы также добавляем Envoy, как дополнительный Ingress Controller. Наши тесты показывают, что Envoy часто быстрее. Ingress Controller интегрирован с облачным балансировщиком нагрузки на базе OpenStack Octavia и поддерживает Proxy Protocol.
- Мониторинг на базе Prometheus Operator. Раньше использовали просто Prometheus, но сейчас все хотят автоматизацию и сервис-мониторы, поэтому мы уже несколько месяцев предлагаем Prometheus Operator + Grafana, в рамках которой можно добавлять сервис-мониторы и выполнять мониторинг кластеров.
- Аддоны (опциональные расширения). В один клик можно установить Docker registry, интегрированный с нашим S3-хранилищем, ingress controller, различные системы мониторинга (Heapster, Prometheus).
Multi Master и сетевая топология
Kubernetes от Linx Cloud поддерживает деплой в формате Multi Master, при этом каждая пользовательская группа нод уже находится в конкретной зоне доступности. Геораспределение гарантируется созданием виртуальных машин по принципу Soft Anti Affinity, когда машины по возможности запускаются на разных гипервизорах.
Multi Master в облаке
В Multi Master etcd работает в кластерном режиме, так что если что-то случается с одним из мастеров, другие продолжают работать. Под каждый etcd выделен отдельный SSD-диск, что обеспечивает хороший latency и быструю работу API-сервера, т.к. в etcd находится служебная информация о всех ресурсах кластера Kubernetes.
Для доступа извне используется балансировщик нагрузки API сервера Kubernetes, который имеет внешний IP-адрес. При этом все ноды — и мастера, и миньоны — находятся в приватной сети (фактически в виртуальном частном облаке) и не имеют публичных адресов.
Доступ к кластеру Kubernetes из публичной сети
В общем случае способы доступа к сервисам внутри кластера перечислены здесь. Подробности нашей реализации:
NodePort открывает публичный порт на ноде. Однако есть ограничение: в целях безопасности по умолчанию публичные IP-адреса не установлены ни на мастера, ни на миньоны, кластеры создаются без белых IP-адресов. Пользователь может их сам установить.
Load Balancer. Наш Kubernetes интегрирован с облачной платформой Linx Cloud, так что платформа предоставляет Load Balancer как сервис и может сама создавать балансировщики. Для сравнения, если пользователь настраивает Kubernetes (например, в он премисе), нужно самостоятельно поднимать и настраивать софтверные балансеры. На платформе Linx Cloud балансировщики поднимаются сразу в отказоустойчивом режиме active-standby. Когда поднимается основной балансер (на HAProxy), у него всегда есть standby, спящий балансер. Между ними настроен VRRP. Если основной балансер отказывает, весь трафик мгновенно переключается на standby, при этом IP-адрес не меняется.
Отказоустойчивый Load Balancer как сервис на платформе Linx Cloud. Kubernetes создает nodeport на каждой ноде и балансировщик
В настройке балансировки для Kubernetes помогает наш Cloud Provider. Нужно создать манифест, в котором пользователь указывает тип манифеста “сервис” и тип сервиса “Load Balancer”. После деплоя этого манифеста Kubernetes (точнее, Cloud Provider, который работает в Kubernetes) обращается к OpenStack API, создает балансировщик и внешний IP-адрес, если это необходимо. Если внешний адрес не нужен, нужно поставить аннотацию, что требуется внутренний балансировщик, и можно пускать трафик на кластер, не открывая публичный IP-адрес на каждой ноде.
Сервисный манифест для создания балансировщика нагрузки с помощью Cloud Provider
Не всегда удобно создавать по балансеру на каждый сервис, 10 сервисов — есть 10 балансировщиков, 50 сервисов — 50 балансировщиков. Ими потом также приходится управлять, это тяжелые сущности. Эту проблему решает Ingress.
Ingress. Чтобы можно было не создавать много балансировщиков, мы добавили поддержку Ingress Controller. Ingress Controller интегрирован с балансировщиком OpenStack. То есть в декларации сервиса конкретного Ingress Controller указан тип Load Balancer. Для кластера создается один балансировщик, по которому Ingress Controller работает и дальше распределяет трафик по сервисам. Ingress Controller балансирует по DNS-именам.
Схема работы Ingress
Для некоторых клиентов важно, чтобы в подах было видно IP-адреса клиентов, получающих доступ в кластер. При балансировке теряются заголовки IP-пакетов: приложение не получает реальный IP-адрес клиента. Балансировщик OpenStack еще видит заголовок X-Forwarded-For, но Ingress Controller и под его уже не получают. Это не позволяет настроить доступ пользователей по White Lists, не работают сервисы типа GeoIP или anti-DDoS, которым нужно видеть реальные IP-адреса клиентов.
IP-адрес клиента не доходит до пода
И здесь у нас оказалось два решения :
Сделать режим proxy-протокола как в Amazon. Ради этой возможности мы перешли на балансировщик OpenStack Octavia, так как в стандартном балансировщике OpenStack нет такой опции. В итоге мы сделали новый балансировщик, который поддерживал как TCP-балансировку, так и HTTP(HTTP/2) с терминацией SSL.
При этом поддержку proxy-протокола нужно включать как на самом балансировщике (HAproxy), так и на Nginx Ingress Controller, который выступает таким приемником. Иначе схема пропускания трафика ломается. Также важно, что SSL-терминация, если у вас стандартный веб-трафик, должна проходить на Ingress:
Терминация SSL на балансировщике. Здесь на балансер приходит HTTPS , он расшифровывается, и в кластер идет HTTP. Если все это сделать и активировать в сервисе ExternalTrafficPolicy: Local, вы будете видеть заголовки IP-пакетов:
Storage и Kubernetes
Если разворачивать Kubernetes локально или в облаке просто на виртуальных машинах, то по умолчанию в нем нет нормальной работы с постоянными дисками. Можно использовать Host Path, Local volume (no-provisioner), либо прямо в кластере Kubernetes разворачивать экзотические программно-определяемые системы хранения типа Linstor или OpenEBS. Но что произойдет с данными или очередью данных, которая размещается в кластере, если умрет нода или под?
При самостоятельном подключении блочных устройств к кластеру есть проблемы: CSI драйверы не идеальны для многих типов стораджей, и автоматическое перемонтирование может не произойти. Мы сделали работу с блочными устройствами автоматизированной. Чтобы при отключении пода блочное устройство переподключалось к новому поду само.
Мы используем Ceph. Главное, что они работают через OpenStack, который предоставляет специальные модули, абстрагирующие Kubernetes (или любые виртуальные машины, работающие в облаке), на конкретных драйверах — OpenStack Cinder.
У нас несколько разных storage-классов, которые работают в Kubernetes: SSD Ceph, HDD Ceph, геораспределенные Ceph между нашими ЦОДами. Есть storage-класс, отвечающий за блочные диски: фактически это дисковые шкафы с SSD, они подключаются к хост-машинам по iSCSI.
Несколько Storage-классов в Linx Cloud
При необходимости мы используем NFS, когда клиенты не могут переписать приложения в микросервисную архитектуру. У нас есть аналог сервиса EFS от Amazon — файловое хранилище с NFS-протоколом, доступное как сервис. Оно подходит, если у вас legacy-приложение, которое вы переводите в Kubernetes.
Кроме того, у нас есть локальные SSD, но здесь сложно гарантировать их доступность и переезд данных, поскольку они доступны только с физических серверов, к которым подключены.
Наиболее отказоустойчивым решением является использование Kubernetes PersistenVolume’s на основе OpenStack Cinder. PersistenVolume подключаются через единый модуль OpenStack — OpenStack Cinder, к каждой ноде Kubernetes и обеспечивают возможность переезда постоянных томов в случае падения ноды на рабочую. А также когда повышается нагрузка чтения/записи и Kubernetes решает перевозить неважные поды на другие ноды — тогда он автоматически переводит монтирование этого диска к другим Kubernetes-нодам.
Так происходит автоматическое перемонтирование
Можно использовать storage class, написав декларации PersistentVolumeClaim. На примере, который изображен ниже, Cloud Provider выделит в заданной зоне доступности новый Persistent Volume, размером 30 ГБ с типом диска SSD, подключит его к ноде и примонтирует к подам. Также он будет следить, чтобы этот диск переезжал между нодами в случае переезда подов:
Автоматическое масштабирование
В Linx Cloud есть Cluster Autoscaler. Это не просто автоскейлинг подов внутри кластера, а автоскейлинг самого кластера по необходимости: новые ноды добавляются, когда нагрузка выросла, и удаляются, если нагрузка упала. Масштабирование происходит автоматически — до 100 узлов и обратно за несколько минут.
Автоскейлинг позволяет для каждой группы узлов задать свои правила автомасштабирования, например максимальное и минимальное число нод, которое может задать автоскейлер.
Cluster Autoscaler лучше настраивать совместно с Horizontal Pod Autoscaler. Различие использования двух вариантов Autoscaler:
- Cluster Autoscaler позволяет расширять сами выделенные для кластера ресурсы. По сути он может автоматически арендовать дополнительные ресурсы или сократить их использование через Cloud Provider.
- Horizontal Pod Autoscaler позволяет расширять ресурсы подов в рамках существующих выделенных ресурсов кластера, чтобы оптимально их использовать.
Функциональность
Интеграция со стандартными инструментами Kubernetes
- Хранение и обработка serverless-функций в контейнерах: OpenFaaS, OpenWhisk, Kubeless
- Инструменты Service Mesh: Istio, Consul, Linkerd
- Мониторинг, аналитика, логирование: Prometheus, Fluentd, Jaeger, OpenTracing
- CI/CD: Gitlab, CircleCI, Travis CI
- IaC (описание приложений): Terraform, Helm
Безопасность
- Kubernetes использует аутентификацию по сертификатам.
- Систему безопасности кластеров можно интегрировать с LDAP/Active Directory для аутентификации пользователей. При этом ролевую модель безопасности в Kubernetes можно настроить на проверку прав доступа на основе принадлежности пользователя к группам в LDAP-каталоге.
- Для сетевой безопасности можно применять Calico Network Policy.
- В наш Kubernetes aaS интегрирован Docker Registry, защищенный SSL.
Резервное копирование и миграция
- Мы поддерживаем интеграцию с Velero. Velero выполняет резервное копирование, которое позволяет бэкапить манифесты etcd и Persistent Volumes.
- Также с помощью Velero можно мигрировать кластеры on-premises и других провайдеров на наш Kubernetes.
Работа с большими данными
Kubernetes по сути можно использовать для любых микросервисных приложений, работающих с данными. Чем Kubernetes на платформе Linx Cloud интересен для data scientist’ов:
- Автомасштабирование позволяет выдерживать большие вычислительные нагрузки.
- Можно создавать событийные (event-triggered) обработчики данных.
- Приложения на Kubernetes легко интегрировать с другими нашими PaaS для Big Data, машинного обучения, в рамках одной сети.
- Если хочется поэкспериментировать, то для ускорения обучения к очереди событий или событийному обработчику на базе Kubernetes можно напрямую подключить GPU.