Как устроен Kubernetes as a Service на платформе Mail.ru Cloud Solutions

0_opjgcpbfdce-d9ius1httbltw.jpeg


Российские провайдеры давно умеют делать облачные платформы сами, а не только реселлить зарубежные. Это снижает стоимость сервисов, но их пользователям бывает интересно узнать, какая у них начинка и что обеспечивает их надёжность.

Я Дмитрий Лазаренко, директор по продуктам облачной платформы Mail.ru Cloud Solutions (MCS). Сегодня я расскажу, что под капотом у нашего Kubernetes aaS, как обеспечивается его надёжность и какие у него есть интересные функциональности, которыми любят пользоваться наши клиенты. Это автомасштабирование, интеграция с другими PaaS нашей платформы и многое другое.

Главные фичи Kubernetes на платформе MCS


Наш Kubernetes aaS включает:

  • Интерфейс управления для создания кластера в несколько кликов, масштабирования и настройки.
  • Автоматическое масштабирование узлов кластера в большую или меньшую сторону, то есть добавление или удаление нод (Cluster Autoscaler).
  • Встроенный мониторинг на основе Prometheus Operator и Grafana. Многие наши пользователи начинают с базовых инсталляций, где запускается приложение. Когда оно выходит в продуктив, это позволяет им мониторить сервисы и сам кластер.
  • Свой Terraform-провайдер для Kubernetes. Он полностью поддерживает API MCS.
  • Интеграция с Docker Registry для хранения и управления образами.
  • Автоматизированное развёртывание федеративных кластеров Kubernetes на базе AWS и Mail.ru Cloud Solutions (о чём мы писали тут).
  • Возможность сделать Start/Stop для кластера целиком — экономия для тестовых сред. Вы можете выключить кластер одним кликом в интерфейсе и платить только за диски в случае остановленных кластеров.
  • Поддержка создания Node Pools, пулов виртуальных машин разных размеров: можно запускать тяжелые задачи на больших машинах, веб-приложения на маленьких. Масштабировать группы можно независимо и размещать их в разных регионах либо зонах доступности (для большей надежности и доступности).
  • Persistent Volumes интегрированы с системой хранения OpenStack.
  • Поддержка приватных кластеров, доступных только через VPN-соединение.
  • Поддерживается Cluster Policy: Local, которая позволяет получать реальные IP пользователей внутри кластеров.
  • Создание и масштабирование кластеров Kubernetes с помощью UI или API MCS, управление сущностями через Kubernetes dashboard и kubectl.
  • Плавное обновление (rolling update) в один клик без простоя как для минорных, так и для мажорных версий. Обновления кластеров до 1.16.
  • На момент написания статьи мы поддерживаем Kubernetes вплоть до версии 1.17.

e1d-aiozgc6hdei0zcuwwyihhy0.png

Создание кластера Kubernetes в несколько кликов

Дальнейшее развитие сервиса:

  • CI/CD aaS, интегрированный с Kubernetes и другими сервисами платформы: дополнительные сервисы, которые обеспечивают CI/CD, на базе наших собственных доработок OpenStack.
  • Логирование aaS для приложений приложений, которые работают в нашем Kubernetes. Логирование будет реализовано на базе нескольких решений OpenStack.
  • Service mesh: у нас появятся плагины для Kubernetes, которые в рамках реализации service mesh будут выполнять шифрование, бэкапирование и другие функции.


Сертификация дистрибутива в Cloud Native Computing Foundation


Mail.ru Cloud Solutions входит в CNCF (Cloud Native Computing Foundation). Дистрибутив Kubernetes от MCS получил сертификат Certified Kubernetes — Hosted. Его проверили на надежность и соответствие стандартам, он отвечает всем функциональным требованиям сообщества и совместим со стандартным Kubernetes API. MCS — пока единственный в России облачный провайдер, получивший такую сертификацию.

Место Kubernetes в инфраструктуре облачной платформы


Самый нижний слой — типовые физические серверы (compute nodes). Сейчас их несколько тысяч, они используются под вычисления и хранение. Для хранения мы предоставляем файловые и блочные хранилища на базе Ceph и S3-совместимые объектные хранилища. Серверы распределены по дата-центрам, между которыми проложена сеть 40 Gbps.

Поверх уровня серверов работает OpenStack, который обеспечивает виртуализацию для пользовательских окружений. А уже поверх виртуальных машин, сетей и балансировщиков работают PaaS-решения: Kubernetes, базы данных, DWH на базе ClickHouse, Hadoop, Spark и другие.

Аналогичную схему мы строим и в приватных инсталляциях Kubernetes как сервиса в дата-центрах наших заказчиков в формате частного облака.

8ryfmj1zgkx7b6ei7pgpck9yjla.jpeg

Архитектура облачной платформы

Интеграция Kubernetes с облаком не односторонняя. Kubernetes не просто развертывается на виртуальных машинах, он полностью интегрируется с IaaS OpenStack.

На основе провайдера Cloud Provider OpenStack мы сделали Cloud Provider для MCS, который в рамках вашего проекта (тенанта) OpenStack соединяется с API MCS и создает, конфигурирует, удаляет диски, балансеры, внешние IP-адреса, подключает их к нодам Kubernetes, конфигурирует security-группы (фактически виртуальный firewall). Без Cloud Provider создание тех же Persistent Volumes — головная боль для всех, кто запускает Kubernetes on-premise, на железе либо просто в облаке.

mqjchbvc7rxqwrk9f0d8g6ejhkw.png

Интеграция Kubernetes с IaaS OpenStack

Какие инструменты мы используем


  1. Операционная система. Сначала мы использовали CoreOS, которая работает на хостах, сейчас у нас Fedora Atomic (1.14–1.15) и CentOS (1.16).
  2. Сеть — Calico. Сети Kubernetes зависят от облачной сети, которая обеспечивается SDN всего облака. В основе нашей SDN изначально был OpenStack Neutron. Но год назад мы начали разработку модуля Sprut — нашего собственного SDN-решения, которое поддерживает API Neutron, но работает по другим принципам. Подход Sprut решил наши проблемы масштабируемости, возникающие из-за десятков тысяч сетевых сущностей (портов) у нас в облаке, когда при падении сетевых нод в сети такого размера начинался процесс полной синхронизации (fullsync). Сейчас Sprut мы задействуем для тех клиентов, для которых в силу особенностей нагрузки на сеть использовать его целесообразнее, чем Calico, в перспективе мы его откроем для всех.
  3. Кластерный DNS на базе CoreDNS, со всеми его Service Discovery, метриками Prometheus и другими стандартными фичами.
  4. Ingress Controller. Сейчас это Nginx, но мы также планируем добавить Envoy, как дополнительный Ingress Controller. Наши тесты показывают, что Envoy часто быстрее. Ingress Controller интегрирован с облачным балансировщиком нагрузки на базе OpenStack Octavia и поддерживает Proxy Protocol.
  5. Мониторинг на базе Prometheus Operator. Раньше использовали просто Prometheus, но сейчас все хотят автоматизацию и сервис-мониторы, поэтому мы уже несколько месяцев предлагаем Prometheus Operator + Grafana, в рамках которой можно добавлять сервис-мониторы и выполнять мониторинг кластеров.
  6. Аддоны (опциональные расширения). В один клик можно установить Docker registry, интегрированный с нашим S3-хранилищем, ingress controller, различные системы мониторинга (Heapster, Prometheus).


Multi Master и сетевая топология


Kubernetes от Mail.ru поддерживает деплой в формате Multi Master, при этом каждая пользовательская группа нод уже находится в конкретной зоне доступности.

rlo_hbm1wbksh3cne1wsclyuqmy.png
Multi Master в облаке

В Multi Master etcd работает в кластерном режиме, так что если что-то случается с одним из мастеров, другие продолжают работать. Под каждый etcd выделен отдельный SSD-диск, что обеспечивает хороший latency и быструю работу API-сервера, т.к. в etcd находится служебная информация о всех ресурсах кластера Kubernetes.

Для доступа извне используется балансировщик нагрузки API сервера Kubernetes, который имеет внешний IP-адрес. При этом все ноды — и мастера, и миньоны — находятся в приватной сети (фактически в виртуальном частном облаке) и не имеют публичных адресов.

Доступ к кластеру Kubernetes из публичной сети: запуск трафика и балансировка нагрузки


В общем случае способы доступа к сервисам внутри кластера перечислены здесь. Подробности нашей реализации:

NodePort открывает публичный порт на ноде. Однако есть ограничение: в целях безопасности по умолчанию публичные IP-адреса не установлены ни на мастера, ни на миньоны, кластеры создаются без белых IP-адресов. Пользователь может их сам установить.

Load Balancer. Наш Kubernetes интегрирован с облачной платформой MCS, так что платформа предоставляет Load Balancer как сервис и может сама создавать балансировщики. Для сравнения, если пользователь настраивает Kubernetes (например, в он премисе), нужно самостоятельно поднимать и настраивать софтверные балансеры. На платформе MCS балансировщики поднимаются сразу в отказоустойчивом режиме active-standby. Когда поднимается основной балансер (на HAProxy), у него всегда есть standby, спящий балансер. Между ними настроен VRRP. Если основной балансер отказывает, весь трафик мгновенно переключается на standby, при этом IP-адрес не меняется.

tdcd9xclbozkx_cj8omfa1o1r0a.jpeg

Отказоустойчивый Load Balancer как сервис на платформе MCS. Kubernetes создаёт nodeport на каждой ноде и балансировщик

В настройке балансировки для Kubernetes помогает наш Cloud Provider. Нужно создать манифест, в котором пользователь указывает тип манифеста «сервис» и тип сервиса «Load Balancer». После деплоя этого манифеста Kubernetes (точнее, Cloud Provider, который работает в Kubernetes) обращается к OpenStack API, создаёт балансировщик и внешний IP-адрес, если это необходимо. Если внешний адрес не нужен, нужно поставить аннотацию, что требуется внутренний балансировщик, и можно пускать трафик на кластер, не открывая публичный IP-адрес на каждой ноде.

apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
  k8s-app: nginx-backend
 annotations:
  service.beta.kubernetes.io/openstack-internal-load-balancer:"true"
spec:
 type: LoadBalancer
 externalTrafficPolicy: Cluster
 selector:
  k8-app: nginx-backend
 ports:
 -port: 80
  name: http
  targetPort: http
 -port: 443
  name: https
  targetPort: httpn


Сервисный манифест для создания балансировщика нагрузки с помощью Cloud Provider

Не всегда удобно создавать по балансеру на каждый сервис, 10 сервисов — есть 10 балансировщиков, 50 сервисов — 50 балансировщиков. Ими потом также приходится управлять, это тяжелые сущности. Эту проблему решает Ingress.

Ingress. Чтобы можно было не создавать много балансировщиков, мы добавили поддержку Ingress Controller. Ingress Controller интегрирован с балансировщиком OpenStack. То есть в декларации сервиса конкретного Ingress Controller указан тип Load Balancer. Для кластера создается один балансировщик, по которому Ingress Controller работает и дальше распределяет трафик по сервисам. Ingress Controller балансирует по DNS-именам.

lonymhj_qxb-s7mkb81gk94wvxs.png

Схема работы Ingress

Для некоторых клиентов было важно, чтобы в подах было видно IP-адреса клиентов, получающих доступ в кластер. При балансировке теряются заголовки IP-пакетов: приложение не получает реальный IP-адрес клиента. Балансировщик OpenStack ещё видит заголовок X-Forwarded-For, но Ingress Controller и под его уже не получают. Это не позволяет настроить доступ пользователей по White Lists, не работают сервисы типа GeoIP или anti-DDoS, которым нужно видеть реальные IP-адреса клиентов.

g7y4o84bxvolnzb0m2kvp6lumvc.jpeg

IP-адрес клиента не доходит до пода

И здесь у нас оказалось два решения:

Сделать режим proxy-протокола как в Amazon. Ради этой возможности мы перешли на балансировщик OpenStack Octavia, так как в стандартном балансировщике OpenStack нет такой опции. В итоге мы сделали новый балансировщик, который поддерживал как TCP-балансировку, так и HTTP с терминацией SSL.

При этом поддержку proxy-протокола нужно включать как на самом балансировщике (HAproxy), так и на Nginx Ingress Controller, который выступает таким приемником. Иначе схема пропускания трафика ломается. Также важно, что SSL-терминация, если у вас стандартный веб-трафик, должна проходить на Ingress:

-yjgpduf8ay24lvfx432g39slns.jpeg

Терминация SSL на балансировщике. Здесь на балансер приходит HTTPS, он расшифровывается, и в кластер идет HTTP. Если всё это сделать и активировать в сервисе ExternalTrafficPolicy: Local, вы будете видеть заголовки IP-пакетов:

lbjfq1mxuvth2uuoss-svdyad-c.jpeg

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.

hjvdivoggiqawtns5xysx5hrafi.png

Несколько Storage-классов в MCS

При необходимости мы используем NFS, когда клиенты не могут переписать приложения в микросервисную архитектуру. У нас есть аналог сервиса EFS от Amazon — файловое хранилище с NFS-протоколом, доступное как сервис. Оно подходит, если у вас legacy-приложение, которое вы переводите в Kubernetes.

Кроме того, у нас есть локальные SSD, но здесь сложно гарантировать их доступность и переезд данных, поскольку они доступны только с физических серверов, к которым подключены.

Всё это подключается через единый модуль OpenStack — OpenStack Cinder, к каждой ноде Kubernetes и обеспечивает возможность переезда стораджа в случае падения ноды. А также когда повышается нагрузка чтения/записи и Kubernetes решает перевозить неважные поды на другие ноды — тогда он автоматически переводит монтирование этого диска к другим Kubernetes-нодам.

gu179z_reprtxvcbrhss-gahchk.png

Так происходит автоматическое перемонтирование

Можно использовать storage class, написав декларации PersistentVolumeClaim. На примере, который изображён ниже, Cloud Provider выделит в заданной зоне доступности новый Persistent Volume, размером 30 ГБ с типом диска SSD, подключит его к ноде и примонтирует к подам. Также он будет следить, чтобы этот диск переезжал между нодами в случае переезда подов:

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
 name: nginx-pvc-ssd
spec:
 accessModes:
 -ReadWriteOnce
 storageClassName: dp1-ssd
resources:
 requests:
  storage: 30Gi

Автоматическое масштабирование


В MCS есть Cluster Autoscaler. Это не просто автоскейлинг подов внутри кластера, а автоскейлинг самого кластера по необходимости: новые ноды добавляются, когда нагрузка выросла, и удаляются, если нагрузка упала. Масштабирование происходит автоматически — до 100 узлов и обратно за несколько минут.

Автоскейлинг позволяет для каждой группы узлов задать свои правила автомасштабирования, например максимальное и минимальное число нод, которое может задать автоскейлер.

Cluster Autoscaler лучше настраивать совместно с Horizontal Pod Autoscaler. Различие использования двух вариантов Autoscaler:

  • Cluster Autoscaler позволяет расширять сами выделенные для кластера ресурсы. По сути он может автоматически арендовать дополнительные ресурсы или сократить их использование через Cloud Provider.
  • Horizontal Pod Autoscaler позволяет расширять ресурсы подов в рамках существующих выделенных ресурсов кластера, чтобы оптимально их использовать.

bxlhzu2ue2noefihjcrkua_elb8.png

Настройка автоскейлинга

Функциональности


Совместимость со стандартными инструментами Kubernetes


Так как наш Kubernetes aaS полностью совместим со стандартным Kubernetes API, вы можете свободно пользоваться всеми возможностями экосистемы Kubernetes.

  • Хранение и обработка serverless-функций в контейнерах: OpenFaaS, OpenWhisk, Kubeless.
  • Инструменты Service Mesh: Istio, Consul, Linkerd.
  • Мониторинг, аналитика, логирование: Prometheus, Fluentd, Jaeger, OpenTracing.
  • CI/CD: Gitlab, CircleCI, Travis CI.
  • IaC (описание приложений): Terraform, Helm.


И многие другие инструменты.

Про Terraform отдельно стоит сказать, что стандартный провайдер OpenStack не был полностью совместим с API платформы MCS, так что мы сделали собственный Terraform-провайдер, который полностью совместим с последней версией API MCS. Поддержка API включает:

  • листинг ресурсов MCS (cluster, cluster template, node group)
  • поддержку managed node groups
  • поддержку действий через API: создание/удаление, горизонтальное и вертикальное масштабирование, включение/выключение кластера, обновление версии.

Безопасность


  • Kubernetes использует аутентификацию по сертификатам.
  • Систему безопасности кластеров можно интегрировать с LDAP/Active Directory для аутентификации пользователей. При этом ролевую модель безопасности в Kubernetes можно настроить на проверку прав доступа на основе принадлежности пользователя к группам в LDAP-каталоге.
  • Для сетевой безопасности можно применять Calico Network Policy.
  • В наш Kubernetes aaS интегрирован Docker Registry, защищённый SSL.
  • Планируем реализовать SSO (single sign-on) в интеграции с нашим IAM (identity and access management) на уровне OpenStack.


Резервное копирование и миграция


  • Мы поддерживаем интеграцию с Velero. Velero выполняет резервное копирование, которое позволяет бэкапить манифесты etcd и Persistent Volumes, вот гайд по тому, как это сделать.
  • Также с помощью Velero можно мигрировать кластеры on-premises и других провайдеров на наш Kubernetes.
  • Или запросите миграцию на наш Kubernetes «под ключ». Поможем.


Работа с большими данными


Kubernetes по сути можно использовать для любых микросервисных приложений, работающих с данными. Чем Kubernetes на платформе MCS интересен для data scientist«ов:

  • Автомасштабирование позволяет выдерживать большие вычислительные нагрузки.
  • Можно создавать событийные (event-triggered) обработчики данных.
  • Приложения на Kubernetes легко интегрировать с другими нашими PaaS для Big Data, машинного обучения, в рамках одной сети.
  • Если хочется поэкспериментировать, то для ускорения обучения к очереди событий или событийному обработчику на базе Kubernetes можно напрямую подключить GPU.


Ещё о нашем Kubernetes aaS


  1. Попробовать бесплатно наш Kubernetes aaS можно тут.
  2. В этих двух Telegram-каналах вас ждут новости нашего Kubernetes aaS и анонсы мероприятий @Kubernetes meetup.

© Habrahabr.ru