Как мы меняли инфраструктуру облачного решения: от одной виртуальной машины к кластеру Kubernetes

Вот уже 7 лет мы развиваем Okdesk — облачную help desk систему для малого и среднего бизнеса.
В свое время мы начали с одной виртуальной машины у провайдера.
Постепенно сервис взрослел, менялись приоритеты, задачи и проблемы, с которыми мы сталкивались. Сегодня Okdesk живет уже на третьей версии инфраструктуры.

В этой заметке мы расскажем о том, как и почему эволюционировала архитектура Okdesk. А во второй части поста — почему мы перешли на Kubernetes, каких результатов это позволило добиться и что планируем делать дальше.

98c425b631a76db9be5f1bebbaf15c4a.png

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

В статье нет rocket science, так как в компании и бизнесе мы придерживаемся мнения, что каждый должен заниматься своим делом.

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

Версия 1. Виртуальная машина

Запуская сервис, мы старались как можно быстрее выйти на рынок, поэтому построили инфраструктуру, исходя из принципа наименьшей достаточности. Это была виртуалка в дата-центре на Западе, на которой крутилось само приложение и СУБД (дело было еще до выхода законодательства, запрещающего хранить пользовательские данные за границей). Для стабильной работы MVP этого было более чем достаточно.

7f9ddfb9b878f3aef2d44b6250326a32.jpg

Когда к Okdesk подключились на платной основе первые 15 клиентов, мы разнесли приложение и СУБД по разным виртуальным машинам. Но идеологически инфраструктура осталась той же. Мониторили мы ее через ping-admin (инструмент отправляет http-запросы и предупреждает, если ответ отличается от ожидаемого) и на всякий случай регулярно бэкапились в облачный сервис другого поставщика.

Первой версии не хватало надежности. Несмотря на это за время ее работы доступность сервиса не падала ниже 99.97% — это 2 часа простоев в год, считая плановые остановки. Но это не значит, что гипотетически сервис не мог бы упасть на 2 часа и более. Просто нам удалось этого избежать.

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

Версия 2. Дублирование серверов

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

  • ограничили максимальное время неработоспособности сервиса до 15 минут (даже если дата-центр взорвался, не говоря уже о банальном выходе из строя одного сервера);

  • допустили потерю клиентских данных не более чем за несколько секунд, даже если падает СУБД на продакшне.

Для этого мы дублировали приложение и СУБД на резервный сервер, который вынесли в другой дата-центр (физически расположенный в другом месте) и настроили репликацию данных.

cb69b776eb51be9dac01f298f2f773d9.png

Переключение с основного на резервный сервер в случае аварии должно было выполняться вручную через route 53 от Amazon и занимать не более 5 минут.

Для мониторинга инфраструктуры к уже использовавшемуся ping-admin мы добавили Monit и Scoutapp. Первый собирает базовые метрики сервера, а второй помогает профилировать производительность. Позже Monit расширили клиент-серверным инструментом, который умеет мониторить бизнес-параметры и рисовать картинки.

Вторую версию инфраструктуры мы строили уже в соответствии с законом о защите персональных данных, поэтому размещали сервера в России — на площадке Servers.ru. Подробнее о том переходе можно прочитать в нашей старой статье.

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

Вторая версия инфраструктуры с небольшими доработками просуществовала чуть более 4 лет. Фактически, это были разрозненные сервера, управлять которыми было довольно сложно из-за обилия ручных процедур. Сервис продолжал развиваться и у нас появилась потребность в бесшовном деплое, раздельной обработке разных типов запросов (например, чтобы API запросы не влияли на работу веб-версии), запуске сторонних приложений. Так мы пришли к необходимости проектировать третью версию инфраструктуры.

Версия 3. Kubernetes

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

Базовые «клиентские» метрики для проектирования третьей версии

С точки зрения клиентского сервиса мы хотели снизить последствия отключения одного сервера приложений. При падении сервера до переключения на резервную инфраструктуру запросы от клиентов не обрабатывались и нас это не устраивало.

Чтобы полного прекращения обслуживания не происходило, логично раздробить сервис на много мелких серверов или нод. В этом случае падение одного такого сервера (или ноды) обернется не прекращением обработки запросов, а временной потерей мощности. Аналогичную «конструкцию» логично собрать и в резервном дата-центре.

Дробление серверов приложений несет за собой проблемы сквозного мониторинга и сбора логов, балансировки нагрузки, а также синхронизации данных и конфигураций между серверами (и отдельно экземплярами приложений на этих серверах). С конфигурированием у нас и так во второй версии были определенные сложности — очень многие операции, включая парковку доменов, выполнялись вручную, что было чревато ошибками. Все это хотелось автоматизировать, чтобы исключить человеческий фактор.

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

Простота развития

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

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

Также мы хотели облегчить запуск других приложений в настроенном окружении, например, бота в Telegram. Это приложение взаимодействует с API Okdesk и требует определенных ресурсов для своей работы. Необходимо было, чтобы инфраструктура поддерживала интеграцию этого и других приложений каким-то типовым образом, чтобы нам не приходилось каждый раз заново все настраивать.

Легкое управление

7c218e55a299484c59a7a3bb44e36573.png

Помимо глобальных пожеланий, мы хотели чуть больше возможностей для управления инфраструктурой. В частности, мы хотели влиять на балансировку трафика или изолировать запросы разного типа друг относительно друга, заранее выделяя на них определенный объем ресурсов. Стандартный кейс, где это нужно — мобильное приложение для выездных специалистов. Его используют не только в городах с хорошим покрытием связью, но и там, где мобильный интернет не быстрый. Запросы на загрузку «тяжелых» фотоотчетов о выполненных работах или на полнотекстовый поиск могут «подвешивать» сервис, поэтому их необходимо изолировать от «быстрых» загрузок карточек заявок и т.п.

Какие были варианты кроме Kubernetes?

В теории мы могли развернуть нашу инфраструктуру на нескольких серверах, используя балансировщики нагрузки и настройку параметров серверов и приложений вручную или через Ansible / Chef.
Но такой путь не решает никаких проблем, кроме непосредственно дробления серверов. Удовлетворение остальных требований либо невозможно, либо требует внедрения сторонних инструментов, которые усложняют систему и плодят зоопарк, требующий взаимной интеграции.

На тот момент наш подрядчик, Флант, уже несколько лет специализировался на Kubernetes. Это опенсорсная платформа для управления сервисами в контейнерах с огромной экосистемой.
Флант набрал в этой области большую экспертизу и даже успел разработать свои надстройки, облегчающие управление (они много писали про свои разработки на Хабре: 1, 2, 3). Именно они предложили нам развернуть все на Kubernetes. Честно говоря, мы и сами присматривались к более современным технологиям. Так что выбор был сделан.

Миграцию со второй на третью версию обеспечивал Флант. Он же предложил комплект инструментов — собственный Deckhouse для упрощения контроля, Graylog для сбора логов со всех нод, стандартные в Kubernetes Grafana и Prometheus для мониторинга.

Итоги переезда на Kubernetes

03624a32f73ffd42349371fe650fa834.png

В целом переезд оказался несколько сложнее и дольше, чем мы ожидали. Но мы добились того, чего хотели — получили отказоустойчивый сервис, развернутый на нескольких физических серверах, который автоматически перезапускается в случае нештатных ситуаций. Достигли доступности 99.99%.

Мы можем легко вводить в эксплуатацию новые сервера — после установки минимального ПО Kubernetes делает все сам. Таким образом суммарное время запуска сервера сократилось в 10 раз.

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

Не стоит думать, что Kubernetes дает какой-то выигрыш по железу. Дополнительный слой абстракции требует мощностей, которые в общем случае зависят от сложности реализуемой логики. А у нас она сложна — только припаркованных доменов больше 160 штук, и каждый из них требует собственного конфига. Общий объем конфигурации — несколько тысяч строк. 

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

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

  • Найти альтернативный дата-центр для размещения резерва. Сейчас они физически находятся в разных дата-центрах, но обслуживаются одним поставщиком услуг, что означает существование общих точек отказа. Мы хотим избавиться от этого риска.

  • Оптимизировать потребление ресурсов Kubernetes. В современных реалиях наращивать мощности будет сложно, поэтому после завершения активной фазы развития инфраструктуры мы попробуем немного «отжать» сервис и Kubernetes.

  • Глубже погрузить сотрудников в понимание третьей версии архитектуры — какие есть базовые компоненты, как они друг с другом взаимодействуют, как хранятся конфигурационные файлы и какие вещи в коде сервиса поддерживают Kubernetes. Все это необходимо документировать и озвучивать внутри компании.

В завершении хотелось бы отметить, что если ваша компания ищет функциональную систему автоматизации процессов сервиса, техподдержки и выездного обслуживания с надежной и отказоустойчивой архитектурой, то вы знаете что найти ее можно у нас, в Okdesk. Присоединяйтесь к 800+ компаний, которые каждый день сфокусированы на основном бизнесе, а не поиске или разработке собственного ПО для решения обозначенных выше задач.

© Habrahabr.ru