Сотни контейнеров. Миллионы внешних запросов. Миллиарды внутренних транзакций. Мониторинг и нотификации проблем. Простое масштабирование. 99% up time. Деплои и откатывание релизов.


Kubernetes как решение всех проблем! «Быть или не быть?» — вот в чем вопрос!

Disclaimer


Не смотря на публичность данной статьи, скорее всего, я пишу это в первую очередь для себя, как разговор с резиновой уточкой. После более чем двухгодового плавания с «хипстерскими» технологиями, я должен сделать шаг в сторону и адекватно оценить насколько это было обоснованно и будет адекватно для моего любого следующего проекта.

Тем не менее, я очень надеюсь, что эта публикация найдет своего читателя и поможет многим подготовлено подойти к выбору или отказу от Kubernetes.

Я попытаюсь описать весь опыт, полученный нами в `Lazada Express Logistics`, компании являющейся частью `Lazada Group`, которая в свою очередь — часть `Alibaba Group`. Мы разрабатываем и осуществляем поддержку систем автоматизирующих по-максимуму весь операционный цикл доставки и фулфилмента в 6 крупнейших странах Юго-восточной Азии.

Предпосылки к использованию


Однажды представитель компании, продающей облачные решения по всему миру, спросил у меня: «А что для Вас 'облако'?». Помешкав пару секунд (и подумав:«Хммм… наш диалог явно не о взвешенных в атмосфере конденсациях водяного пара...»), я ответил, что, мол, это как будто один сверх-надежный компьютер с неограниченными ресурсами и практически не имеющий накладных расходов на передачу потоков данных(cеть, диск, память, т.д.). Словно это мой лэптоп работающий для всего мира и способный держать такую нагрузку, а я в одиночку способен им управлять.


Собственно зачем нам это облачное чудо? Все в общем-то очень просто! Мы стремимся облегчить жизнь разработчиков, системных администраторов, devops-ов, тех-менеджеров. А такая вещь, как правильно приготовленное облако, многократно облегчает жизнь всем. Да и помимо всего прочего, мономорфные системы работающие на бизнес всегда дешевле и порождают меньше рисков.

Мы задались целью найти простую, удобную и надежную платформу приватного облака для всех наших приложений и для всех типов ролей в команде перечисленных выше. Провели небольшое исследование: Docker, Puppet, Swarm, Mesos, Openshift + Kubernetes, Kubernetes — Openshift… остановились на последнем — Kubernetes безо всяких аддонов.

Функционал описанный на самой первой странице отлично вписывался и годился для всего нашего предприятия. Подробное изучение документации, болтовня с коллегами и небольшой опыт быстрой пробы. Все это дало уверенность, что авторы продукта не врут, и мы сможем получить наше великолепное облако!

Засучили рукава. И понеслось…

Проблемы и их решения



3-х уровневая архитектура


Все идет с основ. Для того чтобы создать систему, способную хорошо жить в кластере Kubernetes, вам придется продумать архитектуру и процессы разработки, настроить кучу механизмов и средств доставки, научиться мириться с ограничениями/концепциями мира Docker и изолированных процессов.


Как итог: мы приходим к выводу, что идеология микро-сервисной и сервисно-ориентированной архитектуры как не кстати годится для наших задач. Если вы читали статью Мартина Фаулера(перевод) на эту тему, то более-менее должны представлять какой титанический труд должен быть проделан, прежде чем первый сервис оживет.

Мой чек-лист разделяет инфраструктуру на три слоя, а затем примерно описывает то, о чем на каждом из уровней нужно помнить при создании подобных систем. Три слоя о которых идет речь:

  • Hardware — сервера, физические сети
  • Cluster — в нашем случае Kubernetes и системные сервисы поддерживающие его (flannel, etcd, confd, docker)
  • Service — непосредственно процесс упакованный в Docker — микро/макро сервис в своем домене

Вообще идея 3-х слойной архитектуры и задач связанных с ней — это тема отдельной статьи. Но в свет она выйдет не раньше, чем этот самый чек-лист будет безукоризненно полон. Это может и не случиться никогда :)

Квалифицированные специалисты


Насколько тема приватных облаков актуальна и интересна все больше и больше среднему и крупному бизнесу, настолько же актуален вопрос о квалифицированных архитекторах, devops-ах, разработчиках, администраторах баз данных способных с этим работать.


Причина тому — новые технологии, которые, поступая на рынок, не успевают обрастать нужным объемом документации, обучающих статей и ответов на `Stack Overflow`. Однако, не смотря на это, такие технологии, как в нашем случае, Kubernetes — становятся очень популярными и создают дефицит кадров.

Решение простое — нужно взращивать специалистов внутри компании! Благо, в нашем случае, мы уже знали что такое Docker и как его готовить — остальное пришлось нагонять.

Continuous Delivery/Integration


Не смотря на всю прелесть технологии «умного облачного кластера», нам были необходимы средства общения и установки объектов внутрь Kubernetes. Пройдя дорогу от самописного bash скрипта и сотен ветвей логики, мы закончили вполне понятными и читаемыми рецептами для Ansible. Для полноценного превращения Docker файлов в живые объекты нам понадобилось:

  • Набор стандартных решений:

    • Team City — для автоматизированных деплоев
    • Ansible — для сборки шаблонов и доставки/установки объектов
    • Docker Registry — для хранения и доставки Docker образов
  • images-builder — скрипт для рекурсивного поиска Docker файлов в репозитории и отправки образов на их основе после сборки в централизованное registry
  • Ansible Kubernetes Module — модуль для установки объектов с различными стратегиями в зависимости от объекта (создать или обновить/создать или заменить/создать или пропустить)


По мимо всего прочего мы изучали вопрос о Kubernetes Helm. Но тем не менее, не смогли найти той самой killer-feature, которая могла бы заставить нас отказаться или заменить Ansible шаблонизацию на Helm чарты. Других полезных способностей этого решения мы не смогли найти.
Например, как делать проверку того, что один из объектов успешно установлен и можно продолжить выкатку других? Или как делать более тонкие настройки и установки контейнеров, которые уже работают, и нужно просто выполнить пару команд внутри их?

Эти и многие другие вопросы обязывают относиться к Helm как к простому шаблонизатору. Но зачем это?.. если Jinja2, входящая в состав Ansible, даст фору любому не профильному решению.

Сервисы хранящие состояние


Как полноценное решение для любого типа сервисов, включая statefull(имеющие состояние), Kubernetes поставляется с набором драйверов для работы с сетевыми блочными устройствами. В случае с AWS, единственный приемлемый вариант — EBS.

Как вы можете убедится, треккер k8s пестрит кучей багов связанных с EBS, и решаются они довольно медленно. На сегодня, мы не страдаем от каких-то серьезных проблем, помимо того, что, иногда, для создания объекта с персистентным хранилищем требуется до 20 минут. Интеграция EBS-k8s очень, очень, очень сомнительного качества.


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


Помимо всего прочего, Kubernetes, да и Docker мир, в принципе, обязывает, иногда, к множеству хитростей и тонкостей, которые очевидны на первый взгляд, но требуют дополнительного решения.
Небольшой пример.
Собирать логи внутри запущенного Docker контейнера нельзя. НО очень много систем и фреймворков не готовы к стримингу в `STDOUT`. Нужно заниматься `патчингом` и осознанной разработкой на системном уровне: писать в пайпы, заботиться о процессах и т.д. Немного времени и у нас есть Monolog Handler для `php`, который способен выдавать логи так, как их поймет Docker/k8s

API Gateway


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

Все довольно просто — нужна единая точка отказа доступа ко всем вашим сервисам.


Есть ряд задач которые мы решали в разрезе Kubernetes кластера:

  • Контроль доступа и лимитация запросов извне — как пример небольшой LUA скрипт проливает свет на проблему
  • Единая точка аутентификации/авторизации пользователей для любых сервисов
  • Отсутствие множества сервисов требующих доступ по HTTP из `мира` — резервирование портов на серверах для каждого желающего сервиса управляется тяжелее, чем роутинг в Nginx
  • Интеграция Kubernetes-AWS для работы с AWS Load Balancer
  • Единая точка мониторинга HTTP статусов — удобно даже для внутреннего общения сервисов
  • Динамическая маршрутизация запросов на сервисы или версии сервисов, A/B тесты (альтернативно проблема может решаться разными pod-ами за сервисом Kubernetes)

Искушенный пользователь Kubernetes поспешит спросить о Kubernetes Ingress Resource, который предназначен именно для решения подобных задач. Все верно! Но мы требовали немного больше `фич`, как вы могли заметить, для нашего API Gateway чем есть в Ingress. Тем более, это всего лишь обертка для Nginx, с которым мы и так умеем работать.

Текущее состояние


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


Что же из себя представляет платформа в текущем состоянии — немного сухих фактов:

  • Всего 2-3 человека для поддержки всей платформы
  • Один репозиторий хранящий всю информацию обо всей инфраструктуре
  • От 10-50 независимых автоматизированных релизов в день — CI/CD mode
  • Ansible как средство управления кластером
  • Считанные часы для создания идентичного `life` окружения — локально на minikube или на реальных серверах
  • AWS-based архитектура на базе EC2 + EBS, CentOS, Flannel
  • 500~1000 pod-ов в системе
  • Лист технологий завернутых в Docker/K8s: Go, PHP, JAVA/Spring FW/Apache Camel, Postgres/Pgpool/Repmgr, RabbitMQ, Redis, Elastic Search/Kibana, FluentD, Prometheus, etc
  • Инфраструктура вне кластера отсутствует, за исключением мониторинга на уровне `Hardware`
  • Централизованное хранилище логов на базе Elastic Search внутри Kubernetes кластера
  • Единая точка сбора метрик и алертинга проблем на базе Prometheus

Список отражает множество фактов, но опущенными остаются явные преимущества и приятные особенности Kubernetes как системы управления Docker процессами. Подробнее с этими вещами можно ознакомится на оффициальном сайте Kubernetes, в статьях на том же Хабре или Medium.

Длинный список наших пожеланий, которые находятся на стадии прототипов или пока еще покрывают небольшую часть системы, тоже очень большой:

  • Система профилирования и трэйсинга — например, zipkin
  • Anomaly detectionмашинно обучаемые алгоритмы для анализа проблем по сотням метрик, когда мы не можем или не хотим понимать что значит каждая метрика/набор метрик в отдельности, но хотим знать о проблеме связанной с этими метриками
  • Автоматическое планирование мощностей и масштабирование как количества pod-ов в сервисе так и серверов в кластере на основе определенных метрик
  • Интеллектуальная система управления бэкапами — для любых stateful сервисов, в первую очередь баз данных
  • Система мониторинга сетей и визуализации связей — внутри кластера, между сервисами и pod-ами, прежде всего (интересный пример)
  • Federation mode — распределенный и связнный режим работы нескольких кластеров

Тaк быть или не быть?


Опытный читатель, скорее всего, уже догадался, что статья врядли даст однозначный ответ на такой, казалось бы, простой короткий вопрос. Множество деталей и мелочей могут сделают вашу систему безумно крутой и производительной. Или другое множество багов и кривых имплементаций превратят вашу жизнь в ад.

Решать вам! Но мое мнение по поводу всего этого: «БЫТЬ!.. но очень аккуратно»
Поделиться с друзьями
-->

Комментарии (16)


  1. farcaller
    07.07.2017 11:58

    Вы ямлы пишете руками? не надоедает? jsonnet пробовали?


    1. nightvich
      07.07.2017 16:44
      +3

      А в чем сложность написания yaml?


      1. farcaller
        07.07.2017 21:21

        В k8s часто приходится писать одни и те же параметры и значения от ConfigSet к Deployment к Service и внутри них. Выше шанс опечатки, да и надоедает как-то все лейблы расставлять везде одинаково.


      1. farcaller
        08.07.2017 13:02

        Рефакторил тут правила calico, нарисовался пример.


        Надо сделать ServiceAccount с конкретными правами. В чистом k8s это три объекта:


        ---
        apiVersion: rbac.authorization.k8s.io/v1beta1
        kind: ClusterRoleBinding
        metadata:
          name: calico-cni-plugin
        roleRef:
          apiGroup: rbac.authorization.k8s.io
          kind: ClusterRole
          name: calico-cni-plugin
        subjects:
        - kind: ServiceAccount
          name: calico-cni-plugin
          namespace: kube-system
        ---
        kind: ClusterRole
        apiVersion: rbac.authorization.k8s.io/v1beta1
        metadata:
          name: calico-cni-plugin
          namespace: kube-system
        rules:
        - apiGroups: [""]
          resources:
          - pods
          - nodes
          verbs:
          - get
        ---
        apiVersion: v1
        kind: ServiceAccount
        metadata:
          name: calico-cni-plugin
          namespace: kube-system

        В jsonnet мешанину текста легко упросить до читаемого:


        {
          // account — одна строка
          calico_cni_account: kube.ServiceAccount('kube-system/calico-cni-plugin'),
        
          // role — одинарные объекты сами разворачиваются в массивы где надо
          calico_cni_role: kube.ClusterRole('kube-system/calico-cni-plugin') {
            rules_: kube.ClusterRoleRule('', ['pods', 'nodes'], 'get'),
          },
        
          // binding — сам резолвит релевантные поля из соседних объектов
          calico_cni_cluster_rb: kube.ClusterRoleBinding('calico-cni-plugin') {
            roleRef_: $.calico_cni_role,
            subjects_: $.calico_cni_account,
          },
        }

        Чем удобнее — все это в реальном времени рендерится в текстовом редакторе (vscode), и любая опечатка будет найдена компилятором при наборе текста, а не при kubectl apply.


  1. arykalin
    07.07.2017 19:01

    А что вы используете для конфигурации nginx? Мы сейчас пробуем читать сервисы из etcd кубернета и делать конфигурацию с помощью confd. Правда для этого пришлось переключиться обратно на etcd V2 API т.к. confd не умеет работать с etcd v3.


    1. ZmeeeD
      07.07.2017 19:04

      А как вы лимитируете что светить наружу а что нет? Не все же сервисы подключать… у нас простая конфигурация нутри самого nginx как часть проекта API gateway (не динамическая). Какие-то переменные приходят из ENV ну а внутри естественно собирается с confd


      1. arykalin
        08.07.2017 03:49

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


    1. farcaller
      07.07.2017 21:22

      nginx ingress controller пробовали?


      1. arykalin
        08.07.2017 03:50

        Да, но насколько я помню он не умеет динамическую конфигурацию с нескольких неймспейсов в бесплатной версии nginx.


        1. farcaller
          08.07.2017 12:21

          Нормально работает в бесплатной.


  1. galeev_roman
    07.07.2017 23:15

    Прошу прощения, если не увидел в тексте, а как вы осуществляете документацию текущего API для взаимодействия с подпроектами вашей группы проектов? То есть вы свои контейнеры обновляете, как хотите, это круто, но как остальные части проекта про это узнают?


  1. romangoward
    07.07.2017 23:59
    +2

    Самое интересное, как обычно, не рассказали: любой online shopping сегодня привязан к PCI DSS, а у сервисов уровня Alibaba — всегда свой процессинг. И тут у контейнеров в целом, да и у k8s в частности — всё, мягко говоря, не очень хорошо.


    1. farcaller
      09.07.2017 22:25
      +2

      вот тут прошлогодняя статья о том как WePay использует k8s. Что там не так с PCI DSS?


  1. reistlin87
    08.07.2017 07:57
    +2

    А в чем для вас преимущества Kubernetes перед Swarm?


    1. arturgspb
      09.07.2017 19:13

      Я бы даже сказал Текущего сварма, а не сварма времен начала кубера.


    1. ZmeeeD
      11.07.2017 06:23

      Отчасти исторически сложилось (старый Swarm, год назад, был не готов к продакшену, про текущий надо смотреть), отчасти то как k8s более обширно пошел по рынку.